mirror of
https://github.com/narrrl/holy-flavor-rater.git
synced 2026-11-03 16:41:27 +01:00
55 lines
2.3 KiB
Python
55 lines
2.3 KiB
Python
from django.db import transaction
|
|
|
|
from api.models import Flavor, Notification, Rating, Reply
|
|
|
|
|
|
def _quality(rating: Rating) -> tuple[int, object]:
|
|
"""Rank a rating for conflict resolution: longest comment wins, newer breaks ties."""
|
|
return (len(rating.comment or ""), rating.created_at)
|
|
|
|
|
|
def merge_flavors(keep_flavor: Flavor, remove_flavor: Flavor) -> None:
|
|
"""
|
|
Merges remove_flavor into keep_flavor.
|
|
|
|
Re-assigns all ratings. When a user rated both flavors, the higher-quality
|
|
review survives (longest comment, newer on ties) and its replies +
|
|
notifications are re-pointed to the surviving row.
|
|
"""
|
|
if keep_flavor.id == remove_flavor.id:
|
|
return
|
|
|
|
with transaction.atomic():
|
|
for incoming in Rating.objects.filter(flavor=remove_flavor):
|
|
existing = Rating.objects.filter(user=incoming.user, flavor=keep_flavor).first()
|
|
|
|
if existing is None:
|
|
# No conflict — move the rating wholesale.
|
|
incoming.flavor = keep_flavor
|
|
incoming.save(update_fields=["flavor"])
|
|
continue
|
|
|
|
# Conflict: keep one row (unique_together user+flavor). If the
|
|
# incoming review is better, copy its content + timestamp onto the
|
|
# surviving row so the comment and its date stay consistent.
|
|
if _quality(incoming) > _quality(existing):
|
|
existing.score = incoming.score
|
|
existing.comment = incoming.comment
|
|
existing.created_at = incoming.created_at # auto_now_add ignores updates
|
|
existing.save(update_fields=["score", "comment", "created_at"])
|
|
|
|
# Preserve community feedback attached to the discarded rating.
|
|
Reply.objects.filter(rating=incoming).update(rating=existing)
|
|
Notification.objects.filter(rating=incoming).update(rating=existing)
|
|
incoming.delete()
|
|
|
|
# Carry over the Shopify link if the kept flavor lacks one. external_id
|
|
# is unique, so the donor row must be gone before we assign it.
|
|
inherited_external_id = remove_flavor.external_id if not keep_flavor.external_id else None
|
|
|
|
remove_flavor.delete()
|
|
|
|
if inherited_external_id is not None:
|
|
keep_flavor.external_id = inherited_external_id
|
|
keep_flavor.save(update_fields=["external_id"])
|