@@ -0,0 +1,3300 @@
+# -*- coding: utf-8 *-*%0A%0A# This file is part of wger Workout Manager.%0A#%0A# wger Workout Manager is free software: you can redistribute it and/or modify%0A# it under the terms of the GNU Affero General Public License as published by%0A# the Free Software Foundation, either version 3 of the License, or%0A# (at your option) any later version.%0A#%0A# wger Workout Manager is distributed in the hope that it will be useful,%0A# but WITHOUT ANY WARRANTY; without even the implied warranty of%0A# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the%0A# GNU General Public License for more details.%0A#%0A# You should have received a copy of the GNU Affero General Public License%0A%0A# Standard Library%0Aimport collections%0A%0A# Django%0Afrom django.core.management.base import BaseCommand%0A%0A# wger%0Afrom wger.core.models import Language%0Afrom wger.exercises.models import ExerciseBase%0Afrom wger.utils.constants import ENGLISH_SHORT_NAME%0A%0A%0Aclass Command(BaseCommand):%0A    %22%22%22%0A    Performs some sanity checks on the exercise database%0A    %22%22%22%0A%0A    help = %22%22%22Performs some sanity checks on the database%0A%0A            At the moment this script checks the following:%0A            - each base has at least one exercise%0A            - each exercise base has a translation in English%0A            - exercise bases have no duplicate translations%0A            %22%22%22%0A%0A    def add_arguments(self, parser):%0A%0A        # Add dry run argument%0A        parser.add_argument(%0A            '--delete',%0A            action='store_true',%0A            dest='delete',%0A            default=False,%0A            help='Delete problematic exercise bases from the database (use with care!!)',%0A        )%0A%0A    def handle(self, **options):%0A%0A        delete = options%5B'delete'%5D%0A        english = Language.objects.get(short_name=ENGLISH_SHORT_NAME)%0A%0A        for base in ExerciseBase.objects.all():%0A%0A            if not base.exercises.count():%0A                warning = f'Exercise base %7Bbase.uuid%7D has no translations!'%0A                self.stdout.write(self.style.WARNING(warning))%0A%0A                if delete:%0A                    base.delete()%0A                    self.stdout.write('  Deleting base...')%0A                continue%0A%0A            if not base.exercises.filter(language=english).exists():%0A                warning = f'Exercise base %7Bbase.uuid%7D has no English translation!'%0A                self.stdout.write(self.style.WARNING(warning))%0A%0A                if delete:%0A                    base.delete()%0A                    self.stdout.write('  Deleting base...')%0A%0A            exercise_languages = base.exercises.values_list('language_id', flat=True)%0A            duplicates = %5B%0A                item for item, count in collections.Counter(exercise_languages).items() if count %3E 1%0A            %5D%0A%0A            if not duplicates:%0A                continue%0A%0A            warning = f'Exercise base %7Bbase.uuid%7D has duplicate translations for language IDs: %7Bduplicates%7D!'%0A            self.stdout.write(self.style.WARNING(warning))%0A%0A            if delete:%0A                exercises = base.exercises.filter(language_id__in=duplicates)%0A                for exercise in exercises%5B1:%5D:%0A                    exercise.delete()%0A                    self.stdout.write(%0A                        f'  Deleting translation %7Bexercise.uuid%7D for language ID %7Bexercise.language_id%7D...'%0A                    )%0A

Add script to check the current exercise translations