mirror of https://github.com/zulip/zulip.git
reaction: Fix missing unique constraint on Reactions model.
This fixes a missing unique constraint on the Reactions data model state when using multiple aliases for an emoji code. As with any missing unique constraints, we first need to apply a migration that eliminates violations of the rule; in this case, deleting the duplicates is correct. Added unique constraint for "user_profile", "message", "reaction_type", "emoji_code". Fixes #15347.
This commit is contained in:
parent
7c6ddf90ae
commit
c7d0192755
|
@ -0,0 +1,35 @@
|
|||
from django.db import migrations
|
||||
from django.db.backends.postgresql.schema import DatabaseSchemaEditor
|
||||
from django.db.migrations.state import StateApps
|
||||
from django.db.models import Count
|
||||
|
||||
|
||||
def clear_duplicate_reactions(apps: StateApps, schema_editor: DatabaseSchemaEditor) -> None:
|
||||
"""Zulip's data model for reactions has enforced via code,
|
||||
nontransactionally, that they can only react with one emoji_code
|
||||
for a given reaction_type. This fixes any that were stored in the
|
||||
database via a race; the next migration will add the appropriate
|
||||
database-level unique constraint.
|
||||
"""
|
||||
Reaction = apps.get_model('zerver', 'Reaction')
|
||||
|
||||
duplicate_reactions = Reaction.objects.all().values(
|
||||
"user_profile_id", "message_id", "reaction_type", "emoji_code").annotate(
|
||||
Count('id')).filter(id__count__gt=1)
|
||||
for duplicate_reaction in duplicate_reactions:
|
||||
duplicate_reaction.pop('id__count')
|
||||
to_cleanup = Reaction.objects.filter(**duplicate_reaction)[1:]
|
||||
for reaction in to_cleanup:
|
||||
reaction.delete()
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('zerver', '0286_merge_0260_0285'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(clear_duplicate_reactions,
|
||||
reverse_code=migrations.RunPython.noop,
|
||||
elidable=True),
|
||||
]
|
|
@ -0,0 +1,21 @@
|
|||
# Generated by Django 2.2.13 on 2020-06-19 08:16
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('zerver', '0287_clear_duplicate_reactions'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterUniqueTogether(
|
||||
name='archivedreaction',
|
||||
unique_together={('user_profile', 'message', 'emoji_name'), ('user_profile', 'message', 'reaction_type', 'emoji_code')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='reaction',
|
||||
unique_together={('user_profile', 'message', 'emoji_name'), ('user_profile', 'message', 'reaction_type', 'emoji_code')},
|
||||
),
|
||||
]
|
|
@ -1893,7 +1893,8 @@ class AbstractReaction(models.Model):
|
|||
|
||||
class Meta:
|
||||
abstract = True
|
||||
unique_together = ("user_profile", "message", "emoji_name")
|
||||
unique_together = (("user_profile", "message", "emoji_name"),
|
||||
("user_profile", "message", "reaction_type", "emoji_code"))
|
||||
|
||||
class Reaction(AbstractReaction):
|
||||
message: Message = models.ForeignKey(Message, on_delete=CASCADE)
|
||||
|
|
Loading…
Reference in New Issue