Fix not being able to negate the following metatags:
* id (didn't support ranges)
* md5
* width
* height
* mpixels
* ratio
* score
* favcount
* filesize
* date
* age
* tagcount
* pixiv
`normalize_query` is used in certain places on the post index page where
we don't want to pay the cost of looking up tag aliases (namely inside
fast_count, in post_search_count_js, and in tag change notices). Don't
normalize aliases by default unless we need to.
Several fixes for the "This tag is under discussion" notice on the post
index page:
* Fix the notice appearing for BURs that aren't pending.
* Fix the notice never going away because of the cache never expiring.
* List all topics when a tag is involved in multiple BURs.
* Link to the forum post instead of the forum topic (fix#4421).
* Optimization: don't check for BURs when the search isn't a simple
single tag search.
* Add a `tags` field to the bulk update requests table for tracking all
tags involved in the request (excluding tags in mass updates that are
negated/optional/wildcards). Known issue: doesn't handle tag type
prefixes in mass updates correctly (e.g. `mass update foo -> artist:bar`
doesn't detect the tag `bar`).
* Allow searching the /bulk_update_requests page by tags.
We don't really need to cache the notice here, but we do it anyway to
reduce queries on the post index page.
* Eliminate the `parse_query` method.
* Move all the metatag handling logic from the `build` method
to `metatag_matches` and helper methods.
This is to get all the main metatag handling logic in one place, inside
`metatag_matches`, so that it's easier to add new metatags and to handle
things like negated metatags more consistently.
* Move various search parser helper methods (`has_metatag?`,
`is_single_tag?` et al) from PostSets and the Tag model to
PostQueryBuilder.
* Fix various minor bugs stemming from trying to check if a search query
contains certain metatags using regexes or other adhoc techniques.
* Make scan_query, parse_query, normalize_query into instance methods
instead of class methods. This is to a) clean up the API and b)
prepare for moving certain tag utility methods into PostQueryBuilder.
* Fix a few cases where a caller used scan_query when they should have
used split_query or parse_tag_edit.
Fix a severe performance regression on the posts/index page introduced
by 6ca42947.
Short answer: scan_query dynamically allocated a regex inside an
inner loop that was called thousands of times per pageload.
Long answer:
* The post index page checks each post to see if they're tagged loli/shota,
* This triggers a call to Post#tag_array for every post.
* Post#tag_array called scan_query to split the tag string.
* scan_query loops over the tag string, checking if each tag matches the
regex /#{METATAGS.join("|")}:/.
* This regex uses string interpolation, which makes Ruby treat as a
dynamic value rather than a static value. Ruby doesn't know the
interpolation is static here. This causes the regex to be reallocated
on every iteration of the loop, or in other words, for every tag in
the tag string.
* This caused us to do thousands of regex allocations per pageload. On
average, a posts/index pageload contains 20 posts with ~35 tags per
post, or 7000+ total tags. Doing this many allocations killed performance.
The fix:
* Don't use scan_query for Post#tag_array. We don't have to fully parse
the tag_string here, we can use a simple split.
* Use the /o regex flag to tell Ruby to treat the regex as static and
only evaluate the interpolation once.
* Fix not being able to use the status: metatag twice in the same search.
* Fix status:active excluding banned posts.
* Fix status:garbage returning all posts.
Add:
* commentary:true (posts with commentary)
* commentary:false (posts without commentary)
* commentary:translated (posts with translated commentary)
* commentary:untranslated (posts with untranslated commentary)
* commentary:"text" (posts where any commentary field matches "text")
Known issues:
* There's no way to escape the true, false, translated, or
untranslated keywords to do a literal text search for commentaries
containing one of these keywords.
* Negated searches may be slow. Using a left outer join instead of a
subquery would be faster in most cases, but negating it is harder.
Change favgroup:<name> searches to return no results instead of raising
a UserPrivilege error when an unpermitted user searches for a private
favgroup.
Partial fix for #4389.
Partial fix for #4389.
* Fix invalid username searches returning all posts instead of no posts.
* Fix "user:A user:B" returning results for user:B instead of no results.
* Fix "approver:A approver:B" returning results for approver:B instead of no results.
* Add support for negated -commenter, -noter, -noteupdater, -upvote, -downvote metatags.
* Add support for "any" and "none" values for all username metatags,
including negated metatags that didn't support "any" or "none" before.
* Change noter:any and commenter:any to include posts with deleted notes
or comments. Note that commenter:<username> already included deleted
comments before. This is so that commenter:any has the same behavior
as commenter:<username>
* Fix corrupted image detection. We were shelling out to vips and trying
to grep for error messages, but the error message for jpeg files changed.
Now we load the file in ruby vips, which raises an error on failure.
* Don't attempt to redownload corrupted images. If a download completes
without any errors yet the downloaded file is corrupt, then something is
wrong at the source and redownloading is unlikely to help. Let the
upload fail and the user retry if necessary.
* Validate that all uploads are uncorrupted, including files uploaded
from a computer, not just files uploaded from a source.
* Make IP bans soft deletable.
* Add a hit counter to track how many times an IP ban has blocked someone.
* Add a last hit timestamp to track when the IP ban last blocked someone.
* Add a new type of IP ban, the signup ban. Signup bans restrict new
signups from editing anything until they've verified their email
address.
* Let moderators see name changes for deleted users on the user name
change requests index and show pages. Before they could see name changes
for deleted users on user profiles, but not on the user name changes index.
* Let members see previous names on profile pages. Before they could see
previous names on the user name changes index, but not on profile pages
(ref: #4382).
* Allow tagging a post with a `disapproved:<disinterest|breaks_rules|poor_quality>` to disapprove it.
* Disallow disapproving active posts.
Fixes#4384.
- Tag matches allows a user to search for a single tag
-- Since testing for multiple tags would require converting the "tags"
string to an array which would most likely fail even for single tags
- Is new for quick searching of uploads or not uploads
- "Current" is now most like the old format
-- It is therefore now the default for post versions
- Only show the actual edits in their own column
- Show the current state at that version in another column
- On the "previous" view, don't double-show full list of tags for
the first post versions, so leave edits blank
* Add a "View original" sidebar option.
* Rename the "View large" sidebar option to "View smaller".
* Remove the "Loading..." message when switching image sizes.
* Fix the V hotkey not working after using it once.
* Change #image-resize-link to .image-view-original link (note that
there are two of these links now, one in the notice bar and one in the
sidebar).
* Add a `data-post-current-image-size` attribute on the <body> element
and use it to control visibility of links and notices.
Remove the ability to authenticate to the API with the `login` and
`password_hash` url parameters. This is a legacy authentication method
from Danbooru 1. How to actually generate the password_hash for this
method hasn't been fully documented for many years now. It required
taking the SHA1 hash of your password combined with an undocumented salt
value (i.e., password_hash = sha1("choujin-steiner--#{password}")).
This authentication method was also slow because it required checking
the password on every API call. Checking passwords is deliberately slow
because passwords are hashed with BCrypt. BCrypt takes about ~200ms per
request, so using this method effectively limited you to ~5 requests per
second in a single thread.
* Make authentication methods into User instance methods instead of
class methods.
* Fix API key authentication to use a secure string comparison. Fixes a
hypothetical (unlikely to be exploitable) timing attack.
* Move login logic from SessionCreator to SessionLoader.
Require users who signup using proxies to verify their email addresses
before they can perform any edits. For verification purposes, the email
must be a nondisposable address from a whitelist of trusted email
providers.
Pull the password reauthentication logic out of the user model and put
it in the password update controller where it belongs.
This fixes an issue where when a new user was created the user model had
an incorrect password error set on it by `encrypt_password_on_update`.
It was trying to verify the old password even though we don't have one
when creating a new user. This error caused the user create action to
redirect back to the signup page because `respond_with` thought that
creating the user failed.
Reject email addresses that known to be undeliverable during signup.
Some users signup with invalid email addresses, which causes the welcome
email (which contains the email confirmation link) to bounce. Too many
bounces hurt our ability to send mail.
We check that an email address is undeliverable by checking if the
domain has a mail server and if the server returns an invalid address
error when attempting to send mail. This isn't foolproof since some
servers don't return an error if the address doesn't exist. If the
checks fail we know the address is bad, but if the checks pass that
doesn't guarantee the address is good. However, this is still good
enough to filter out bad addresses for popular providers like Gmail and
Microsoft that do return nonexistent address errors.
The address existence check requires being able to connect to mail
servers over port 25. This may fail if your network blocks port 25,
which many home ISPs and hosting providers do by default.