-
Notifications
You must be signed in to change notification settings - Fork 71
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: management command to truncate social auth (#2376)
truncates all entries in this table were modified outside of the last 90 days. Doesn't take any arguments because YAGNI; can easily be modified in the future if the situation changes. FIXES: APER-3160
- Loading branch information
Showing
3 changed files
with
93 additions
and
0 deletions.
There are no files selected for viewing
45 changes: 45 additions & 0 deletions
45
credentials/apps/core/management/commands/tests/test_truncate_social_auth.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
""" | ||
Tests for the truncate_social_auth management command | ||
""" | ||
|
||
from datetime import datetime, timedelta, timezone | ||
from unittest.mock import patch | ||
|
||
from django.contrib.auth import get_user_model | ||
from django.core.management import call_command | ||
from django.test import TestCase | ||
from social_django.models import UserSocialAuth | ||
|
||
from credentials.apps.core.tests.factories import UserFactory, UserSocialAuthFactory | ||
|
||
|
||
User = get_user_model() | ||
|
||
JSON = "application/json" | ||
|
||
|
||
class TruncateUserSocialAuthTest(TestCase): | ||
def setUp(self): | ||
"""Create social auth records for test""" | ||
super().setUp() | ||
now = datetime.now(timezone.utc) | ||
long_ago = now - timedelta(days=180) | ||
|
||
self.user_young = UserFactory() | ||
self.user_old = UserFactory() | ||
|
||
self.auth_young = UserSocialAuthFactory(user_id=self.user_young.id, modified=now) | ||
with patch("django.utils.timezone.now") as mock_now: | ||
mock_now.return_value = long_ago | ||
self.auth_old = UserSocialAuthFactory(user_id=self.user_old.id, modified=long_ago) | ||
|
||
def test_delete_old_rows(self): | ||
"""verify that only old auth records are deleted.""" | ||
auth_records = UserSocialAuth.objects.all() | ||
self.assertEqual(len(auth_records), 2) | ||
|
||
call_command("truncate_social_auth") | ||
|
||
auth_records = UserSocialAuth.objects.all() | ||
self.assertEqual(len(auth_records), 1) | ||
self.assertEqual(auth_records[0], self.auth_young) |
38 changes: 38 additions & 0 deletions
38
credentials/apps/core/management/commands/truncate_social_auth.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
""" | ||
Django managment command to truncate the social_auth_usersocialauth table. | ||
The social-auth-app-django plugin can have migrations on upgrade, and those | ||
migrations can fail when the social_auth_usersocialauth table is too large. | ||
It's safe to truncate the table; it doesn't affect logged in users at all. | ||
However, to avoid any risk, this keeps a window of learners who have logged | ||
in in the last 90 days. | ||
""" | ||
|
||
import logging | ||
from datetime import datetime, timedelta, timezone | ||
|
||
from django.contrib.auth import get_user_model | ||
from django.core.management.base import BaseCommand | ||
from social_django.models import UserSocialAuth | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
User = get_user_model() | ||
|
||
|
||
class Command(BaseCommand): | ||
def handle(self, *args, **options): | ||
"""Truncate the social_auth_usersocialauth table.""" | ||
now = datetime.now(timezone.utc) | ||
error_message = "truncate_social_auth deleted failed" | ||
# This is unlikely to be a run-more-than-once management command. | ||
# If the need rearises, this timedelta could become an argument. | ||
window_to_keep = timedelta(days=90) | ||
try: | ||
deleted = UserSocialAuth.objects.filter(modified__lte=now - window_to_keep).delete() | ||
except: # pylint: disable=bare-except | ||
logger.exception(error_message) | ||
try: | ||
logger.info(f"truncate_social_auth deleted {deleted[0]} rows") | ||
except IndexError: | ||
logger.error(error_message) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters