Explorar el Código

feat(api): delete users with expired activation links every 5min

Peter Thomassen hace 5 años
padre
commit
15ed5ecbbf

+ 1 - 1
api/cronhook/crontab

@@ -1,2 +1,2 @@
-55 2 * * * /usr/local/bin/python3 -u /usr/src/app/manage.py chores >> /var/log/cron.log 2>&1
+*/5 * * * * /usr/local/bin/python3 -u /usr/src/app/manage.py chores >> /var/log/cron.log 2>&1
 */5 * * * * /usr/local/bin/python3 -u /usr/src/app/manage.py check-slaves >> /var/log/cron.log 2>&1

+ 6 - 1
api/desecapi/management/commands/chores.py

@@ -2,7 +2,7 @@ from django.conf import settings
 from django.core.management import BaseCommand
 from django.utils import timezone
 
-from desecapi.models import Captcha
+from desecapi.models import Captcha, User
 
 
 class Command(BaseCommand):
@@ -10,3 +10,8 @@ class Command(BaseCommand):
     def handle(self, *args, **kwargs):
         # delete expired captchas
         Captcha.objects.filter(created__lt=timezone.now() - settings.CAPTCHA_VALIDITY_PERIOD).delete()
+
+        # delete inactive users whose activation link expired and who never logged in
+        # (this will not delete users who have used their account and were later disabled)
+        User.objects.filter(is_active=False, last_login__exact=None,
+                            created__lt=timezone.now() - settings.VALIDITY_PERIOD_VERIFICATION_SIGNATURE).delete()

+ 2 - 0
api/desecapi/templates/emails/activate-with-domain/content.txt

@@ -11,5 +11,7 @@ hours):
 
 After that, please follow the instructions on the confirmation page.
 
+If link has already expired, please register again.
+
 Stay secure,
 Nils

+ 27 - 1
api/desecapi/tests/test_chores.py

@@ -5,7 +5,7 @@ from django.core import management
 from django.test import override_settings, TestCase
 from django.utils import timezone
 
-from desecapi.models import Captcha
+from desecapi.models import Captcha, User
 
 
 class ChoresCommandTest(TestCase):
@@ -20,3 +20,29 @@ class ChoresCommandTest(TestCase):
 
         management.call_command('chores')
         self.assertEqual(list(Captcha.objects.all()), [captcha2])
+
+    @override_settings(VALIDITY_PERIOD_VERIFICATION_SIGNATURE=timezone.timedelta(hours=1))
+    def test_inactive_user_cleanup(self):
+        def create_users(kind):
+            logintime = timezone.now() + timezone.timedelta(seconds=5)
+            kwargs_list = [
+                dict(email=f'user1+{kind}@example.com', is_active=False, last_login=None),
+                dict(email=f'user2+{kind}@example.com', is_active=True, last_login=None),
+                dict(email=f'user3+{kind}@example.com', is_active=False, last_login=logintime),
+                dict(email=f'user4+{kind}@example.com', is_active=True, last_login=logintime),
+            ]
+            return (User.objects.create(**kwargs) for kwargs in kwargs_list)
+
+        # Old users
+        faketime = timezone.now() - settings.VALIDITY_PERIOD_VERIFICATION_SIGNATURE - timezone.timedelta(seconds=1)
+        with mock.patch('django.db.models.fields.timezone.now', return_value=faketime):
+            expired_user, _, _, _ = create_users('old')
+
+        # New users
+        create_users('new')
+
+        all_users = set(User.objects.all())
+
+        management.call_command('chores')
+        # Check that only the expired user was deleted
+        self.assertEqual(all_users - set(User.objects.all()), {expired_user})