Commit Graph

3485 Commits

Author SHA1 Message Date
evazion
c2adf279ee ugoira: remove the PixivUgoiraFrameData model.
Remove the last remaining uses of the PixivUgoiraFrameData model. As of
32bfb8407, Ugoira frame data is now stored in the MediaMetadata model,
under the `Ugoira:FrameDelays` EXIF field.

The pixiv_ugoira_frame_data table still exists, but it can be removed
after this commit is deployed.

Fixes #5264: Error when replacing with ugoira.
2022-10-10 18:21:30 -05:00
evazion
1d5db37f56 posts: automatically tag AI-generated on NovelAI posts.
Automatically add the AI-generated tag to posts that have the
`PNG:Software=NovelAI` EXIF attribute.

This is not foolproof because this metadata may get removed if an
AI-generated post is resaved or uploaded to a site that strips EXIF
metadata. It also only works for NovelAI. Currently it detects 29 out of
177 AI-generated uploads on Danbooru.
2022-10-10 04:04:35 -05:00
evazion
01d10a54f8 ugoira: store frame delays in MediaMetadata model.
Store Ugoira frame delays in the MediaMetadata model as a fake EXIF
field instead of in the PixivUgoiraFrameData model. This way we can get
rid of the PixivUgoiraFrameData model completely. This is a step towards
fixing #5264.
2022-10-09 22:25:20 -05:00
evazion
16f3250067 ugoira: fix player to only use list of frame delays.
The frame data for Ugoira files is stored like this:

    [{"file"=>"000000.jpg", "delay"=>65},
    {"file"=>"000001.jpg", "delay"=>65},
    {"file"=>"000002.jpg", "delay"=>65},
    {"file"=>"000003.jpg", "delay"=>65},
    {"file"=>"000004.jpg", "delay"=>65},
    {"file"=>"000005.jpg", "delay"=>65},
    {"file"=>"000006.jpg", "delay"=>65},
    {"file"=>"000007.jpg", "delay"=>65},
    {"file"=>"000008.jpg", "delay"=>65},
    {"file"=>"000009.jpg", "delay"=>65},
    {"file"=>"000010.jpg", "delay"=>65}]

This is stored in the pixiv_ugoira_frame_data table in YAML format. This
is a problem because a) we only need the frame delays to play the Ugoira,
not the filenames, and b) storing the data in YAML format is a security
issue that's blocking the upgrade to Rails 7.0.4 (see [1]).

This commit changes the Ugoira Javascript player so that it only uses
the list of frame delays, not the filenames, to play the Ugoira. This
paves the way for storing the frame delays as a simple integer array
instead as a serialized YAML object.

This assumes that the images in a Ugoira zip file are stored in the same
order they should be played back in. This was confirmed by checking every
zip file and verifying that files are actually stored in filename order.

[1]: https://discuss.rubyonrails.org/t/cve-2022-32224-possible-rce-escalation-bug-with-serialized-columns-in-active-record/81017
2022-10-09 18:47:10 -05:00
evazion
56395f8c71 posts: fixup bug in 24216379b 2022-10-05 02:50:31 -05:00
evazion
528d03a60b forum: add more min_levels options. 2022-10-05 01:32:57 -05:00
evazion
24216379b7 posts: increase levelblocked to approver 2022-10-05 01:14:15 -05:00
Talulah
6a71508c3b show locked/unlocked changes on wiki page histories 2022-10-03 19:20:03 -03:00
evazion
86e69e3401 emails: add fix script to delete duplicate email addresses.
In the past it was possible for users to create multiple accounts with
the same email address. We had about 9000 such accounts. This removes
the email address from these accounts.

When multiple accounts have the same email address, the account that
visited the site last gets to keep the address.
2022-10-02 23:59:54 -05:00
evazion
99846b7e3d users: allow mods to change the names of other users.
Allow moderators to forcibly change the username of other users. This is
so mods can change abusive or invalid usernames.

* A mod can only change the username of Builder-level users and below.
* The user can't change their own name again until one week has passed.
* A modaction is logged when a mod changes a user's name.
* A dmail is sent to the user notifying them of the change.
* The dmail does not send the user an email notification. This is so we
  don't spam users if their name is changed after they're banned, or if
  they haven't visited the site in a long time.

The rename button is on the user's profile page, and when you hover over
the user's name and open the "..." menu.
2022-10-02 01:32:10 -05:00
evazion
559bf1ae0a modqueue: fix the disapproved: metatag showing posts outside the queue.
Fix a bug where filtering the modqueue by the `disapproved:<reason>` tag
would return posts outside the modqueue.
2022-09-30 02:03:15 -05:00
evazion
b94cb7d824 emails: include logging information in email headers.
Log the following information in email headers:

* X-Danbooru-User: the user's name and ID.
* X-Danbooru-IP: the user's IP.
* X-Danbooru-Session: the users' session ID.
* X-Danbooru-URL: the page that triggered the email.
* X-Danbooru-Job-Id: the ID of the background job that sent the email.
* X-Danbooru-Enqueued-At: when the email was queued as a background job.
* X-Danbooru-Dmail: for Dmail notifications, the link to the Dmail.
* X-Request-Id: the request ID of the HTTP request that triggered the email.

Also make it so we log an event in the APM when we send an email.
2022-09-29 04:36:11 -05:00
evazion
4c03ea5be3 Fix #5132: Modqueue displays active posts when excluding any search term
Fix a bug where searching for a negated tag inside the modqueue would show
active posts.

The bug was that in a search like this:

    Post.in_modqueue.user_tag_match("-solo")

The `in_modqueue` condition would get sucked inside the tag search and negated
when we tried to apply the negation operator to the "solo" tag. So effectively
the `in_modqueue` condition would get negated and we would end up searching for
everything not in the modqueue.
2022-09-28 00:29:50 -05:00
evazion
f49b3c439f posts: optimize modqueue page, status:modqueue, and status:unmoderated searches.
* Optimize status:modqueue and status:unmoderated searches. This brings them down from
  taking 500ms-1000ms per search to ~5ms.

* Change status:unmoderated so that it only filters out the user's disapproved posts, not
  the user's own uploads or past approvals. Now it's equivalent to `status:modqueue -disapproved:evazion`,
  whereas before it was equivalent to `status:modqueue -disapproved:evazion -approver:evazion -user:evazion`.
  Filtering out the user's own uploads and approvals was slow and usually unnecessary,
  since for most users it's rare for their own uploads or approvals to reenter the modqueue.

Before status:modqueue did this:

   SELECT * FROM posts WHERE is_pending = TRUE OR is_flagged = TRUE OR (is_deleted = TRUE AND id IN (SELECT post_id FROM post_appeals WHERE status = 0))

Now we do this:

   SELECT * FROM posts WHERE id IN (SELECT id FROM posts WHERE is_pending = TRUE UNION ALL SELECT id FROM posts WHERE is_flagged = TRUE UNION ALL SELECT id FROM posts WHERE id IN (SELECT post_id FROM post_appeals WHERE status = 0))

Postgres had a bad time with the "pending or flagged or has a pending appeal" clause because
it didn't know that posts can only be in one state at a time, so it overestimated how many
posts would be returned and chose a seq scan. Replacing the OR with a UNION avoids this.
2022-09-28 00:29:50 -05:00
evazion
65dbd89e25 Fix #4978: -approver:username implicitly adds approver:any
Fix the approver:, parent:, and pixiv: metatags not working correctly when negated:

* Fix -approver:<name> not including posts that don't have an approver (the approver_id is NULL)
* Fix -parent:<id> not including posts that don't have a parent (the parent_id is NULL)
* Fix -pixiv:<id> not including posts that aren't from Pixiv (the pixiv_id is NULL)

The problem lies how the equality operator is negated when the column contains NULL values;
`approver_id != 52664` doesn't match posts where the `approver_id` is NULL.

The search `approver:evazion` boils down to:

    # Post.where(approver_id: 52664).to_sql
    SELECT * FROM posts WHERE approver_id = 52664;

When that is negated with `-approver:evazion`, it becomes:

    # Post.where(approver_id: 52664).invert_where.to_sql
    SELECT * FROM posts WHERE approver_id != 52664;

But in SQL, `approver_id != 52664` doesn't match when the approver_id IS NULL, so the search doesn't
include posts without an approver.

We could use `a IS NOT DISTINCT FROM b` instead of `a = b`:

    # Post.where(Post.arel_table[:approver_id].is_not_distinct_from(52664)).to_sql
    SELECT * FROM posts WHERE approver_id IS NOT DISTINCT FROM 52664;

This way when it's inverted it becomes `IS DISTINCT FROM`:

    # Post.where(Post.arel_table[:approver_id].is_not_distinct_from(52664)).invert_where.to_sql
    SELECT * FROM posts WHERE approver_id IS NOT DISTINCT FROM 52664;

`approver_id IS DISTINCT FROM 52664` is like `approver_id != 52664`, except it matches when
approver_id is NULL [1].

This works correctly, however the problem is that `IS NOT DISTINCT FROM` can't use indexes because
of a long-standing Postgres limitation [2]. This makes searches too slow. So instead we do this:

    # Post.where(approver_id: 52664).where.not(approver_id: nil).to_sql
    SELECT * FROM posts WHERE approver_id = 52664 AND approver_id IS NOT NULL;

That way when negated it becomes:

    # Post.where(approver_id: 52664).where.not(approver_id: nil).invert_where.to_sql
    SELECT * FROM posts WHERE approver_id != 52664 OR approver_id IS NULL;

Which is the correct behavior.

[1] https://modern-sql.com/feature/is-distinct-from
[2] https://www.postgresql.org/message-id/6FC83909-5DB1-420F-9191-DBE533A3CEDE@excoventures.com
2022-09-26 19:28:10 -05:00
evazion
67c992bfbf post events: show post-related mod actions on post event page.
Show the following actions on the post events page:

* Post bans and unbans
* Post deletions and undeletions
* Thumbnail regenerations and IQDB regenerations
* Favorites moves
* Rating locks and unlocks
* Note locks and unlocks

Fixes #3825: Events/Moderation page for each post should show eventual ban actions
2022-09-26 03:24:50 -05:00
evazion
75a2814f18 mod actions: fix ip unban and modreport actions being visible to non-mods.
Fix IP unban actions and moderation report handled/rejected actions
being visible to non-moderators in the mod actions log.

Moderation report actions didn't leak the modreport itself, but it did
leak which moderator handled or rejected it.
2022-09-25 23:16:21 -05:00
evazion
17c6a2d77b mod actions: add options to filter /mod_actions by subject. 2022-09-25 23:02:46 -05:00
evazion
c154ce64fc modreports: fix exception when searching by recipient_name. 2022-09-25 15:06:08 -05:00
evazion
34057b25e1 mod actions: record the subject of the mod action.
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.
2022-09-25 04:04:28 -05:00
evazion
718c4d121b posts: fix double deletion bug.
Fix a bug where, if a user a was deleting a post and they accidentally
clicked the delete button twice, it could create two flags.
2022-09-24 23:41:14 -05:00
evazion
361af6a4cb posts: rework post events page.
* Add a global /post_events page that shows the history of all approvals,
  disapprovals, flags, appeals, and replacements on a single page.

* Redesign the /posts/:id/events page to show all approval, disapproval,
  flag, appeal, and replacement events for a single post (before it only
  showed approvals, flags, and appeals).

* Remove the replacement history link from the post show page. Replacements
  are now included in the post events page (closes #4948: Highlighed replacements).

* Add /post_approvals/:id and /post_replacements/:id routes (these are
  used by the "Details" link on the post events page).
2022-09-24 20:12:41 -05:00
evazion
adba70a0de api: make IP addresses in the API.
Make the following fields visible in API responses:

* ip_bans.ip_addr
* ip_geolocations.ip_addr
* ip_geolocations.network
* users.last_ip_addr (mod only)
* user_sessions.ip_addr
* api_keys.last_ip_address
* api_keys.permitted_ip_addresses

Before IP addresses were globally hidden in API responses because IPs were
present in a lot of tables and we didn't want to accidentally leak them.
Now that we've gotten rid of IPs from most tables, it's safe to unhide them.
2022-09-24 03:48:45 -05:00
evazion
7bf824f0dd disapprovals: fix searching by user.
Fix searching post disapprovals by user to use the new `visible_for_search`
mechanism. This fixes it so you can do subsearches on the user field, like this:

* https://danbooru.donmai.us/post_disapprovals?search[user][level]=32 (find disapprovals by Builder-level approvers)
2022-09-23 21:17:16 -05:00
evazion
e5edd79180 flags: fix flagger:<name> not returning self-flagged uploads
Fix the search `flagger:evazion user:evazion` not returning the user's own self-flagged uploads.

Followup to a6e0872ce.

Fixes #4690: user profile 'flags' count links to /post_flags with different search criteria
2022-09-22 23:07:53 -05:00
evazion
dff27e3a3a comments: put search form on same page as search results.
* Remove the /comment/search page. Instead put the comment search form
  on the same page as the search results, so you don't have to go back
  and forth to update your search.
* Add an "Edited?" search option, for finding comments that have been edited.
* Add options for sorting by oldest comments and lowest scoring comments.
2022-09-22 20:56:10 -05:00
evazion
a442658f8a Fix #5237: Deleted comments can be viewed by other users
* Fix it so non-moderators can't search deleted comments using the
  `updater`, `body`, `score`, `do_not_bump_post`, or `is_sticky` fields.
  Searching for these fields will exclude deleted comments.

* Fix it so non-moderators can search for their own deleted comments using the
  `creator` field, but not for deleted comments belonging to other users.

* Fix it so that if a regular user searches `commenter:<username>`, they
  can only see posts with undeleted comments by that user. If a moderator or
  the commenter themselves searches `commenter:<username>`, they can see all
  posts the user has commented on, including posts with deleted comments.

* Fix it so the comment count on user profiles only counts visible
  comments. Regular users can only see the number of undeleted comments
  a user has, while moderators and the commenter themselves can see the
  total number of comments.

Known issue:

* It's still possible to order deleted comments by score, which can let
  you infer the score of deleted comments.
2022-09-22 19:17:33 -05:00
evazion
88ac91f5f3 search: refactor to pass in the current user explicitly. 2022-09-22 04:31:21 -05:00
evazion
b56b6c554b commentaries: perform full-text search instead of substring search.
Switch `/artist_commentaries?search[text_matches]` to do a full-text
search instead of a substring search. This is more consistent with text
search in other places.
2022-09-22 01:56:14 -05:00
evazion
29a4ca0818 pools: switch from search[name_matches] to search[name_contains].
The previous commit changed it so that `/pools?search[name_matches]`
does a full-text search. So for example, `search[name_matches]=smiling`
will now match pool names containing any of the words "smiling",
"smile", "smiles", or "smiled".

This commit adds a `/pools?search[name_contains]` param that does what
`name_matches` did before, and switches to it in search forms. So for
example, `search[name_contains]=smiling` will only match pool names
containing the exact substring "smiling".

This change is so that `<field>_matches` works consistently across the
site, and so that it's possible to search pool names by either an exact
substring match, or by a looser natural language match.

This is a minor breaking API change. API users can replace
`/pools?search[name_matches]` with `/pools?search[name_contains]` to get
the same behavior as before. The same applies to /favorite_groups.
2022-09-22 01:52:13 -05:00
evazion
3114ef3daf searchable: standardize the <field>_matches operator for text fields.
Standardize it so that all fields of type `text` are searchable with
`search[<field>_matches]`.

Before, the `<field>_matches` param was handled manually and some fields
were left out or handled inconsistently. Now it applies to all columns
of type `text`.

This does a full-text search on the field, so for example, searching
`/artist_commentaries?search[translated_description_matches]=smiling`
will match translated commentaries containing either the word "smiling",
"smiles", "smiled", or "smile".

Note that this only applies to columns defined as type `text`, not to
columns defined as `character varying`. The difference is that `text` is
used for fields containing free-form natural language, such as comments,
notes, forum posts, wiki pages, pool descriptions, etc, while `character
varying` is used for short strings not containing free-form language,
such as tag names, wiki page titles, urls, status fields, etc.

API changes:

* Add the `search[original_title_matches]`, `search[original_description_matches]`,
  `search[translated_title_matches]`, `search[translated_description_matches]` params
  to /artist_commentaries and /artist_commentary_versions.
* Remove the `search[name_matches]` and `search[group_name_matches]` params from /artist_versions.
* Remove the `search[title_matches]` param from /wiki_page_versions.
* Change the `search[name_matches]` param on /pools, /favorite_groups, and /pool_versions
  to do a full-text search instead of a substring match.
2022-09-22 01:52:13 -05:00
evazion
a6e0872ce4 flags: fix mods not being able to see the flagger on self-flagged posts.
Fix a bug where, when a mod searched for their own flags, they couldn't
see their own self-flagged uploads.

Fix a bug where, when a mod viewed their own flags, they couldn't see
the flagger name for their own self-flagged uploads.

This also makes it so you can do things like `/post_flags?search[creator][level]=20`
to search flags by user level.
2022-09-22 01:52:13 -05:00
evazion
a229a6f5c4 models: remove ignored_columns declarations.
These columns have been removed from the underlying database.
2022-09-20 23:09:32 -05:00
evazion
23f9a1af7e mod actions: update /mod_actions index.
* Add newest and oldest order options.
* Rearrange columns to match /user_actions page.
2022-09-19 05:09:06 -05:00
evazion
2119a8efc5 mod actions: fix messages to use consistent format.
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.
2022-09-18 21:56:57 -05:00
evazion
72e95b6ca3 flags: allow approvers to bypass the "can't flag more than once in 3 days" rule.
Allow approvers to bypass the rule that you can't flag a post again if
it was flagged less than 3 days ago. This rule was intended to prevent
flag warring among regular users, which hopefully shouldn't be a problem
among approvers. It was also useless because approvers could always
just directly delete the post even if they couldn't flag it.

Allowing approvers to reflag posts allows them to reinstate flags that
were accidentally approved.
2022-09-18 15:56:35 -05:00
evazion
0c919a6bc8 versions: remove 'subsequent' version comparison option.
This option was rarely used and what it actually did was usually
difficult to understand.
2022-09-18 15:56:10 -05:00
evazion
1d2bac7b95 Remove CurrentUser.ip_addr.
Remove the `CurrentUser.ip_addr` global variable and replace it with
`request.remote_ip`. Before we had to track the current user's IP in a
global variable so that when we edited a post for example, we could pass
down the user's IP to the model and save it in the post_versions table.
Now that we now longer save IPs in version tables, we don't need a global
variable to get access to the current user's IP outside of controllers.
2022-09-18 05:02:10 -05:00
evazion
d4da8499ce models: stop saving IP addresses in version tables.
Mark various `creator_ip_addr` and `updater_ip_addr` columns as ignored
and stop updating them in preparation for dropping them.
2022-09-18 03:49:17 -05:00
evazion
553d35178c Remove IpAddress model. 2022-09-17 23:30:13 -05:00
evazion
a62e844a1a forum: fix visibility of forum post votes.
Make all forum post votes visible to everyone.

When forum votes were first introduced, it was technically possible to
vote on any forum post, including on posts in mod-only threads.
Accordingly, forum post votes were only visible if the forum post itself
was visible. However, there doesn't actually exist any votes on private
forum posts, and trying to filter them out makes the /user_actions page
much slower, so just make them visible to everyone.
2022-09-16 06:01:44 -05:00
evazion
bd73090b4c user events: make all events visible to moderators.
Allow moderators to see all events on the /user_events page. Before only
admins could see when a user changed their email, changed their
password, or had a failed login attempt. Now moderators can see these
events too.

Filtering these events out made the /user_actions page slower, and it
wasn't really necessary since merely knowing that a user changed their
email or password isn't that much more sensitive than knowing when they
logged in or out.
2022-09-16 06:01:44 -05:00
evazion
ee638f976f Add /user_actions page.
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.
2022-09-16 05:39:25 -05:00
evazion
cfe567b649 uploads: fix exception in UploadMediaAsset.visible.
Fix `UploadMediaAsset.visible(user).count` failing when we weren't
joined on the uploads table.
2022-09-15 19:19:44 -05:00
evazion
0a5ebcc69d uploads: refactor media asset validation logic.
Refactor the upload validation logic to not depend on the current user.
Fixes several broken upload tests.
2022-09-15 05:09:07 -05:00
evazion
9e16de13ef Merge pull request #5220 from nonamethanks/duration-validation
Uploads: allow admins to bypass duration limits again
2022-09-15 03:46:21 -05:00
evazion
ab900beffd Merge pull request #5250 from jwood7423/Add-api-to-the-list-of-meta-wikis
Added `api:` to the list of META_WIKIS
2022-09-15 03:43:42 -05:00
evazion
fb980d4a16 notes: merge versions when note is deleted.
Unlike other models, notes had a special rule where if you deleted or
undeleted a note, it would always create a new version instead of
merging it into the previous version. Remove this rule since it didn't
have a purpose and it was inconsistent with other versioned models.
2022-09-12 22:10:14 -05:00
evazion
2c37fdf9e8 tags: don't create mod action when tag is deprecated.
Not needed anymore since deprecations are now tracked in the tag history.
2022-09-12 02:06:16 -05:00
evazion
bb728ecebf tags: add /tag_versions page. 2022-09-11 18:41:16 -05:00