From 9a606c7dd2a317b0c521f459f930a517b2570bcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Z=C3=A1rate=20Montero?= Date: Sat, 18 May 2024 17:56:27 -0600 Subject: [PATCH] Add check_remove_user_notlogin as WIP --- .../commands/check_remove_user_notlogin.py | 61 +++++++++++++ .../migrations/0014_create_user_default.py | 11 ++- .../migrations/0017_merge_20240518_1359.py | 14 +++ .../migrations/0018_deleteuserlist.py | 26 ++++++ src/auth_and_perms/models.py | 9 ++ .../mail/en/user_delete_notification.html | 22 +++++ .../mail/en/user_merge_notification.html | 15 ++++ .../mail/es/user_delete_notification.html | 7 ++ .../mail/es/user_merge_notification.html | 5 ++ .../user_management_notification.html | 18 +--- src/auth_and_perms/users.py | 86 +++++++++++++++++++ src/auth_and_perms/utils.py | 26 ------ src/auth_and_perms/views/users.py | 2 +- 13 files changed, 256 insertions(+), 46 deletions(-) create mode 100644 src/auth_and_perms/management/commands/check_remove_user_notlogin.py create mode 100644 src/auth_and_perms/migrations/0017_merge_20240518_1359.py create mode 100644 src/auth_and_perms/migrations/0018_deleteuserlist.py create mode 100644 src/auth_and_perms/templates/auth_and_perms/mail/en/user_delete_notification.html create mode 100644 src/auth_and_perms/templates/auth_and_perms/mail/en/user_merge_notification.html create mode 100644 src/auth_and_perms/templates/auth_and_perms/mail/es/user_delete_notification.html create mode 100644 src/auth_and_perms/templates/auth_and_perms/mail/es/user_merge_notification.html create mode 100644 src/auth_and_perms/users.py diff --git a/src/auth_and_perms/management/commands/check_remove_user_notlogin.py b/src/auth_and_perms/management/commands/check_remove_user_notlogin.py new file mode 100644 index 00000000..b0fb68b4 --- /dev/null +++ b/src/auth_and_perms/management/commands/check_remove_user_notlogin.py @@ -0,0 +1,61 @@ +from django.conf import settings +from django.core.management import BaseCommand +from django.contrib.auth import get_user_model +from dateutil.relativedelta import relativedelta +from django.utils.timezone import now +from django.contrib.sites.models import Site +from django.test import RequestFactory + +from auth_and_perms.models import DeleteUserList +from auth_and_perms.users import delete_user +from auth_and_perms.users import send_email_user_management + + +class Command(BaseCommand): + + def enqueue_users(self): + User=get_user_model() + User.objects.all() + year_ago = now() + relativedelta(years=1) + deletelist = [] + for user in User.objects.exclude(username="soporte@organilab.org").filter( + deleteuserlist__isnull=True, + last_login__lte=year_ago): + deletelist.append(DeleteUserList(user=user)) + if deletelist: + DeleteUserList.objects.bulk_create(deletelist) + + print("Actual: ", User.objects.all().count()) + print("Remove: ", len(deletelist)) + + def get_now(self): + # fixme: remove this and put now() only + return now() #+ relativedelta(months=1, days=1) + + def delete_users(self): + User = get_user_model() + site = Site.objects.all().last() + if site.domain not in settings.ALLOWED_HOSTS: + settings.ALLOWED_HOSTS.append(site.domain) + request = RequestFactory().get('/') + + request.META['HTTP_HOST']=site.domain + request.META['SERVER_PORT']="80" if settings.DEBUG else "443" + user_base=User.objects.filter(username="soporte@organilab.org").first() + del_count=0 + for user_delete in DeleteUserList.objects.filter(expiration_date__lte=self.get_now()): + send_email_user_management(request, user_base, user_delete, "delete") + print(user_delete.user.username) + delete_user(user_delete.user, user_base) + user_delete.delete() + del_count+=1 + print("Delete users", del_count) + print("Actual to users delete ", DeleteUserList.objects.all().count()) + print("Actual to users ", User.objects.all().count()) + + def handle(self, *args, **options) : + self.enqueue_users() + self.delete_users() + + + diff --git a/src/auth_and_perms/migrations/0014_create_user_default.py b/src/auth_and_perms/migrations/0014_create_user_default.py index 12148fa9..693bbe7f 100644 --- a/src/auth_and_perms/migrations/0014_create_user_default.py +++ b/src/auth_and_perms/migrations/0014_create_user_default.py @@ -4,9 +4,16 @@ def create_user_default(apps, schema_editor): User = apps.get_model('auth', 'User') - User.objects.create(username="soporte@organilab.org", email="soporte@organilab.org", + Profile = apps.get_model('auth_and_perms', 'Profile') + user=User.objects.create(username="soporte@organilab.org", email="soporte@organilab.org", first_name="Usuario preservador de integridad") - + Profile.objects.create( + user = user, + phone_number = "8888888", + id_card = "888888", + job_position = "Integrity", + language = 'es' + ) def delete_user_default(apps, schema_editor): User = apps.get_model('auth', 'User') User.objects.filter(username="soporte@organilab.org").delete() diff --git a/src/auth_and_perms/migrations/0017_merge_20240518_1359.py b/src/auth_and_perms/migrations/0017_merge_20240518_1359.py new file mode 100644 index 00000000..31f23821 --- /dev/null +++ b/src/auth_and_perms/migrations/0017_merge_20240518_1359.py @@ -0,0 +1,14 @@ +# Generated by Django 4.1.10 on 2024-05-18 19:59 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth_and_perms', '0014_create_user_default'), + ('auth_and_perms', '0016_addpermissiontoadmingroup'), + ] + + operations = [ + ] diff --git a/src/auth_and_perms/migrations/0018_deleteuserlist.py b/src/auth_and_perms/migrations/0018_deleteuserlist.py new file mode 100644 index 00000000..f16796de --- /dev/null +++ b/src/auth_and_perms/migrations/0018_deleteuserlist.py @@ -0,0 +1,26 @@ +# Generated by Django 4.1.10 on 2024-05-18 19:59 + +import auth_and_perms.models +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('auth_and_perms', '0017_merge_20240518_1359'), + ] + + operations = [ + migrations.CreateModel( + name='DeleteUserList', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('creation_date', models.DateTimeField(auto_now=True)), + ('expiration_date', models.DateTimeField(default=auth_and_perms.models.user_expiration_date)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/src/auth_and_perms/models.py b/src/auth_and_perms/models.py index 06245a65..8c7e8b17 100644 --- a/src/auth_and_perms/models.py +++ b/src/auth_and_perms/models.py @@ -1,6 +1,7 @@ import random import uuid +from dateutil.relativedelta import relativedelta from django.conf import settings from django.contrib.auth import get_user_model from django.contrib.auth.models import Permission, User @@ -8,6 +9,7 @@ from django.contrib.contenttypes.models import ContentType from django.core.validators import RegexValidator from django.db import models +from django.utils.timezone import now from django.utils.translation import gettext_lazy as _ from django_otp.plugins.otp_totp.models import TOTPDevice @@ -133,6 +135,13 @@ class AuthorizedApplication(models.Model): notification_url = models.URLField() token = models.TextField() +def user_expiration_date(): + return now()+relativedelta(months=1) + +class DeleteUserList(models.Model): + user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE) + creation_date = models.DateTimeField(auto_now=True) + expiration_date = models.DateTimeField(default=user_expiration_date) class ImpostorLog(models.Model): impostor = models.ForeignKey( diff --git a/src/auth_and_perms/templates/auth_and_perms/mail/en/user_delete_notification.html b/src/auth_and_perms/templates/auth_and_perms/mail/en/user_delete_notification.html new file mode 100644 index 00000000..88ac52e4 --- /dev/null +++ b/src/auth_and_perms/templates/auth_and_perms/mail/en/user_delete_notification.html @@ -0,0 +1,22 @@ +{% extends 'gentelella/registration/email_base.html' %} +{% load i18n %} +{% block content %} +{% trans 'Dear' %} {{user_delete.get_full_name}}, +

+ {% trans 'We would like to inform you that the user' %} {{user_delete.username}} {% trans 'was deleted. The reasons for this delete are as follows:' %} +

+ 1) {% trans 'Account inactive for a long time.' %} +
+ 2) {% trans 'System purification.' %} +

+ {% trans 'This measure has been taken to optimize our resources, ensure more efficient management, and enhance the security of our services.' %} + {% endif %} +

+ {% trans 'If you have any questions or require further assistance, please do not hesitate to contact our support team. We will be glad to assist you.' %} +

+ {% trans 'Sincerely,' %} +

+ Organilab +

+ +{% endblock %} diff --git a/src/auth_and_perms/templates/auth_and_perms/mail/en/user_merge_notification.html b/src/auth_and_perms/templates/auth_and_perms/mail/en/user_merge_notification.html new file mode 100644 index 00000000..3efcc90b --- /dev/null +++ b/src/auth_and_perms/templates/auth_and_perms/mail/en/user_merge_notification.html @@ -0,0 +1,15 @@ +{% extends 'gentelella/registration/email_base.html' %} +{% load i18n %} +{% block content %} +{% trans 'Dear' %} {{user_base.get_full_name}}, +

+ {% trans 'We would like to inform you that an update has been made to your account information. The reason for this update is as follows:' %} +

+ {% trans 'Account consolidation by an administrator: An administrator from your organization has decided to consolidate the accounts that belong to you in order to centralize access. This action aims to simplify account management and provide you with a smoother experience when accessing our resources.' %} +

+ {% trans 'From now on, you can log in to your account using the following username:' %} {{user_base.username}} +

+ {% trans 'If you do not remember your password, you can use the following link to recover it:' %} {% trans 'Click here' %} +

+ {% trans 'We appreciate your understanding and cooperation during this account update process. We value your trust in our services and strive to provide you with an optimal experience.' %} +{% endblock content %} diff --git a/src/auth_and_perms/templates/auth_and_perms/mail/es/user_delete_notification.html b/src/auth_and_perms/templates/auth_and_perms/mail/es/user_delete_notification.html new file mode 100644 index 00000000..64379ce2 --- /dev/null +++ b/src/auth_and_perms/templates/auth_and_perms/mail/es/user_delete_notification.html @@ -0,0 +1,7 @@ +{% extends 'gentelella/registration/email_base.html' %} +{% load i18n %} +{% block content %} +Esto es un adiĆ³s {{user}}. + +No olvides apoyar a Organilab. +{% endblock %} diff --git a/src/auth_and_perms/templates/auth_and_perms/mail/es/user_merge_notification.html b/src/auth_and_perms/templates/auth_and_perms/mail/es/user_merge_notification.html new file mode 100644 index 00000000..c65484e1 --- /dev/null +++ b/src/auth_and_perms/templates/auth_and_perms/mail/es/user_merge_notification.html @@ -0,0 +1,5 @@ +{% extends 'gentelella/registration/email_base.html' %} +{% load i18n %} +{% block content %} +Su usuario ha sido mezclado. +{% endblock %} diff --git a/src/auth_and_perms/templates/auth_and_perms/user_management_notification.html b/src/auth_and_perms/templates/auth_and_perms/user_management_notification.html index 8fb2a65f..ac033e32 100644 --- a/src/auth_and_perms/templates/auth_and_perms/user_management_notification.html +++ b/src/auth_and_perms/templates/auth_and_perms/user_management_notification.html @@ -15,21 +15,5 @@

{% trans 'We appreciate your understanding and cooperation during this account update process. We value your trust in our services and strive to provide you with an optimal experience.' %} {% else %} - {% trans 'Dear' %} {{user_delete.get_full_name}}, -

- {% trans 'We would like to inform you that the user' %} {{user_delete.username}} {% trans 'was deleted. The reasons for this delete are as follows:' %} -

- 1) {% trans 'Account inactive for a long time.' %} -
- 2) {% trans 'System purification.' %} -

- {% trans 'This measure has been taken to optimize our resources, ensure more efficient management, and enhance the security of our services.' %} - {% endif %} -

- {% trans 'If you have any questions or require further assistance, please do not hesitate to contact our support team. We will be glad to assist you.' %} -

- {% trans 'Sincerely,' %} -

- Organilab -

+ {% endblock %} diff --git a/src/auth_and_perms/users.py b/src/auth_and_perms/users.py new file mode 100644 index 00000000..c1cd2ccf --- /dev/null +++ b/src/auth_and_perms/users.py @@ -0,0 +1,86 @@ +from django.utils.translation import gettext_lazy as _ +from django.conf import settings +from django.core.mail import send_mail +from django.template.loader import render_to_string +from django.db.models.fields.related import ManyToOneRel +from django.utils.translation import activate, get_language + +def send_email_user_management(request, user_base, user_delete, action): + schema = request.scheme + "://" + if hasattr(user_base, 'profile'): + lang = user_base.profile.language + oldlang = get_language() + context = { + 'user_base': user_base, + 'user_delete': user_delete, + 'domain': schema + request.get_host(), + 'action': action + } + activate(lang) + send_mail(subject=_( + "Account Update: Merger with Another Account.") if action == "merge" else _( + "Account Delete"), + message=_("Please use a html reader client"), + recipient_list=[user_base.email], + from_email=settings.DEFAULT_FROM_EMAIL, + html_message=render_to_string( + 'auth_and_perms/mail/'+lang+'/user_merge_notification.html', + context=context + ) + ) + activate(oldlang) + + +def send_delete_user_email(user_delete): + if hasattr(user_delete, 'profile'): + lang = user_delete.profile.language + oldlang = get_language() + context={'lang': lang, + 'user': user_delete} + activate(lang) + send_mail(subject=_("Thanks for be part of Organilab, we will miss you."), + message=_("Your account was removed"), + recipient_list=[user_delete.email], + from_email=settings.DEFAULT_FROM_EMAIL, + html_message=render_to_string( + "auth_and_perms/mail/"+lang+"/user_delete_notification.html", + context=context + ) + ) + activate(oldlang) + +def merge_information_user(to_delete, to_related): + for field in to_delete._meta.get_fields(): + if field.name == 'sga_substance': + print(field) + if field.name in ['user_permissions', 'groups', 'profile', 'usertotpdevice', + 'registrationuser', 'authorizedapplication', 'deleteuserlist', + 'auth_token', 'chunked_uploads', 'totpdevice']: + continue + if isinstance(field, ManyToOneRel): + #print(field.name,field.target_field.model, field.field.name) + field.target_field.model.objects.filter(**{field.field.name: to_delete}).update( + **{field.field.name: to_related} + ) + if hasattr(to_delete, 'profile') and hasattr(to_related, 'profile'): + del_profile=to_delete.profile + merge_profile = to_related.profile + for field in del_profile._meta.get_fields(): + if field.name in ['profilepermission']: + continue + if isinstance(field, ManyToOneRel): + field.target_field.model.objects.filter( + **{field.field.name: del_profile}).update( + **{field.field.name: merge_profile} + ) + + +def delete_user(to_delete, to_related): + merge_information_user(to_delete, to_related) + send_delete_user_email(to_delete) + print("Deleting:", to_delete.username) + print(to_delete.delete()) + +def user_management(request, user_base, user_delete, action): + send_email_user_management(request, user_base, user_delete, action) + delete_user(user_delete, user_base) diff --git a/src/auth_and_perms/utils.py b/src/auth_and_perms/utils.py index 46b8b6f1..2a98d99f 100644 --- a/src/auth_and_perms/utils.py +++ b/src/auth_and_perms/utils.py @@ -65,32 +65,6 @@ def send_email(request, user): ) -def send_email_user_management(request, user_base, user_delete, action): - schema = request.scheme + "://" - - context = { - 'user_base': user_base, - 'user_delete': user_delete, - 'domain': schema + request.get_host(), - 'action': action - } - send_mail(subject=_( - "Account Update: Merger with Another Account.") if action == "merge" else _( - "Account Delete"), - message="Por favor use un visor de html", - recipient_list=[user_base.email], - from_email=settings.DEFAULT_FROM_EMAIL, - html_message=render_to_string( - 'auth_and_perms/user_management_notification.html', - context=context - ) - ) - - -def user_management(request, user_base, user_delete, action): - send_email_user_management(request, user_base, user_delete, action) - user_delete.delete() - def get_ip_address(request): """ diff --git a/src/auth_and_perms/views/users.py b/src/auth_and_perms/views/users.py index b97bb55c..e140fd66 100644 --- a/src/auth_and_perms/views/users.py +++ b/src/auth_and_perms/views/users.py @@ -5,7 +5,7 @@ from django.utils.translation import gettext_lazy as _ from auth_and_perms.forms import MergeUsers, UserForm -from auth_and_perms.utils import user_management +from auth_and_perms.users import user_management def users_list(request):