When a dmail is hard deleted, update the user's unread dmail count and
delete any associated mod reports.
Dmails aren't normally hard deleted, except when there's a large spam
wave that necessitates manual intervention.
Bug: if `hatsune_miku` is an empty general tag, then tagging a post with
`hatsune_miku_(cosplay)` would fail because `hatsune_miku` wasn't a
character tag. This could cause tagging posts to fail when aliasing a
character tag back to an old name that was used in the past, but was now
an empty general tag.
Fix: only treat the *_(cosplay) tag as being in conflict with the base
tag when the base tag is nonempty.
* Add a `rename A -> B` command for bulk update requests.
* Change mass updates to only retag the posts, not to move saved
searches or blacklists.
A tag rename does the same thing an alias does, except it doesn't
create a permanent alias. More precisely, a tag rename:
* Moves the wiki.
* Moves the artist entry.
* Moves saved searches.
* Moves blacklists.
* Merges the wikis, if both tags have wiki pages.
* Merges the artist entries, if both tags have artist pages.
* Fixes links in wiki pages to point to the new tag.
* Retags the posts.
When aliasing A to B, update any wikis linking to [[A]] to link to [[B]]
instead.
This is a best-effort process based on rough heuristics. There are a few
known problems:
* We don't always know how to capitalize the new tag. We try to mimic
the capitalization of the old tag, such that if the old tag was
capitalized (because it was at the beginning of a sentence), or if
every word in the old link was capitalized (because it's a proper
noun), then the new link will be capitalized in the same way. This can
handle simple general tags and character tags, but will fail for
copyright tags with mixed capitalization. For example, we don't know
that [[jojo_no_kimyou_na_bouken]] should be capitalized as [[JoJo no
Kimyou na Bouken]]. If we don't know how to capitalize the new tag, we
leave the old tag as-is so it can manually be fixed.
* Some aliases might require changing how a tag is pluralized. If we
changed [[rat]] to [[mouse]], then we should change `[[rat]]s` to
[[mice]]. We don't try to deal with this.
* In general, some changes might require entire sentences to be
rewritten to keep the grammar correct. Changing something like
[[skirt lift]] to [[lifting skirt]] could break the grammar of the
sentence. We don't try to deal with this.
* Factor out the code for moving tags from tag aliases to a separate
TagMover class.
* When aliasing two tags that have conflicting wikis, merge the old wiki
into the new one instead of failing with an error. Merge the other names
fields, replace the old wiki body with a message linking to the new
wiki, and mark the old wiki as deleted.
* When aliasing two tags that have conflicting artist entries, merge the
old artist into the new one instead of silently ignore the conflict.
Merge the group name, other names, and urls fields, and mark the old
artist as deleted.
* When two tags have conflicting wikis or artist entries, but the old
wiki or artist entry is deleted, then just ignore the old wiki or
artist and don't try to merge it.
* Fix it so that when saved searches are rewritten, we rewrite negated
searches too.
Remove the following alternate forms of commands:
* aliasing A -> B
* unaliasing A -> B
* implicating A -> B
* implicate A -> B
* unimplicating A -> B
* unimplicate A -> B
* updating A -> B
* change A -> B
The following forms are accepted:
* create alias A -> B
* alias A -> B
* create implication A -> B
* imply A -> B
* remove alias A -> B
* unalias A -> B
* remove implication A -> B
* unimply A -> B
* update A -> B
Only downcase tags in aliases, implications, and category change
commands. Don't downcase mass update commands. Mass updates are
potentially case sensitive (for example: `mass update source:imageboard -> source:Imageboard`).
* Don't raise exceptions when a BUR is invalid. Instead, use Rails
validations to return errors. Fixes invalid BURs potentially raising
exceptions in views. Also makes it so that each error in a BUR is
reported, not just the first one.
* Revalidate the BUR whenever the script is edited, not just when the
BUR is created. Ensures the BUR can't be broken by editing. Fixes a bug
where forum threads could be broken by someone editing a BUR and
breaking the syntax, thereby causing the BUR to raise an unparseable
script error when the forum thread was viewed.
* Validate that removed aliases and implication actually exist.
* Validate that the tag actually exists when changing a tag's category.
* Combine bulk update request processor unit tests with main bulk update
request unit tests.
Prevent age-restricted fanbox posts from raising errors when source data
is fetched. This prevents error messages from being shown to users when
switching to the edit tab on a post.
This will cause uploads of age-restricted posts to fail with an
unrelated error because we either can't find the image url (if we were
given only the html page) or we can't download the image (because we're
not logged in to Fanbox).
Move html_data_attributes definitions from models to policies. Which
attributes are permitted as data-* attributes is a view level concern
and should be defined on the policy level, not the model level. Models
should be agnostic about how they're used in views.
* Add index on posts.is_deleted. The modqueue was slow because we the
appeal condition wasn't constrained to deleted posts, so it degraded to
a full table scan.
* Avoid extra queries for calculating the page count and disapproval counts.
* Only show the current pending flag on flagged posts. Don't show old flags.
* Don't show both the "This post was flagged for review" and the "This
post was flagged and is pending" notices.
* Only show the current pending appeal in the "This post was appealed"
notice. Don't show old appeals.
* Don't show both the "This post was deleted" and the "This post was
appealed" notice on appealed posts. Only show the "This post was
appealed" notice.
* Show "no reason" if no appeal reason was given.