Sith/rootplace/views.py

223 lines
7.7 KiB
Python
Raw Normal View History

#
# Copyright 2016,2017
# - Skia <skia@libskia.so>
2017-08-17 18:55:20 +00:00
# - Sli <antoine@bartuccio.fr>
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License a published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
2024-08-06 09:42:10 +00:00
import logging
2023-03-04 14:01:08 +00:00
from ajax_select.fields import AutoCompleteSelectField
2016-09-21 12:09:16 +00:00
from django import forms
from django.core.exceptions import PermissionDenied
2023-03-04 14:01:08 +00:00
from django.urls import reverse
from django.utils import timezone
2024-10-02 22:21:16 +00:00
from django.utils.timezone import localdate
2023-03-04 14:01:08 +00:00
from django.utils.translation import gettext as _
from django.views.generic import ListView
from django.views.generic.edit import FormView
2016-09-21 12:09:16 +00:00
2024-06-24 11:07:36 +00:00
from core.models import OperationLog, SithFile, User
from core.views import CanEditPropMixin
2016-09-21 12:09:16 +00:00
from counter.models import Customer
from forum.models import ForumMessageMeta
2017-08-17 18:55:20 +00:00
2016-09-21 12:09:16 +00:00
2023-03-04 14:01:08 +00:00
def __merge_subscriptions(u1: User, u2: User):
2024-07-12 07:34:16 +00:00
"""Give all the subscriptions of the second user to first one.
2023-03-04 14:01:08 +00:00
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
2024-10-02 22:21:16 +00:00
if subscription.subscription_start > localdate():
remaining = subscription.subscription_end - localdate()
2023-03-04 14:01:08 +00:00
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()
2016-09-21 12:09:16 +00:00
u1.save()
2023-03-04 14:01:08 +00:00
def merge_users(u1: User, u2: User) -> User:
2024-07-12 07:34:16 +00:00
"""Merge u2 into u1.
2023-03-04 14:01:08 +00:00
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
2016-09-21 12:09:16 +00:00
u1.save()
2023-03-04 14:01:08 +00:00
u2.delete() # everything remaining in u2 gets deleted thanks to on_delete=CASCADE
2016-09-21 12:09:16 +00:00
return u1
2017-08-17 18:55:20 +00:00
def delete_all_forum_user_messages(
user: User, moderator: User, *, verbose: bool = False
):
2024-07-12 07:34:16 +00:00
"""Soft delete all messages of a user.
Args:
user: core.models.User the user to delete messages from
moderator: core.models.User the one marked as the moderator.
verbose: bool if True, print the deleted messages
"""
for message in user.forum_messages.all():
if message.is_deleted():
continue
if verbose:
2024-08-06 09:42:10 +00:00
logging.getLogger("django").info(message)
ForumMessageMeta(message=message, user=moderator, action="DELETE").save()
2016-09-21 12:09:16 +00:00
class MergeForm(forms.Form):
2018-10-04 19:29:19 +00:00
user1 = AutoCompleteSelectField(
"users", label=_("User that will be kept"), help_text=None, required=True
)
user2 = AutoCompleteSelectField(
"users", label=_("User that will be deleted"), help_text=None, required=True
)
2016-09-21 12:09:16 +00:00
2017-08-17 18:55:20 +00:00
class SelectUserForm(forms.Form):
user = AutoCompleteSelectField(
"users", label=_("User to be selected"), help_text=None, required=True
)
2016-09-21 12:09:16 +00:00
class MergeUsersView(FormView):
template_name = "rootplace/merge.jinja"
form_class = MergeForm
def dispatch(self, request, *arg, **kwargs):
if request.user.is_root:
2023-03-04 14:01:08 +00:00
return super().dispatch(request, *arg, **kwargs)
2016-09-21 12:09:16 +00:00
raise PermissionDenied
def form_valid(self, form):
2018-10-04 19:29:19 +00:00
self.final_user = merge_users(
form.cleaned_data["user1"], form.cleaned_data["user2"]
)
2024-06-27 12:46:43 +00:00
return super().form_valid(form)
2016-09-21 12:09:16 +00:00
def get_success_url(self):
2023-03-04 14:01:08 +00:00
return self.final_user.get_absolute_url()
class DeleteAllForumUserMessagesView(FormView):
2024-07-12 07:34:16 +00:00
"""Delete all forum messages from an user.
2020-08-27 13:59:42 +00:00
Messages are soft deleted and are still visible from admins
2024-07-12 07:34:16 +00:00
GUI frontend to the dedicated command.
"""
template_name = "rootplace/delete_user_messages.jinja"
form_class = SelectUserForm
def dispatch(self, request, *args, **kwargs):
2024-06-27 12:46:43 +00:00
res = super().dispatch(request, *args, **kwargs)
if request.user.is_root:
return res
raise PermissionDenied
def form_valid(self, form):
self.user = form.cleaned_data["user"]
delete_all_forum_user_messages(self.user, self.request.user)
2024-06-27 12:46:43 +00:00
return super().form_valid(form)
def get_success_url(self):
return reverse("core:user_profile", kwargs={"user_id": self.user.id})
class OperationLogListView(ListView, CanEditPropMixin):
2024-07-12 07:34:16 +00:00
"""List all logs."""
model = OperationLog
template_name = "rootplace/logs.jinja"
ordering = ["-date"]
paginate_by = 100