Add a polymorphic `subject` field that records the subject of the mod
action. The subject is the post, user, comment, artist, etc the mod
action is for.
* The subject for the user ban and unban actions is the user, not the ban itself.
* The subject for the user feedback update and deletion actions is the user,
not the feedback itself.
* The subject for the post undeletion action is the post, not the approval itself.
* The subject for the move favorites action is the source post where the
favorites were moved from, not the destination post where the favorites
were moved to.
* The subject for the post permanent delete action is nil, because the
post itself is hard deleted.
* When a post is permanently deleted, all mod actions related to the
post are deleted as well.
Fix mod actions to use the same message format everywhere.
Before mod actions were formatted in various inconsistent ways:
* "deleted post #1234"
* "comment #1234 updated by <user>"
* "<user> updated forum #1234"
* "<user> level changed Member -> Builder"
Now all mod actions consistently use this format:
* "deleted post #1234"
* "updated comment #1234"
* "updated forum #1234"
* "promoted <user> from Member to Builder"
This way mod actions are formatted consistently with other actions on
the /user_actions page, where everything is written as "<user> did X".
Also add a fix script to fix existing mod actions.
Add a /user_actions page. This page shows you a global timeline of
(almost) all activity on the site, including uploads, comments, votes,
edits, forum posts, and so on.
The main things it doesn't include are post edits, pool edits, and
favorites (posts and pools live in a separate database, and favorites
don't have the timestamps we need for ordering).
This page is useful for moderation purposes because it lets you see a
history of almost all of a user's activity on a single page.
Currently this page is mod-only. In the future it will be open to all
users, so you can view the history of your own site activity, or the
activity of others.
Allow admins to remove votes on posts. This is for fixing vote abuse.
Votes can be removed by going to the vote list on the /post_votes page,
or by clicking on a post's score, then using the "Remove" option in the
"..." dropdown menu next to the vote.
Votes are soft-deleted - they're marked as deleted in the database, but
not fully deleted. Removed votes are only visible to admins, not to
regular users. When a vote is removed by an admin, it leaves a mod
action.
Technically it's possible to undelete votes, but there's no UI for it.
Make upvotes public the same way favorites are public:
* Rename the "Private favorites" account setting to "Private favorites and upvotes".
* Make upvotes public, unless the user has private upvotes enabled. Note
that private upvotes are still visible to admins. Downvotes are still
hidden to everyone except for admins.
* Make https://danbooru.donmai.us/post_votes visible to all users. This
page shows all public upvotes. Private upvotes and downvotes are only
visible on the page to admins and to the voter themselves.
* Make votes searchable with the `upvote:username` and `downvote:username`
metatags. These already existed before, but they were only usable by
admins and by people searching for their own votes.
Upvotes are public to discourage users from upvoting with multiple
accounts. Upvote abuse is obvious to everyone when upvotes are public.
The other reason is to make upvotes consistent with favorites, which are
already public.
Like 9efb374ae, allow users to toggle between upvoting and downvoting a
post without raising an error or having to manually remove the vote
first. If you upvote a post, then downvote it, the upvote is
automatically removed and replaced by the downvote.
Other changes:
* Tagging a post with `upvote:self` or `downvote:self` is now silently
ignored when the user doesn't have permission to vote, instead of
raising an error.
* Undoing a vote that doesn't exist now does nothing instead of
returning an error. This can happen if you open the same post in two
tabs, undo the vote in tab 1, then try to undo the vote again in tab 2.
Changes to the /post_votes API:
* `POST /post_votes` and `DELETE /post_votes` now return a post vote
instead of a post.
* The `score` param in `POST /post_votes` is now 1 or -1, not `up` or
`down`.
Change post votes to work the same way as comment votes:
* Make the upvote arrow blue if you've upvoted the post, or grey if you
haven't. Likewise for the downvote arrow.
* Make it so you can click the upvote or downvote arrows to undo the vote.
* Don't show any notices when you vote on a post.
Also fix it so that votes work the same way on the posts page, the
comments page, and in the modqueue. Before it wasn't possible to undo
votes on the comments page or in the modqueue.
Refactor how model visibility works in index actions:
* Call `visible` in the controller instead of in model `search`
methods. This decouples model visibility from model searching.
* Explicitly pass CurrentUser when calling `visible`. This reduces
hidden dependencies on the current user inside models.
* Standardize on calling the method `visible`. In some places it was
called `permitted` instead.
* Add a `visible` base method to ApplicationModel.
- The only string works much the same as before with its comma separation
-- Nested includes are indicated with square brackets "[ ]"
-- The nested include is the value immediately preceding the square brackets
-- The only string is the comma separated string inside those brackets
- Default includes are split between format types when necessary
-- This prevents unnecessary includes from being added on page load
- Available includes are those items which are allowed to be accessible to the user
-- Some aren't because they are sensitive, such as the creator of a flag
-- Some aren't because the number of associated items is too large
- The amount of times the same model can be included to prevent recursions
-- One exception is the root model may include the same model once
--- e.g. the user model can include the inviter which is also the user model
-- Another exception is if the include is a has_many association
--- e.g. artist urls can include the artist, and then artist urls again
In rails 5, belongs_to associations automatically validate that the
associated item is present, meaning that we don't need to validate these
things manually any more.
Fail loudly if we forget to whitelist a param instead of silently
ignoring it.
misc models: convert to strong params.
artist commentaries: convert to strong params.
* Disallow changing or setting post_id to a nonexistent post.
artists: convert to strong params.
* Disallow setting `is_banned` in create/update actions. Changing it
this way instead of with the ban/unban actions would leave the artist in
a partially banned state.
bans: convert to strong params.
* Disallow changing the user_id after the ban has been created.
comments: convert to strong params.
favorite groups: convert to strong params.
news updates: convert to strong params.
post appeals: convert to strong params.
post flags: convert to strong params.
* Disallow users from setting the `is_deleted` / `is_resolved` flags.
ip bans: convert to strong params.
user feedbacks: convert to strong params.
* Disallow users from setting `disable_dmail_notification` when creating feedbacks.
* Disallow changing the user_id after the feedback has been created.
notes: convert to strong params.
wiki pages: convert to strong params.
* Also fix non-Builders being able to delete wiki pages.
saved searches: convert to strong params.
pools: convert to strong params.
* Disallow setting `post_count` or `is_deleted` in create/update actions.
janitor trials: convert to strong params.
post disapprovals: convert to strong params.
* Factor out quick-mod bar to shared partial.
* Fix quick-mod bar to use `Post#is_approvable?` to determine visibility
of Approve button.
dmail filters: convert to strong params.
password resets: convert to strong params.
user name change requests: convert to strong params.
posts: convert to strong params.
users: convert to strong params.
* Disallow setting password_hash, last_logged_in_at, last_forum_read_at,
has_mail, and dmail_filter_attributes[user_id].
* Remove initialize_default_image_size (dead code).
uploads: convert to strong params.
* Remove `initialize_status` because status already defaults to pending
in the database.
tag aliases/implications: convert to strong params.
tags: convert to strong params.
forum posts: convert to strong params.
* Disallow changing the topic_id after creating the post.
* Disallow setting is_deleted (destroy/undelete actions should be used instead).
* Remove is_sticky / is_locked (nonexistent attributes).
forum topics: convert to strong params.
* merges https://github.com/evazion/danbooru/tree/wip-rails-5.1
* lock pg gem to 0.21 (1.0.0 is incompatible with rails 5.1.4)
* switch to factorybot and change all references
Co-authored-by: r888888888 <r888888888@gmail.com>
Co-authored-by: evazion <noizave@gmail.com>
add diffs
Bug: when moving favorites, the parent is given an upvote for each gold+
favoriter, but the magnitude of these upvotes was based on the
CurrentUser, rather than the upvoter. This meant that upvotes for
supervoter favorites weren't given correctly.
To fix this, `magnitude` is changed to use the voting `user` instead of
CurrentUser.
New problem: when setting the score, `score=` calls `magnitude`, but
`user` isn't initialized yet. So we also refactor so that
1. `initialize_attributes` initializes `user` before setting `score`
2. the vote direction is given by `vote`, so it's separate from `score`
3. updating the score on the post happens in a callback instead of
directly in `score=`.
Bug: when an approver moves the favorites of a post, each favorite is
removed from the child post and added to the parent post. For gold+
users, this triggers an upvote, but these upvotes were performed by the
approver rather than the favoriter.