From 75264858377e4b48078fcdd14806356157d4df6c Mon Sep 17 00:00:00 2001 From: FreneticScribbler Date: Fri, 21 Oct 2022 00:04:53 +0100 Subject: [PATCH] FEAT: Add periodic cleanup command Currently performs two functions: 1. Inactivates users that have not logged in for at least one year. Closes #478 (Need to circle back round to full deletion SoonTM) 2. Ensures the supervisor database flag is set correctly for each user This is run automatically by the Heroku Scheduler addon at midnight daily. --- .../0045_alter_profile_is_approved.py | 18 +++++++++++++ RIGS/models.py | 2 +- templates/form_errors.html | 7 +++-- templates/registration/loginform.html | 5 ++++ users/management/commands/usercleanup.py | 26 +++++++++++++++++++ 5 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 RIGS/migrations/0045_alter_profile_is_approved.py create mode 100644 users/management/commands/usercleanup.py diff --git a/RIGS/migrations/0045_alter_profile_is_approved.py b/RIGS/migrations/0045_alter_profile_is_approved.py new file mode 100644 index 00000000..1ef2ae1e --- /dev/null +++ b/RIGS/migrations/0045_alter_profile_is_approved.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.12 on 2022-10-20 23:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('RIGS', '0044_profile_is_supervisor'), + ] + + operations = [ + migrations.AlterField( + model_name='profile', + name='is_approved', + field=models.BooleanField(default=False, help_text='Designates whether a staff member has approved this user.', verbose_name='Approval Status'), + ), + ] diff --git a/RIGS/models.py b/RIGS/models.py index afb7c520..30fdecd8 100644 --- a/RIGS/models.py +++ b/RIGS/models.py @@ -36,7 +36,7 @@ class Profile(AbstractUser): initials = models.CharField(max_length=5, null=True, blank=False) phone = models.CharField(max_length=13, blank=True, default='') api_key = models.CharField(max_length=40, blank=True, editable=False, default='') - is_approved = models.BooleanField(default=False) + is_approved = models.BooleanField(default=False, verbose_name="Approval Status", help_text="Designates whether a staff member has approved this user.") # Currently only populated by the admin approval email. TODO: Populate it each time we send any email, might need that... last_emailed = models.DateTimeField(blank=True, null=True) dark_theme = models.BooleanField(default=False) diff --git a/templates/form_errors.html b/templates/form_errors.html index 5c945501..a8680703 100644 --- a/templates/form_errors.html +++ b/templates/form_errors.html @@ -1,13 +1,12 @@ {% load nice_errors from filters %} {% if form.errors %} -
- +
{% with form|nice_errors as qq %} {% for error_name,desc in qq.items %} -
{{error_name}}
-
{{desc}}
+
{{error_name}}
+
{{desc}}
{% endfor %} {% endwith %} diff --git a/templates/registration/loginform.html b/templates/registration/loginform.html index fe1ee44f..8a6c44c8 100644 --- a/templates/registration/loginform.html +++ b/templates/registration/loginform.html @@ -1,5 +1,10 @@ {% load widget_tweaks %} {% include 'form_errors.html' %} +{% if form.errors %} +
+

Please note: If it has been more than a year since you last logged in, your account will have been automatically deactivated. Contact it@nottinghamtec.co.uk for assistance.

+
+{% endif %}
{% csrf_token %}
diff --git a/users/management/commands/usercleanup.py b/users/management/commands/usercleanup.py new file mode 100644 index 00000000..5b538ce8 --- /dev/null +++ b/users/management/commands/usercleanup.py @@ -0,0 +1,26 @@ +from datetime import datetime, timedelta +from django.core.management.base import BaseCommand, CommandError +from django.utils import timezone + +from RIGS.models import Profile +from training.models import TrainingLevel + + +# This is triggered nightly by Heroku Scheduler +class Command(BaseCommand): + help = 'Performs perodic user maintenance tasks' + + def handle(self, *args, **options): + for person in Profile.objects.all(): + # Inactivate users that have not logged in for a year (or have never logged in) + if person.last_login is None or (timezone.now() - person.last_login).days > 365: + person.is_active = False + person.is_approved = False + person.save() + # Ensure everyone with a supervisor level has the flag correctly set in the database + if person.level_qualifications.exclude(confirmed_on=None).select_related('level') \ + .filter(level__level__gte=TrainingLevel.SUPERVISOR) \ + .exclude(level__department=TrainingLevel.HAULAGE) \ + .exclude(level__department__isnull=True).exists(): + person.is_supervisor = True + person.save()