diff --git a/server/core/convert_page_translation.py b/server/core/convert_page_translation.py new file mode 100644 index 00000000..f530a2ee --- /dev/null +++ b/server/core/convert_page_translation.py @@ -0,0 +1,68 @@ +from wagtail.models import Locale, Page + +from books.models.module import Module +from books.models.topic import Topic + +from core.logger import get_logger + +logger = get_logger(__name__) + + +class AlreadyTranslatedException(Exception): + pass + + +class ModuleDoesNotExistException(Exception): + pass + + +# todo: make this a django command +# todo: add language to translate to as an argument +# todo: write a test maybe +def convert_page_to_translation(slug: str, original_slug: str, language_code="en"): + """ + Migrate a module and its children to a new locale and links it to + its translation in the original locale. + + @param slug: the slug of the module to migrate + @param original_slug: the slug of the module in the original locale + """ + try: + module = Module.objects.get(slug=slug) + except Module.DoesNotExist: + raise ModuleDoesNotExistException(slug) + try: + original = Module.objects.get(slug=original_slug) + except Module.DoesNotExist: + raise ModuleDoesNotExistException(original_slug) + if original.translation_key == module.translation_key: + raise AlreadyTranslatedException + locale, _ = Locale.objects.get_or_create(language_code=language_code) + logger.debug("Starting conversion") + topic: Topic = module.get_parent() + try: + logger.debug("Getting existing topic translation") + translated_topic = topic.get_translation(locale) + except Page.DoesNotExist: + logger.debug("Creating topic translation") + translated_topic = topic.copy_for_translation(locale) + revision = translated_topic.latest_revision + translated_topic.publish(revision) + + module.locale = locale + if original is not None: + translation_key = original.translation_key + module.translation_key = translation_key + module.save() + chapters = module.get_children() + for chapter in chapters: + chapter.locale = locale + chapter.save() + content_blocks = chapter.get_children() + for content_block in content_blocks: + content_block.locale = locale + content_block.save() + + module.move(translated_topic, "last-child") + + return f"Converted page {slug} to be the {language_code} translation of {original_slug}" diff --git a/server/core/management/commands/migrate_translation.py b/server/core/management/commands/migrate_translation.py new file mode 100644 index 00000000..13d21b1b --- /dev/null +++ b/server/core/management/commands/migrate_translation.py @@ -0,0 +1,43 @@ +import csv +import os +from django.core import management +from django.core.management import BaseCommand, CommandError + +from basicknowledge.models import BasicKnowledge +from datetime import date + +from core.convert_page_translation import ( + AlreadyTranslatedException, + ModuleDoesNotExistException, + convert_page_to_translation, +) + +EN = "en" +FR = "fr" + + +class Command(BaseCommand): + """ + usage: `python manage.py migrate_translation --slug slug --original original_slug --language 'en'` + """ + + def add_arguments(self, parser): + parser.add_argument("--slug", type=str, required=True) + parser.add_argument("--original", type=str, required=True) + parser.add_argument("--language", type=str, choices=[EN, FR], default=EN) + + def handle(self, *_, **options): + slug = options.get("slug") + original_slug = options.get("original") + language_code = options.get("language") + try: + result = convert_page_to_translation( + slug=slug, original_slug=original_slug, language_code=language_code + ) + self.stdout.write(result) + except ModuleDoesNotExistException as e: + raise CommandError(f"Module does not exist: {e}") + except AlreadyTranslatedException: + raise CommandError( + f"Pages {slug} and {original_slug} already are translations of each other" + ) diff --git a/server/core/migrate_i18n_pages.py b/server/core/migrate_i18n_pages.py deleted file mode 100644 index 4b151ca5..00000000 --- a/server/core/migrate_i18n_pages.py +++ /dev/null @@ -1,53 +0,0 @@ -from wagtail.models import Locale, Page - -from books.models.module import Module -from books.models.topic import Topic - -from core.logger import get_logger - -logger = get_logger(__name__) - - -# todo: make this a django command -# todo: add language to translate to as an argument -# todo: write a test maybe -def migrate_i18n(slug: str, original_slug: str): - """ - Migrate a module and its children to a new locale and links it to - its translation in the original locale. - - @param slug: the slug of the module to migrate - @param original_slug: the slug of the module in the original locale - """ - module = Module.objects.get(slug=slug) - original = Module.objects.get(slug=original_slug) - en = Locale.objects.get(language_code="en") - logger.debug("starting this") - topic: Topic = module.get_parent() - try: - logger.debug("getting translation") - en_topic = topic.get_translation(en) - except Page.DoesNotExist: - logger.debug("creating translation") - en_topic = topic.copy_for_translation(en) - revision = en_topic.latest_revision - en_topic.publish(revision) - - logger.debug(f"new topic {en_topic.pk}") - module.locale = en - if original is not None: - translation_key = original.translation_key - module.translation_key = translation_key - module.save() - chapters = module.get_children() - for chapter in chapters: - chapter.locale = en - chapter.save() - content_blocks = chapter.get_children() - for content_block in content_blocks: - content_block.locale = en - content_block.save() - - module.move(en_topic, "last-child") - - print(f"go {module.title} {module.locale.language_code}") diff --git a/server/core/utils.py b/server/core/utils.py index c47b3597..23473d75 100644 --- a/server/core/utils.py +++ b/server/core/utils.py @@ -8,6 +8,7 @@ from users.models import SchoolClass logger = get_logger(__name__) + def set_hidden_for(block, visibility_list): for v in visibility_list: school_class = get_object(SchoolClass, v.school_class_id) @@ -31,51 +32,63 @@ def is_private_api_call_allowed(user, body): # logged in users without valid license have only access to logout, me & coupon mutations if user.is_anonymous: - logger.debug('User is anonymous') + logger.debug("User is anonymous") return False if user.is_superuser: - logger.debug('User is superuser') + logger.debug("User is superuser") return True - body_unicode = body.decode('utf-8') + body_unicode = body.decode("utf-8") if is_endpoint_allowed(body_unicode): - logger.debug('Endpoint allowed') + logger.debug("Endpoint allowed") return True license_expiry = user.license_expiry_date # all other resources are denied if the license is not valid if license_expiry is None: - logger.debug('license expiry is None') + logger.debug("license expiry is None") return False - logger.debug('private api call is allowed') + # logger.debug('private api call is allowed') return True # logout, betalogin, me and coupon resources are always allowed. Even if the user has no valid license def is_endpoint_allowed(body): - return re.search(r"mutation\s*.*\s*logout\s*{", body) or re.search(r"query\s*.*\s*me\s*{", body) \ - or re.search(r"mutation\s*Coupon", body) or re.search(r"mutation\s*BetaLogin", body) + return ( + re.search(r"mutation\s*.*\s*logout\s*{", body) + or re.search(r"query\s*.*\s*me\s*{", body) + or re.search(r"mutation\s*Coupon", body) + or re.search(r"mutation\s*BetaLogin", body) + ) def sync_hidden_for(model, school_class_template, school_class_to_sync): - if model.hidden_for.filter(id=school_class_template.id).exists() and not model.hidden_for.filter( - id=school_class_to_sync.id).exists(): + if ( + model.hidden_for.filter(id=school_class_template.id).exists() + and not model.hidden_for.filter(id=school_class_to_sync.id).exists() + ): model.hidden_for.add(school_class_to_sync) - if model.hidden_for.filter(id=school_class_to_sync.id).exists() and not model.hidden_for.filter( - id=school_class_template.id).exists(): + if ( + model.hidden_for.filter(id=school_class_to_sync.id).exists() + and not model.hidden_for.filter(id=school_class_template.id).exists() + ): model.hidden_for.remove(school_class_to_sync) def sync_visible_for(model, school_class_template, school_class_to_sync): - if model.visible_for.filter(id=school_class_template.id).exists() and not model.visible_for.filter( - id=school_class_to_sync.id).exists(): + if ( + model.visible_for.filter(id=school_class_template.id).exists() + and not model.visible_for.filter(id=school_class_to_sync.id).exists() + ): model.visible_for.add(school_class_to_sync) - if model.visible_for.filter(id=school_class_template.id).exists() and not model.visible_for.filter( - id=school_class_to_sync.id).exists(): + if ( + model.visible_for.filter(id=school_class_template.id).exists() + and not model.visible_for.filter(id=school_class_to_sync.id).exists() + ): model.visible_for.add(school_class_to_sync)