mirror of
https://github.com/ae-utbm/sith.git
synced 2025-07-11 12:29:24 +00:00
repair user merging tool (#498)
This commit is contained in:
@ -23,72 +23,114 @@
|
||||
#
|
||||
#
|
||||
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.generic.edit import FormView
|
||||
from django.views.generic import ListView
|
||||
from django.urls import reverse
|
||||
from ajax_select.fields import AutoCompleteSelectField
|
||||
from django import forms
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.generic import ListView
|
||||
from django.views.generic.edit import FormView
|
||||
|
||||
from ajax_select.fields import AutoCompleteSelectField
|
||||
|
||||
from core.models import User, OperationLog, SithFile
|
||||
from core.views import CanEditPropMixin
|
||||
from core.models import User, OperationLog
|
||||
from counter.models import Customer
|
||||
|
||||
from forum.models import ForumMessageMeta
|
||||
|
||||
|
||||
def merge_users(u1, u2):
|
||||
u1.nick_name = u1.nick_name or u2.nick_name
|
||||
u1.date_of_birth = u1.date_of_birth or u2.date_of_birth
|
||||
u1.home = u1.home or u2.home
|
||||
u1.sex = u1.sex or u2.sex
|
||||
u1.pronouns = u1.pronouns or u2.pronouns
|
||||
u1.tshirt_size = u1.tshirt_size or u2.tshirt_size
|
||||
u1.role = u1.role or u2.role
|
||||
u1.department = u1.department or u2.department
|
||||
u1.dpt_option = u1.dpt_option or u2.dpt_option
|
||||
u1.semester = u1.semester or u2.semester
|
||||
u1.quote = u1.quote or u2.quote
|
||||
u1.school = u1.school or u2.school
|
||||
u1.promo = u1.promo or u2.promo
|
||||
u1.forum_signature = u1.forum_signature or u2.forum_signature
|
||||
u1.second_email = u1.second_email or u2.second_email
|
||||
u1.phone = u1.phone or u2.phone
|
||||
u1.parent_phone = u1.parent_phone or u2.parent_phone
|
||||
u1.address = u1.address or u2.address
|
||||
u1.parent_address = u1.parent_address or u2.parent_address
|
||||
def __merge_subscriptions(u1: User, u2: User):
|
||||
"""
|
||||
Give all the subscriptions of the second user to first one
|
||||
If some subscriptions are still active, update their end date
|
||||
to increase the overall subscription time of the first user.
|
||||
|
||||
Some examples :
|
||||
- if u1 is not subscribed, his subscription end date become the one of u2
|
||||
- if u1 is subscribed but not u2, nothing happen
|
||||
- if u1 is subscribed for, let's say, 2 remaining months and u2 is subscribed for 3 remaining months,
|
||||
he shall then be subscribed for 5 months
|
||||
"""
|
||||
last_subscription = (
|
||||
u1.subscriptions.filter(
|
||||
subscription_start__lte=timezone.now(), subscription_end__gte=timezone.now()
|
||||
)
|
||||
.order_by("subscription_end")
|
||||
.last()
|
||||
)
|
||||
if last_subscription is not None:
|
||||
subscription_end = last_subscription.subscription_end
|
||||
for subscription in u2.subscriptions.filter(
|
||||
subscription_end__gte=timezone.now()
|
||||
):
|
||||
subscription.subscription_start = subscription_end
|
||||
if subscription.subscription_start > timezone.now().date():
|
||||
remaining = subscription.subscription_end - timezone.now().date()
|
||||
else:
|
||||
remaining = (
|
||||
subscription.subscription_end - subscription.subscription_start
|
||||
)
|
||||
subscription_end += remaining
|
||||
subscription.subscription_end = subscription_end
|
||||
subscription.save()
|
||||
u2.subscriptions.all().update(member=u1)
|
||||
|
||||
|
||||
def __merge_pictures(u1: User, u2: User) -> None:
|
||||
SithFile.objects.filter(owner=u2).update(owner=u1)
|
||||
if u1.profile_pict is None and u2.profile_pict is not None:
|
||||
u1.profile_pict, u2.profile_pict = u2.profile_pict, None
|
||||
if u1.scrub_pict is None and u2.scrub_pict is not None:
|
||||
u1.scrub_pict, u2.scrub_pict = u2.scrub_pict, None
|
||||
if u1.avatar_pict is None and u2.avatar_pict is not None:
|
||||
u1.avatar_pict, u2.avatar_pict = u2.avatar_pict, None
|
||||
u2.save()
|
||||
u1.save()
|
||||
for u in u2.godfathers.all():
|
||||
u1.godfathers.add(u)
|
||||
|
||||
|
||||
def merge_users(u1: User, u2: User) -> User:
|
||||
"""
|
||||
Merge u2 into u1
|
||||
This means that u1 shall receive everything that belonged to u2 :
|
||||
|
||||
- pictures
|
||||
- refills of the sith account
|
||||
- purchases of any item bought on the eboutic or the counters
|
||||
- subscriptions
|
||||
- godfathers
|
||||
- godchildren
|
||||
|
||||
If u1 had no account id, he shall receive the one of u2.
|
||||
If u1 and u2 were both in the middle of a subscription, the remaining
|
||||
durations stack
|
||||
If u1 had no profile picture, he shall receive the one of u2
|
||||
"""
|
||||
for field in u1._meta.fields:
|
||||
if not field.is_relation and not u1.__dict__[field.name]:
|
||||
u1.__dict__[field.name] = u2.__dict__[field.name]
|
||||
for group in u2.groups.all():
|
||||
u1.groups.add(group.id)
|
||||
for godfather in u2.godfathers.exclude(id=u1.id):
|
||||
u1.godfathers.add(godfather)
|
||||
for godchild in u2.godchildren.exclude(id=u1.id):
|
||||
u1.godchildren.add(godchild)
|
||||
__merge_subscriptions(u1, u2)
|
||||
__merge_pictures(u1, u2)
|
||||
u2.invoices.all().update(user=u1)
|
||||
c_src = Customer.objects.filter(user=u2).first()
|
||||
if c_src is not None:
|
||||
c_dest, created = Customer.get_or_create(u1)
|
||||
c_src.refillings.update(customer=c_dest)
|
||||
c_src.buyings.update(customer=c_dest)
|
||||
c_dest.recompute_amount()
|
||||
if created:
|
||||
# swap the account numbers, so that the user keep
|
||||
# the id he is accustomed to
|
||||
tmp_id = c_src.account_id
|
||||
# delete beforehand in order not to have a unique constraint violation
|
||||
c_src.delete()
|
||||
c_dest.account_id = tmp_id
|
||||
u1.save()
|
||||
for i in u2.invoices.all():
|
||||
for f in i._meta.local_fields: # I have sadly not found anything better :/
|
||||
if f.name == "date":
|
||||
f.auto_now = False
|
||||
u1.invoices.add(i)
|
||||
u1.save()
|
||||
s1 = User.objects.filter(id=u1.id).first()
|
||||
s2 = User.objects.filter(id=u2.id).first()
|
||||
for s in s2.subscriptions.all():
|
||||
s1.subscriptions.add(s)
|
||||
s1.save()
|
||||
c1 = Customer.objects.filter(user__id=u1.id).first()
|
||||
c2 = Customer.objects.filter(user__id=u2.id).first()
|
||||
if c1 and c2:
|
||||
for r in c2.refillings.all():
|
||||
c1.refillings.add(r)
|
||||
c1.save()
|
||||
for s in c2.buyings.all():
|
||||
c1.buyings.add(s)
|
||||
c1.save()
|
||||
elif c2 and not c1:
|
||||
c2.user = u1
|
||||
c1 = c2
|
||||
c1.save()
|
||||
c1.recompute_amount()
|
||||
u2.delete()
|
||||
u2.delete() # everything remaining in u2 gets deleted thanks to on_delete=CASCADE
|
||||
return u1
|
||||
|
||||
|
||||
@ -128,9 +170,8 @@ class MergeUsersView(FormView):
|
||||
form_class = MergeForm
|
||||
|
||||
def dispatch(self, request, *arg, **kwargs):
|
||||
res = super(MergeUsersView, self).dispatch(request, *arg, **kwargs)
|
||||
if request.user.is_root:
|
||||
return res
|
||||
return super().dispatch(request, *arg, **kwargs)
|
||||
raise PermissionDenied
|
||||
|
||||
def form_valid(self, form):
|
||||
@ -140,7 +181,7 @@ class MergeUsersView(FormView):
|
||||
return super(MergeUsersView, self).form_valid(form)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse("core:user_profile", kwargs={"user_id": self.final_user.id})
|
||||
return self.final_user.get_absolute_url()
|
||||
|
||||
|
||||
class DeleteAllForumUserMessagesView(FormView):
|
||||
|
Reference in New Issue
Block a user