Commit Graph

78 Commits

Author SHA1 Message Date
evazion
4448b3d15b posts: fix incorrect post counts for -pool:, -fav: searches
Fix `-pool:1234` and `-fav:evazion` searches incorrectly returning the
same post count as `pool:1234` and `fav:evazion` searches.
2022-08-28 23:17:01 -05:00
evazion
e3af738371 tests: fix broken tests. 2022-08-24 02:03:37 -05:00
evazion
05df3a194c posts: add more free metatags.
The following metatags no longer count against the tag search limit:

* is
* id
* date
* age
* filesize
* filetype
* parent
* child
* md5
* width
* height
* duration
* mpixels
* ratio
* score
* upvotes
* downvotes
* favcount
* embedded
* tagcount
* pixiv_id
* pixiv

These are mostly metatags that have to do with properties of the post
itself. Other metatags still count because they involve things like
subqueries or joins, or they're more tag-like in function.
2022-06-05 14:28:44 -05:00
evazion
81bd86d202 posts: add "general" rating; rename "safe" rating to "sensitive".
* Add "general" rating.
* Rename "safe" rating to "sensitive".
* Change safe mode to include both rating:s and rating:g.
* Treat rating:safe as a synonym for rating:sensitive.
* Link "howto:rate" in the post edit form.
2022-05-22 13:38:45 -05:00
evazion
9867514a78 Fix #5177: ordfav with commentary search raises exception. 2022-05-20 22:59:02 -05:00
evazion
0fe9356bf6 tests: fix broken tests. 2022-05-20 22:51:02 -05:00
evazion
181639368c posts: add is: and has: metatags.
Add the following metatags:

* is:parent
* is:child
* is:safe
* is:questionable
* is:explicit
* is:sfw (same as -rating:q,e)
* is:nsfw (same as rating:q,e)
* is:active
* is:deleted
* is:pending
* is:flagged
* is:appealed
* is:banned
* is:modqueue
* is:unmoderated
* is:jpg
* is:png
* is:gif
* is:mp4
* is:webm
* is:swf
* is:zip
* has:parent
* has:children
* has:source
* has:appeals
* has:flags
* has:replacements
* has:comments
* has:commentary
* has:notes
* has:pools

All of these searches were already possible with other metatags, but these might be more convenient.
2022-05-18 13:04:15 -05:00
evazion
141044d352 posts: refactor hardcoded ratings.
Refactor ratings to not be hardcoded in various places. Make it so
all ratings are defined in Post::RATINGS.

Also make it so that you can search multiple ratings at once with `rating:q,e`.
2022-05-18 13:04:15 -05:00
evazion
f117049750 users: remove 'hide deleted posts' account setting.
This setting automatically added the `-status:deleted` metatag to all searches. This meant deleted
posts were filtered out at the database level, rather than at the html level. This way searches
wouldn't have less-than-full pages.

The cost was that searches were slower, mainly because post counts weren't cached. Normally when you
search for a tag, we can get the post count from the tags table. If the search is actually like
`touhou -status:deleted`, then we don't know the count and we have to calculate it on demand.

This option is being removed because it did the opposite of what people thought it did. People
thought it made deleted posts visible, when actually it made them more hidden.
2022-05-01 00:47:46 -05:00
evazion
ccd0dde081 Fix #5013: BUR model doesn't validate tags.
Don't allow users to request aliases, implications, or renames for invalid tag names.

As a side effect, it's no longer possible to request shortcut aliases like
`/hr -> hakurei_reimu` (slash abbreviations still exist, but they can't
be overridden with aliases). Tests involving these types of aliases are
removed.
2022-04-30 20:03:04 -05:00
evazion
918f32c554 Fix #4461: Improve posts/index page titles. 2022-04-30 01:52:33 -05:00
evazion
906ac25221 autocomplete: fix metatags not completing until a character is typed.
Fix metatags not showing autocomplete results until after the first
letter was typed. For example, typing `filetype:` didn't show any
completions until another letter was typed. Now typing `filetype:` shows
all available file types.

This was because `filetype:` by itself wasn't recognized as a valid
search before, since metatags always required a value. Now it is a valid
search, so it's technically possible to search for `filetype:` by
itself. In this case the metatag value will be the empty string, which
will return no results because there are no posts where the filetype is
the empty string.

This sounds nonsensical, but it's potentially useful for metatags like
the `source:` metatag, where searching for posts with an empty source
does make sense. It was also technically possible before by searching
for `source:""`, so making the value optional doesn't change anything.
2022-04-29 22:22:11 -05:00
evazion
db6bb2ccac Fix #5136: Regular tags are now case-sensitive.
* Fix `AST.tag` to downcase the tag name.
* Change PostQuery::Parser to use build nodes using `AST.tag`,
  `AST.metatag`, `AST.wildcard`, etc methods instead of building nodes
  directly. This way all the normalization happens in the node
  constructor methods instead of in the parser.
2022-04-22 02:14:07 -05:00
evazion
6c5dd5ffed tests: fix broken tests. 2022-04-18 00:31:31 -05:00
evazion
eca0ab04f7 post queries: raise error on invalid searches.
Raise an error if the search is invalid for one of the following reasons:

* It contains multiple conflicting order: metatags (e.g. `order:score order:favcount` or `ordfav:a ordfav:b`).
* It contains a metatag that can't be used more than once: (e.g. `limit:5 limit:10`, `random:5 random:10`).
* It contains a metatag that can't be negated (e.g. `-order:score`, `-limit:20`, or `-random:20`).
* It contains a metatag that can't be used in an OR clause (e.g. ` touhou or order:score`, `touhou or limit:20`, `touhou or random:20`).
2022-04-17 23:20:22 -05:00
evazion
3e8e33e663 post queries: fix handling of '~' operator.
Fix queries like `(~a ~b) (~c ~d)` being handled like `~a ~b ~c ~d`.
Caused by trimming AND nodes from the tree before rewriting the '~'
operator, which caused `~a` terms to be incorrectly lifted out of
subexpressions.
2022-04-17 23:20:22 -05:00
evazion
af183467b6 post queries: switch to new post search engine.
Switch to the post search engine using the new PostQuery parser. The new
engine fully supports AND, OR, and NOT operators and grouping expressions
with parentheses.

Highlights:

New OR operator:

* `skirt or dress` (same as `~skirt ~dress`)

Tags can be grouped with parentheses:

* `1girl (skirt or dress)`
* `(blonde_hair blue_eyes) or (red_hair green_eyes)`
* `~(blonde_hair blue_eyes) ~(red_hair green_eyes)` (same as above)
* `(pantyhose or thighhighs) (black_legwear or brown_legwear)`
* `(~pantyhose ~thighhighs) (~black_legwear ~brown_legwear)` (same as above)

Metatags can be OR'd together:

* `user:evazion or fav:evazion`
* `~user:evazion ~fav:evazion`

Wildcard tags can combined with either AND or OR:

* `black_* white_*` (find posts with at least one black_* tag AND one white_* tag)
* `black_* or white_*` (find posts with at least one black_* tag OR one white_* tag)
* `~black_* ~white_*` (same as above)

See 4c7cfc73 for more syntax examples.

Fixes #4949: And+or search?
Fixes #5056: Wildcard searches return unexpected results when combined with OR searches
2022-04-17 23:20:22 -05:00
Talulah
c1996e4f06 favgroups: allow favgroup:any/none searches 2022-04-12 23:01:19 -03:00
evazion
86de5cb5d2 posts: fixup flagger: metatag.
Fix regression in 01a22930e.
2022-04-06 23:57:50 -05:00
evazion
a12f82cb86 tests: fix tag name '(' test broken by dd21d4b45. 2022-03-26 16:31:20 -05:00
evazion
0baca68a37 search: make order:random truly random; add random:N metatag.
Make the `order:random` metatag truly randomize the search. Add a
`random:N` metatag that returns up to N random posts, like what
`order:random` did before.

`order:random` now returns the entire search in random order. Before it
just returned a pageful of pseudorandom posts. This will be more
accurate for small searches, but slower for large searches. If
`order:random` times out, try `random:N` instead.

The `random:N` metatag returns up to N pseudorandom posts. This is
faster than `order:random` for large searches, but for small searches,
it may return less than N posts, and the randomness may be biased. Some
posts may be more likely than others to appear. N must be between 0 and
200.

Also, `/posts?tags=touhou&random=1` now redirects to `/posts?tags=touhou+random:N`.
Before the `random=1` param acted like a free `order:random` tag; now it
redirects to a `random:N` search, so it counts against your tag limit.
2021-11-25 18:14:34 -06:00
evazion
eda23c719a votes: fixup various minor issues.
* Add a gap between thumbnails on mobile.
* Adjust CSS for scores and vote buttons.
* Include "Private favorites" as an incentive on the user upgrade page.
* Fix vote buttons not being visible beneath thumbnails on mobile.
* Fix the "Show scores" link not preserving the current page number.
* Fix vote buttons being unintentionally enabled for all thumbnails by default.
* Fix banned and restricted users being able to favorite posts by
  tagging them with `fav:self`.
* Fix search engines being able to crawl /posts?view=score pages.
* Fix broken tests.
2021-11-20 02:40:18 -06:00
evazion
1a27b1d5eb votes: make upvotes visible to everyone by default.
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.
2021-11-16 05:23:54 -06:00
evazion
43c2870664 Fix #4917: Add down_score/up_score orders and metasearches.
Add `upvotes:N`, `downvotes:N`, `order:upvotes`, `order:downvotes`,
`order:upvotes_asc`, `order:downvotes_asc` metatags.

In the API, the field is called up_score / down_score. Here it's called
`upvotes` and `downvotes` because this should be easier to understand
for end users.

Note that internally, `down_score` is negative. A post that matches
`downvotes:>5` will have down_score < -5 internally.
2021-11-16 03:52:38 -06:00
evazion
a5ed8c72c9 search: fix parsing of invalid metatag values.
* Change `age:` metatag to require time units. This means e.g.
  `age:<600` no longer works; instead you have to say `age:<600sec`.

* Allow time units in the `age:` metatag to be abbreviated as long as
  they're unambiguous. This means `age:<60sec`, `age:<5min`, and
  `age:<5mon` now work, in addition to `age:<60s` and `age:<60seconds`.

* Allow the `ratio:` metatag to be written like `ratio:16/9` in addition
  to `ratio:16:9`.

* Fix invalid date searches like `date:foo` or `date:05-15-2021`
  to return nothing instead of raising an "undefined method
  'beginning_of_day' for nil" exception. (`date:05-15-2021` is invalid
  because it's parsed as DD-MM-YYYY).

* Fix invalid searches like `score:foo`, `ratio:foo`, and `mpixels:foo`
  to return nothing instead of being treated like `score:0`, `ratio:0`,
  `mpixels:0`.

* Fix `age:<60m` to return nothing instead of silently being treated
  like `age:<60seconds`.

* Fix `age:foo` to return nothing instead of silently being treated like
  `age:0d` (return all uploads from today).

Fixes #4389.
2021-11-02 01:54:05 -05:00
evazion
a9088d8a87 search: fix flag_count:N metatag being broken. 2021-10-24 17:02:38 -05:00
evazion
0b22e873c9 search: cache timed out search counts.
When a search is performed, we cache the post count so we don't have to
calculate it again every time the user switches pages. However, if the
count times out, we didn't cache it before, causing us to do a slow
count on every page load. This usually happens on multi-tag searches
that return a lot of results, `1girl solo` for example.

This changes it so that the count is cached even when it times out. This
will speed up large multi-tag searches.

This also changes it so that the count is cached for a fixed 5 minutes.
Before it was variable based on the size of the count, but this probably
didn't make much difference.
2021-10-12 01:33:21 -05:00
evazion
37a8dc5dbd posts: use string_to_array index for tag searches.
Use the `string_to_array(tag_string, ' ')` index instead of the
`tag_index` for tag searches. The string_to_array index lets us treat
the tag_string as an array for searching purposes. This lets us get rid
of the tag_index column and the test_parser dependency in the future.
2021-10-10 22:00:10 -05:00
evazion
c4eeeb8531 search: optimize counting posts for fav: and pool: searches.
Optimize counting the number of posts returned by fav:<name> and
pool:<name> searches. Use cached counts to avoid slow count(*) queries
for users with lots of favorites.
2021-10-08 21:26:42 -05:00
evazion
595e02ab45 posts: add duration:<x> and order:duration metatags.
Add duration:<x> and order:duration metatags for searching animated
posts by duration.

https://danbooru.donmai.us/posts?tags=animated+duration:<5.0
https://danbooru.donmai.us/posts?tags=animated+duration:>60
https://danbooru.donmai.us/posts?tags=animated+order:duration
2021-10-07 03:21:08 -05:00
evazion
126046cb69 posts: remove rating, note, and status locks.
Remove the ability for users to lock ratings, note, and post statuses.

Historically the majority of locked posts were from 10+ years ago when
certain users habitually locked ratings and notes on every post they
touched for no reason. Nowadays most posts have been unlocked. Only a
handful of locked posts are left, none of which deserve to be locked.

The is_rating_locked, is_note_locked, and is_status_locked columns still
exist in the database, but aren't used.
2021-09-27 22:32:30 -05:00
evazion
313257b771 posts: add exif:<value> search metatags.
Examples:

* https://danbooru.donmai.us/posts?tags=exif:File:ColorComponents
* https://danbooru.donmai.us/posts?tags=exif:GIF:GIFVersion
* https://danbooru.donmai.us/posts?tags=exif:PNG:ColorType

* https://danbooru.donmai.us/posts?tags=exif:PNG:ColorType=RGB
* https://danbooru.donmai.us/posts?tags=exif:GIF:GIFVersion=89a
* https://danbooru.donmai.us/posts?tags=exif:File:ColorComponents=3
2021-09-16 02:13:15 -05:00
evazion
d00aa847ae search: allow mods to search disapproved:<user> for other users.
Allow moderators to search `disapproved:<username>` with any user.
Before mods could only search for their own disapprovals, even though
they could see disapprovals by others.
2021-09-01 01:39:14 -05:00
evazion
a062c040cb saved searches: fail gracefully when Redis is disabled.
Just make saved searches return nothing when Redis is disabled.
2021-03-30 05:35:42 -05:00
evazion
28c0a48117 discord: fix tag search commands being limited to 2 tags. 2021-03-14 16:42:07 -05:00
evazion
19974d3ab1 Fix #4688: Malformed SQL when searching -status:any.
Negating `Post.all` produced the invalid SQL fragment `WHERE NOT ()`.
Use `Post.where("TRUE")` instead to produce `WHERE NOT (TRUE)`.
2021-02-03 21:15:58 -06:00
evazion
6ca007ee1f Fix #4670: Replace RequestStore with AS::CurrentAttributes.
This also requires replacing CurrentUser.name with CurrentUser.user.name
because the `name` method had a conflict with CurrentAttributes.
2021-01-16 12:43:20 -06:00
evazion
98ee6c31c1 favorites: refactor fav:/ordfav: searches to not use fav_string.
Refactor fav:<name> and ordfav:<name> searches to use the favorites
table instead of the posts.fav_string.

This may be slower for fav:<name> searches. The fav_string effectively
treats favorites like secret tags on the post, so fav:<name> searches
were effectively the same as tag searches. Now they do a subquery on the
favorites table, which may not perform as well for things like multiple
fav:<name> metatags or negated fav:<name> metatags.

For ordfav:<name> searches, this may be faster. ordfav: searches had a
tag match clause (`tag_index @@ 'fav:123'`) in addition to a join on the
favs table. This was redundant, and in some cases it inhibited the query
planner from choosing a more optimal plan.

Partially addresses #4652 by eliminating another place where we depended
on the fav_string.
2021-01-03 19:18:31 -06:00
evazion
2c1da660fd tags: allow tag abbreviations in searches and during tagging.
Expand the tag abbreviation system introduced in b0be8ae45 so that it
works in searches and when tagging posts, not just in autocomplete.

For example, you can tag a post with /evth and it will add the tag
eyebrows_visible_through_hair. You can search for /evth and it will
search for the tag eyebrows_visible_through_hair.

Some more examples:

* /ops is short for one-piece_swimsuit
* /hooe is short for hair_over_one_eye
* /saol is short for standing_on_one_leg
* /tlozbotw is short for the_legend_of_zelda:_breath_of_the_wild

If two tags have the same abbreviation, then the larger tag takes
precedence. For example, /be is short for blue_eyes, not brown_eyes,
because blue_eyes is the bigger tag.

If there is an existing shortcut alias that conflicts with the
abbreviation, then the alias take precedence. For example, /sh is short
for suzumiya_haruhi, not short_hair, because there's an old alias for
/sh -> suzumiya_haruhi.
2020-12-17 23:57:13 -06:00
evazion
b358714790 tests: add test for #4613. 2020-12-05 12:48:45 -06:00
evazion
d884cb6642 search: fix parsing of quoted metatag values.
* Fix #4552: Multiple quoted search terms not parsed correctly.
* Allow quotes to be escaped in quoted metatags.
* Allow spaces to be escaped in unquoted metatags.
* Allow the empty string to be used in metatags.

Examples:

* `source:""` and `source:''` (same as `source:none`)
* `source:foo\ bar\ baz` (same as `source:"foo bar baz"`)
* `source:"don't say \"lazy\""` (use \" to write a literal ")
* `source:'don\'t say "lazy"'` (use \' to write a literal ')
* `source:"C:\\Windows"` (use \\ to write a literal \)
2020-08-12 18:12:16 -05:00
evazion
0a0a85ee70 Fix #4568: Send appealed posts back to the mod queue
* Include appealed posts in the modqueue.

* Add `status` field to appeals. Appeals start out as `pending`, then
  become `rejected` if the post isn't approved within three days. If the
  post is approved, the appeal's status becomes `succeeded`.

* Add `status` field to flags. Flags start out as `pending` then become
  `rejected` if the post is approved within three days. If the post
  isn't approved, the flag's status becomes `succeeded`.

* Leave behind a "Unapproved in three days" dummy flag when an appeal
  goes unapproved, just like when a pending post is unapproved.

* Only allow deleted posts to be appealed. Don't allow flagged posts to be appealed.

* Add `status:appealed` metatag. `status:appealed` is separate from `status:pending`.

* Include appealed posts in `status:modqueue`. Search `status:modqueue order:modqueue`
  to view the modqueue as a normal search.

* Retroactively set old flags and appeals as succeeded or rejected. This
  may not be correct for posts that were appealed or flagged multiple
  times. This is difficult to set correctly because we don't have
  approval records for old posts, so we can't tell the actual outcome of
  old flags and appeals.

* Deprecate the `is_resolved` field on post flags. A resolved flag is a
  flag that isn't pending.

* Known bug: appealed posts have a black border instead of a blue
  border. Checking whether a post has been appealed would require either
  an extra query on the posts/index page, or an is_appealed flag on
  posts, neither of which are very desirable.

* Known bug: you can't use `status:appealed` in blacklists, for the same
  reason as above.
2020-08-06 20:55:45 -05:00
evazion
8ef2b7772d Merge pull request #4530 from BrokenEagle/parent-child-status-search
Add ability to search on status of parent/child
2020-06-23 23:53:57 -05:00
BrokenEagle
4acd89838b Add ability to search on status of parent/child 2020-06-21 22:39:21 +00:00
evazion
05f78f9bef saved searches: fix call to redis.exists?
https://github.com/redis/redis-rb/blob/master/CHANGELOG.md#421
2020-06-19 13:53:35 -05:00
evazion
ad02e0f62c posts/index: fix rating:s being included in page title in safe mode.
Fixes bug described in d3e4ac7c17 (commitcomment-39049351)

When dealing with searches, there are several variables we have to keep
in mind:

* Whether tag aliases should be applied.
* Whether search terms should be sorted.
* Whether the rating:s and -status:deleted metatags should be added by
  safe mode and the hide deleted posts setting.

Which of these things we need to do depends on the context:

* We want to apply aliases when actually doing the search, calculating
  the count, looking up the wiki excerpt, recording missed/popular
  searches in Reportbooru, and calculating related tags for the sidebar,
  but not when displaying the raw search as typed by the user (for
  example, in the page title or in the tag search box).
* We want to sort the search when calculating cache keys for fast_count
  or related tags, and when recording missed/popular searches, but not
  in the page title or when displaying the raw search.
* We want to add rating:s and -status:deleted when performing the
  search, calculating the count, or recording missed/popular searches,
  but not when calculating related tags for the sidebar, or when
  displaying the page title or raw search.

Here we introduce normalized_query and try to use it in contexts where
query normalization is necessary. When to use the normalized query
versus the raw unnormalized query is still subtle and prone to error.
2020-05-12 21:47:00 -05:00
evazion
438186a75a search: fix user-dependent searches showing incorrect paginators.
Some searches, such as searches for private favorites or for the
status:unmoderated tag, return different results for different users.
These searches need to have their counts cached separately for each user
so that we don't return incorrect page counts when two different users
perform the same search.

This can also potentially leak private information, such as the number
of posts flagged, downvoted, or disapproved by a given user.

Partial fix for #4280.
2020-05-07 21:02:22 -05:00
evazion
41c6c882c2 search: refactor fast_count to return nil on timeout.
* Refactor fast_count to return nil instead of 1,000,000 if the exact count times out.
* Remove the estimate_post_counts and blank_tag_search_fast_count global config options.
* Replace the hardcoded post count estimates inside fast_count with a
  method that parses Postgres's estimated row count from EXPLAIN.

* /counts/posts.json:
** Remove the `raise_on_timeout` parameter.
** Add an `estimate_count=<true|false>` parameter.
** Return null instead of 1,000,000 if the exact count times out.
2020-05-07 21:02:22 -05:00
evazion
d3e4ac7c17 search: clean up safe_mode / hide_deleted_posts settings.
Change PostQueryBuilder to add rating:s and -status:deleted to the
search inside the constructor instead of inside `#build` and
`#fast_count`. This lets up clean up `#fast_count` so it doesn't have to
reparse the query after adding these tags. This caused aliases to be
evaluated more than once on the post index page.
2020-05-07 21:02:22 -05:00
evazion
67aab0236d search: apply aliases after parsing searches.
Make PostQueryBuilder apply aliases earlier, immediately after parsing
the search.

On the post index page there are multiple places where we need to apply
aliases:

* When running the search with PostQueryBuilder#build.
* When calculating the search count with PostQueryBuilder#fast_count.
* When calculating the related tags for the sidebar.
* When tracking missed searches and popular searches for Reportbooru.
* When looking up wiki excerpts.

Applying aliases after parsing ensures we only have to apply aliases
once for all of these things.

We also normalize the order of tags in searches and strip repeated tags.
This is so that we have consistent cache keys for fast_count.

* Fixes searches for aliased tags being counted as missed searches (fixes #4433).
* Fixes wiki excerpts not showing up when searching for aliased tags.
2020-05-07 13:53:35 -05:00