Example #1
0
def log_action(
    action,
    user,
    translation=None,
    entity=None,
    locale=None,
):
    """Save a new action in the database.

    :arg string action:
        The type of action that was performed.
        See models.ActionLog.ACTIONS_TYPES for choices.
    :arg User user: The User who performed the action.
    :arg Translation translation: The Translation the action was performed on.
    :arg Entity entity:
        The Entity the action was performed on.
        Only used for the "translation:deleted" action.
    :arg Locale locale:
        The Locale the action was performed on.
        Only used for the "translation:deleted" action.

    :returns: None
    """
    action = ActionLog(
        action_type=action,
        performed_by=user,
        translation=translation,
        entity=entity,
        locale=locale,
    )
    action.save()
Example #2
0
def approve_translations(form, user, translations, locale):
    """Approve a series of translations.

    For documentation, refer to the `batch_action_template` function.

    """
    invalid_translation_pks = list(
        translations.filter(
            approved=False,
            errors__isnull=False,
        ).values_list("pk", flat=True)
    )

    translations = translations.filter(
        approved=False,
        errors__isnull=True,
    )
    changed_translation_pks = list(translations.values_list("pk", flat=True))

    latest_translation_pk = None
    if changed_translation_pks:
        latest_translation_pk = translations.last().pk

    count, translated_resources, changed_entities = utils.get_translations_info(
        translations,
        locale,
    )

    # Log approving actions
    actions_to_log = [
        ActionLog(
            action_type=ActionLog.ActionType.TRANSLATION_APPROVED,
            performed_by=user,
            translation=t,
        )
        for t in translations
    ]
    ActionLog.objects.bulk_create(actions_to_log)

    # Approve translations.
    translations.update(
        approved=True,
        approved_user=user,
        approved_date=timezone.now(),
        rejected=False,
        rejected_user=None,
        rejected_date=None,
        pretranslated=False,
        fuzzy=False,
    )

    return {
        "count": count,
        "translated_resources": translated_resources,
        "changed_entities": changed_entities,
        "latest_translation_pk": latest_translation_pk,
        "changed_translation_pks": changed_translation_pks,
        "invalid_translation_pks": invalid_translation_pks,
    }
Example #3
0
 def bulk_create_translations(self):
     Translation.objects.bulk_create(self.translations_to_create)
     for translation in self.translations_to_create:
         self.actions_to_log.append(
             ActionLog(
                 action_type=ActionLog.ActionType.TRANSLATION_CREATED,
                 created_at=translation.date,
                 performed_by=translation.user or self.sync_user,
                 translation=translation,
             ))
Example #4
0
 def bulk_create_translations(self):
     Translation.objects.bulk_create(self.translations_to_create)
     for translation in self.translations_to_create:
         self.actions_to_log.append(
             ActionLog(
                 action_type="translation:created",
                 created_at=translation.date,
                 performed_by=translation.user or self.sync_user,
                 translation=translation,
             ))
Example #5
0
def reject_translations(form, user, translations, locale):
    """Reject a series of translations.

    Note that this function doesn't use the `translations` parameter, as it
    needs to impact non-active translations. Hence it will generate its own
    list of suggested translations to work on.

    For documentation, refer to the `batch_action_template` function.

    """
    suggestions = Translation.objects.filter(
        locale=locale,
        entity__pk__in=form.cleaned_data["entities"],
        approved=False,
        rejected=False,
    )
    count, translated_resources, changed_entities = utils.get_translations_info(
        suggestions,
        locale,
    )
    TranslationMemoryEntry.objects.filter(translation__in=suggestions).delete()

    # Log rejecting actions
    actions_to_log = [
        ActionLog(
            action_type=ActionLog.ActionType.TRANSLATION_REJECTED,
            performed_by=user,
            translation=t,
        )
        for t in translations
    ]
    ActionLog.objects.bulk_create(actions_to_log)

    # Reject translations.
    suggestions.update(
        active=False,
        rejected=True,
        rejected_user=user,
        rejected_date=timezone.now(),
        approved=False,
        approved_user=None,
        approved_date=None,
        pretranslated=False,
        fuzzy=False,
    )

    return {
        "count": count,
        "translated_resources": translated_resources,
        "changed_entities": changed_entities,
        "latest_translation_pk": None,
        "changed_translation_pks": [],
        "invalid_translation_pks": [],
    }
Example #6
0
def replace_translations(form, user, translations, locale):
    """Replace characters in a series of translations.

    Replaces all occurences of the content of the `find` parameter with the
    content of the `replace` parameter.

    For documentation, refer to the `batch_action_template` function.

    """
    find = form.cleaned_data["find"]
    replace = form.cleaned_data["replace"]
    latest_translation_pk = None

    (
        old_translations,
        translations_to_create,
        invalid_translation_pks,
    ) = utils.find_and_replace(translations, find, replace, user)

    count, translated_resources, changed_entities = utils.get_translations_info(
        old_translations,
        locale,
    )

    # Log rejecting actions
    actions_to_log = [
        ActionLog(
            action_type=ActionLog.ActionType.TRANSLATION_REJECTED,
            performed_by=user,
            translation=t,
        ) for t in old_translations
    ]
    ActionLog.objects.bulk_create(actions_to_log)

    # Deactivate and unapprove old translations
    old_translations.update(
        active=False,
        approved=False,
        approved_user=None,
        approved_date=None,
        rejected=True,
        rejected_user=user,
        rejected_date=timezone.now(),
        fuzzy=False,
    )

    # Create new translations
    changed_translations = Translation.objects.bulk_create(
        translations_to_create, )

    # Log creating actions
    actions_to_log = [
        ActionLog(
            action_type=ActionLog.ActionType.TRANSLATION_CREATED,
            performed_by=user,
            translation=t,
        ) for t in changed_translations
    ]
    ActionLog.objects.bulk_create(actions_to_log)

    changed_translation_pks = [c.pk for c in changed_translations]

    if changed_translation_pks:
        latest_translation_pk = max(changed_translation_pks)

    return {
        "count": count,
        "translated_resources": translated_resources,
        "changed_entities": changed_entities,
        "latest_translation_pk": latest_translation_pk,
        "changed_translation_pks": changed_translation_pks,
        "invalid_translation_pks": invalid_translation_pks,
    }
Example #7
0
    def update_entity_translations_from_vcs(
        self,
        db_entity,
        locale_code,
        vcs_translation,
        user=None,
        db_translations=None,
        db_translations_approved_before_sync=None,
    ):
        if db_translations is None:
            db_translations = db_entity.translation_set.filter(
                locale__code=locale_code, )

        if db_translations_approved_before_sync is None:
            db_translations_approved_before_sync = db_translations.filter(
                approved_date__lte=self.now)

        approved_translations = []
        fuzzy_translations = []

        for plural_form, string in vcs_translation.strings.items():
            db_translation = match_attr(db_translations,
                                        plural_form=plural_form,
                                        string=string)

            # Modify existing translation.
            if db_translation:
                new_action = None
                if not db_translation.approved and not vcs_translation.fuzzy:
                    new_action = ActionLog(
                        action_type=ActionLog.ActionType.TRANSLATION_APPROVED,
                        performed_by=user or self.sync_user,
                        translation=db_translation,
                    )
                    db_translation.approved = True
                    db_translation.approved_user = user
                    db_translation.approved_date = self.now
                db_translation.rejected = False
                db_translation.fuzzy = vcs_translation.fuzzy
                db_translation.extra = vcs_translation.extra

                if db_translation.is_dirty():
                    self.translations_to_update[
                        db_translation.pk] = db_translation
                    if new_action:
                        self.actions_to_log.append(new_action)
                if db_translation.fuzzy:
                    fuzzy_translations.append(db_translation)
                else:
                    approved_translations.append(db_translation)

            # Create new translation.
            else:
                self.translations_to_create.append(
                    Translation(
                        entity=db_entity,
                        locale=self.locales[locale_code],
                        string=string,
                        plural_form=plural_form,
                        approved=not vcs_translation.fuzzy,
                        approved_user=user,
                        approved_date=self.now
                        if not vcs_translation.fuzzy else None,
                        user=user,
                        fuzzy=vcs_translation.fuzzy,
                        extra=vcs_translation.extra,
                    ))

        # Unapprove translations that were approved before the sync job started unless sync
        # resolves them as active approved translations.
        # Note: If translations get approved after the sync starts, duplicate approvals can arise.
        # We take care of that at the and of the sync job in tasks.py.
        for translation in db_translations_approved_before_sync:
            if translation not in approved_translations:
                # Use the translation instance already set for update if it exists.
                translation = self.translations_to_update.get(
                    translation.pk, translation)
                translation.approved = False
                translation.approved_user = None
                translation.approved_date = None

                # Reject translations unless they became fuzzy during sync. Condition is sufficient
                # because they were approved previously.
                if not translation.fuzzy:
                    new_action = ActionLog(
                        action_type=ActionLog.ActionType.TRANSLATION_REJECTED,
                        performed_by=user or self.sync_user,
                        translation=translation,
                    )
                    translation.rejected = True
                    translation.rejected_user = user
                    translation.rejected_date = self.now
                else:
                    new_action = ActionLog(
                        action_type=ActionLog.ActionType.
                        TRANSLATION_UNAPPROVED,
                        performed_by=user or self.sync_user,
                        translation=translation,
                    )

                if translation.is_dirty():
                    self.translations_to_update[translation.pk] = translation
                    self.actions_to_log.append(new_action)

        # Unfuzzy existing translations unless sync resolves them as active fuzzy translations.
        # Note: Translations cannot get fuzzy after the sync job starts, because they cannot be
        # made fuzzy in Pontoon.
        for translation in db_translations:
            if translation not in fuzzy_translations:
                # Use the translation instance already set for update if it exists.
                translation = self.translations_to_update.get(
                    translation.pk, translation)
                translation.fuzzy = False

                if translation.is_dirty():
                    self.translations_to_update[translation.pk] = translation