Skip to content

Commit

Permalink
Clears the exercise api cache when editing an exercise
Browse files Browse the repository at this point in the history
Closes #1487
  • Loading branch information
rolandgeider committed Jan 15, 2024
1 parent 0781442 commit b70f4a0
Show file tree
Hide file tree
Showing 10 changed files with 217 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@
# You should have received a copy of the GNU Affero General Public License

# Django
from django.core.cache import cache
from django.core.management.base import BaseCommand

# wger
from wger.exercises.api.serializers import ExerciseBaseInfoSerializer
from wger.exercises.models import ExerciseBase
from wger.utils.cache import CacheKeyMapper
from wger.utils.cache import reset_exercise_api_cache


class Command(BaseCommand):
Expand Down Expand Up @@ -62,7 +61,7 @@ def handle_cache(self, exercise: ExerciseBase, force: bool):
self.stdout.write(f"Warming cache for exercise base {exercise.uuid}")

if force:
cache.delete(CacheKeyMapper.get_exercise_api_key(exercise.uuid))
reset_exercise_api_cache(exercise.uuid)

serializer = ExerciseBaseInfoSerializer(exercise)
serializer.data
8 changes: 8 additions & 0 deletions wger/exercises/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
ExerciseBaseManagerNoTranslations,
ExerciseBaseManagerTranslations,
)
from wger.utils.cache import reset_exercise_api_cache
from wger.utils.constants import ENGLISH_SHORT_NAME
from wger.utils.models import (
AbstractHistoryMixin,
Expand Down Expand Up @@ -236,6 +237,11 @@ def get_translation(self, language: Optional[str] = None):

return translation

def save(self, *args, **kwargs):
super().save(*args, **kwargs)

reset_exercise_api_cache(self.uuid)

def delete(self, using=None, keep_parents=False, replace_by: str = None):
"""
Save entry to log
Expand All @@ -257,4 +263,6 @@ def delete(self, using=None, keep_parents=False, replace_by: str = None):
)
log.save()

reset_exercise_api_cache(self.uuid)

return super().delete(using, keep_parents)
15 changes: 12 additions & 3 deletions wger/exercises/models/comment.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@
from simple_history.models import HistoricalRecords

# wger
from wger.utils.cache import reset_workout_canonical_form
from wger.utils.cache import (
reset_exercise_api_cache,
reset_workout_canonical_form,
)

# Local
from .exercise import Exercise
Expand Down Expand Up @@ -71,7 +74,10 @@ def save(self, *args, **kwargs):
for setting in self.exercise.exercise_base.setting_set.all():
reset_workout_canonical_form(setting.set.exerciseday.training_id)

super(ExerciseComment, self).save(*args, **kwargs)
# Api cache
reset_exercise_api_cache(self.exercise.exercise_base.uuid)

super().save(*args, **kwargs)

def delete(self, *args, **kwargs):
"""
Expand All @@ -80,7 +86,10 @@ def delete(self, *args, **kwargs):
for setting in self.exercise.exercise_base.setting_set.all():
reset_workout_canonical_form(setting.set.exerciseday.training.pk)

super(ExerciseComment, self).delete(*args, **kwargs)
# Api cache
reset_exercise_api_cache(self.exercise.exercise_base.uuid)

super().delete(*args, **kwargs)

def get_owner_object(self):
"""
Expand Down
15 changes: 12 additions & 3 deletions wger/exercises/models/exercise.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@
# wger
from wger.core.models import Language
from wger.exercises.models import ExerciseBase
from wger.utils.cache import reset_workout_canonical_form
from wger.utils.cache import (
reset_exercise_api_cache,
reset_workout_canonical_form,
)
from wger.utils.models import (
AbstractHistoryMixin,
AbstractLicenseModel,
Expand Down Expand Up @@ -119,7 +122,10 @@ def save(self, *args, **kwargs):
"""
Reset all cached infos
"""
super(Exercise, self).save(*args, **kwargs)
super().save(*args, **kwargs)

# Api cache
reset_exercise_api_cache(self.exercise_base.uuid)

# Cached workouts
for setting in self.exercise_base.setting_set.all():
Expand All @@ -133,7 +139,10 @@ def delete(self, *args, **kwargs):
for setting in self.exercise_base.setting_set.all():
reset_workout_canonical_form(setting.set.exerciseday.training.pk)

super(Exercise, self).delete(*args, **kwargs)
# Api cache
reset_exercise_api_cache(self.exercise_base.uuid)

super().delete(*args, **kwargs)

def __str__(self):
"""
Expand Down
19 changes: 17 additions & 2 deletions wger/exercises/models/exercise_alias.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@
from simple_history.models import HistoricalRecords

# wger
from wger.utils.cache import reset_workout_canonical_form
from wger.utils.cache import (
reset_exercise_api_cache,
reset_workout_canonical_form,
)

# Local
from .exercise import Exercise
Expand Down Expand Up @@ -63,14 +66,26 @@ def __str__(self):
"""
return self.alias

def save(self, *args, **kwargs):
"""
Reset cached workouts
"""
# Api cache
reset_exercise_api_cache(self.exercise.exercise_base.uuid)

super().save(*args, **kwargs)

def delete(self, *args, **kwargs):
"""
Reset cached workouts
"""
for setting in self.exercise.exercise_base.setting_set.all():
reset_workout_canonical_form(setting.set.exerciseday.training.pk)

super(Alias, self).delete(*args, **kwargs)
# Api cache
reset_exercise_api_cache(self.exercise.exercise_base.uuid)

super().delete(*args, **kwargs)

def get_owner_object(self):
"""
Expand Down
8 changes: 6 additions & 2 deletions wger/exercises/models/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

# wger
from wger.exercises.models import ExerciseBase
from wger.utils.cache import reset_exercise_api_cache
from wger.utils.helpers import BaseImage
from wger.utils.models import (
AbstractHistoryMixin,
Expand Down Expand Up @@ -145,14 +146,17 @@ def save(self, *args, **kwargs):
.count():
self.is_main = True

# Api cache
reset_exercise_api_cache(self.exercise_base.uuid)

# And go on
super(ExerciseImage, self).save(*args, **kwargs)
super().save(*args, **kwargs)

def delete(self, *args, **kwargs):
"""
Reset all cached infos
"""
super(ExerciseImage, self).delete(*args, **kwargs)
super().delete(*args, **kwargs)

# Make sure there is always a main image
if not ExerciseImage.objects.all().filter(exercise_base=self.exercise_base, is_main=True
Expand Down
7 changes: 6 additions & 1 deletion wger/exercises/models/video.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
# Third Party
from simple_history.models import HistoricalRecords

# wger
from wger.utils.cache import reset_exercise_api_cache

try:
# Third Party
Expand Down Expand Up @@ -210,4 +212,7 @@ def save(self, *args, **kwargs):
self.codec = stream['codec_name']
self.codec_long = stream['codec_long_name']

super(ExerciseVideo, self).save(*args, **kwargs)
# Api cache
reset_exercise_api_cache(self.exercise_base.uuid)

super().save(*args, **kwargs)
148 changes: 148 additions & 0 deletions wger/exercises/tests/test_exercise_api_cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# This file is part of wger Workout Manager.
#
# wger Workout Manager is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# wger Workout Manager is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License

# Django
from django.core.cache import cache

# wger
from wger.core.tests.base_testcase import (
WgerTestCase,
)
from wger.exercises.models import (
Alias,
Exercise,
ExerciseBase,
ExerciseComment,
)
from wger.utils.cache import cache_mapper


class ExerciseApiCacheTestCase(WgerTestCase):
"""
Tests the API cache for the exercisebaseinfo endpoint
"""

exercise_id = 1
exercise_uuid = 'acad3949-36fb-4481-9a72-be2ddae2bc05'
url = '/api/v2/exercisebaseinfo/1/'

cache_key = cache_mapper.get_exercise_api_key('acad3949-36fb-4481-9a72-be2ddae2bc05')

def test_edit_exercise(self):
"""
Tests editing an exercise
"""
self.assertFalse(cache.get(self.cache_key))
self.client.get(self.url)
self.assertTrue(cache.get(self.cache_key))

exercise = ExerciseBase.objects.get(pk=1)
exercise.category_id = 1
exercise.save()

self.assertFalse(cache.get(self.cache_key))

def test_delete_exercise(self):
"""
Tests deleting an exercise
"""
self.assertFalse(cache.get(self.cache_key))
self.client.get(self.url)
self.assertTrue(cache.get(self.cache_key))

exercise = ExerciseBase.objects.get(pk=1)
exercise.delete()

self.assertFalse(cache.get(self.cache_key))

def test_edit_translation(self):
"""
Tests editing a translation
"""
self.assertFalse(cache.get(self.cache_key))
self.client.get(self.url)
self.assertTrue(cache.get(self.cache_key))

translation = Exercise.objects.get(pk=1)
translation.name = "something else"
translation.save()

self.assertFalse(cache.get(self.cache_key))

def test_delete_translation(self):
"""
Tests deleting a translation
"""
self.assertFalse(cache.get(self.cache_key))
self.client.get(self.url)
self.assertTrue(cache.get(self.cache_key))

translation = Exercise.objects.get(pk=1)
translation.delete()

self.assertFalse(cache.get(self.cache_key))

def test_edit_comment(self):
"""
Tests editing a comment
"""
self.assertFalse(cache.get(self.cache_key))
self.client.get(self.url)
self.assertTrue(cache.get(self.cache_key))

comment = ExerciseComment.objects.get(pk=1)
comment.name = "The Shiba Inu (柴犬) is a breed of hunting dog from Japan"
comment.save()

self.assertFalse(cache.get(self.cache_key))

def test_delete_comment(self):
"""
Tests deleting a comment
"""
self.assertFalse(cache.get(self.cache_key))
self.client.get(self.url)
self.assertTrue(cache.get(self.cache_key))

comment = ExerciseComment.objects.get(pk=1)
comment.delete()

self.assertFalse(cache.get(self.cache_key))

def test_edit_alias(self):
"""
Tests editing an alias
"""
self.assertFalse(cache.get(self.cache_key))
self.client.get(self.url)
self.assertTrue(cache.get(self.cache_key))

alias = Alias.objects.get(pk=1)
alias.name = "Hachikō"
alias.save()

self.assertFalse(cache.get(self.cache_key))

def test_delete_alias(self):
"""
Tests deleting an alias
"""
self.assertFalse(cache.get(self.cache_key))
self.client.get(self.url)
self.assertTrue(cache.get(self.cache_key))

alias = Alias.objects.get(pk=1)
alias.delete()

self.assertFalse(cache.get(self.cache_key))
16 changes: 2 additions & 14 deletions wger/exercises/tests/test_exercise_comments.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,10 @@
#
# You should have received a copy of the GNU Affero General Public License

# Django
from django.core.cache import cache
from django.urls import reverse

# wger
from wger.core.tests.api_base_test import ExerciseCrudApiTestCase
from wger.core.tests.base_testcase import (
WgerAddTestCase,
WgerEditTestCase,
WgerTestCase,
)
from wger.exercises.models import (
Exercise,
ExerciseComment,
)
from wger.utils.cache import cache_mapper
from wger.core.tests.base_testcase import WgerTestCase
from wger.exercises.models import ExerciseComment


class ExerciseCommentRepresentationTestCase(WgerTestCase):
Expand Down
4 changes: 4 additions & 0 deletions wger/utils/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ def reset_workout_canonical_form(workout_id):
cache.delete(cache_mapper.get_workout_canonical(workout_id))


def reset_exercise_api_cache(uuid: str):
cache.delete(cache_mapper.get_exercise_api_key(uuid))


def reset_workout_log(user_pk, year, month, day=None):
"""
Resets the cached workout logs
Expand Down

0 comments on commit b70f4a0

Please sign in to comment.