Skip to content

Commit

Permalink
feat: management command to truncate social auth (#2376)
Browse files Browse the repository at this point in the history
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
deborahgu authored Feb 5, 2024
1 parent 065e1d5 commit bfda973
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 0 deletions.
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 credentials/apps/core/management/commands/truncate_social_auth.py
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)
10 changes: 10 additions & 0 deletions credentials/apps/core/tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from django.contrib.sites.models import Site
from factory import Faker, PostGenerationMethodCall, Sequence, SubFactory, django, sequence
from social_django.models import UserSocialAuth

from credentials.apps.core.models import SiteConfiguration, User

Expand Down Expand Up @@ -56,3 +57,12 @@ class Meta:
certificate_help_url = Faker("url")
records_help_url = Faker("url")
twitter_username = Faker("word")


class UserSocialAuthFactory(django.DjangoModelFactory):
class Meta:
model = UserSocialAuth

user_id = Faker("random_int")
provider = Faker("word")
extra_data = Faker("json")

0 comments on commit bfda973

Please sign in to comment.