Repository: mozilla/pontoon

Issue:
Move `mark_changed()` model method from Entity to Translation model
Let's move `mark_changed()` [model method](https://docs.djangoproject.com/en/4.1/topics/db/models/#model-methods.) from Entity to Translation model. It's currently always used as `translation.entity.mark_changed()`. 

~And finally, migrate ChangedEntityLocale model to ChangedTranslation. The reason this is currently bound to Entity rather than Translation model is a relic of the past when we had the ability to delete translations without rejecting them first.~

_Originally posted by @mathjazz in https://github.com/mozilla/pontoon/pull/2778#discussion_r1126242719_


Discussion:
> And finally, migrate ChangedEntityLocale model to ChangedTranslation. The reason this is currently bound to Entity rather than Translation model is a relic of the past when we had the ability to delete translations without rejecting them first.

Let's leave that for a separate bug.

Resolving patch:
diff --git a/pontoon/base/models.py b/pontoon/base/models.py
--- a/pontoon/base/models.py
+++ b/pontoon/base/models.py
@@ -2904,16 +2904,6 @@ def has_changed(self, locale):
         """
         return locale in self.changed_locales.all()
 
-    def mark_changed(self, locale):
-        """
-        Mark the given locale as having changed translations since the
-        last sync.
-        """
-        if self.resource.project.data_source == Project.DataSource.DATABASE:
-            return
-
-        ChangedEntityLocale.objects.get_or_create(entity=self, locale=locale)
-
     def get_active_translation(self, plural_form=None):
         """
         Get active translation for a given entity and plural form.
@@ -3526,7 +3516,7 @@ def save(self, update_stats=True, failed_checks=None, *args, **kwargs):
         # changed in the appropriate locale. We could be smarter about
         # this but for now this is fine.
         if self.approved:
-            self.entity.mark_changed(self.locale)
+            self.mark_changed()
 
         if project.slug == "terminology":
             self.entity.reset_term_translation(self.locale)
@@ -3609,7 +3599,7 @@ def approve(self, user):
                 project=self.entity.resource.project,
             )
 
-        self.entity.mark_changed(self.locale)
+        self.mark_changed()
 
     def unapprove(self, user):
         """
@@ -3621,7 +3611,7 @@ def unapprove(self, user):
         self.save()
 
         TranslationMemoryEntry.objects.filter(translation=self).delete()
-        self.entity.mark_changed(self.locale)
+        self.mark_changed()
 
     def reject(self, user):
         """
@@ -3631,7 +3621,7 @@ def reject(self, user):
         # We must do this before rejecting it.
         if self.approved or self.pretranslated or self.fuzzy:
             TranslationMemoryEntry.objects.filter(translation=self).delete()
-            self.entity.mark_changed(self.locale)
+            self.mark_changed()
 
         self.rejected = True
         self.rejected_user = user
@@ -3664,6 +3654,18 @@ def serialize(self):
             "warnings": [warning.message for warning in self.warnings.all()],
         }
 
+    def mark_changed(self):
+        """
+        Mark the given locale as having changed translations since the
+        last sync.
+        """
+        if self.entity.resource.project.data_source == Project.DataSource.DATABASE:
+            return
+
+        ChangedEntityLocale.objects.get_or_create(
+            entity=self.entity, locale=self.locale
+        )
+
 
 class TranslationMemoryEntryQuerySet(models.QuerySet):
     def postgres_levenshtein_ratio(


Test patch:
diff --git a/pontoon/base/tests/models/test_entity.py b/pontoon/base/tests/models/test_entity.py
--- a/pontoon/base/tests/models/test_entity.py
+++ b/pontoon/base/tests/models/test_entity.py
@@ -508,26 +508,21 @@ def test_entity_project_locale_tags(admin, entity_a, locale_a, tag_a):
 
 @pytest.mark.django_db
 def test_entity_marked_changed_when_project_data_source_is_repository(translation_a):
-    entity = translation_a.entity
-    locale = translation_a.locale
-
     assert ChangedEntityLocale.objects.count() == 0
-    entity.mark_changed(locale)
+    translation_a.mark_changed()
     assert ChangedEntityLocale.objects.count() == 1
 
 
 @pytest.mark.django_db
 def test_entity_marked_changed_when_project_data_source_is_database(translation_a):
-    entity = translation_a.entity
-    project = entity.resource.project
-    locale = translation_a.locale
+    project = translation_a.entity.resource.project
 
     Project.objects.filter(pk=project.pk).update(
         data_source=Project.DataSource.DATABASE
     )
 
-    entity.refresh_from_db()
+    translation_a.refresh_from_db()
 
     assert ChangedEntityLocale.objects.count() == 0
-    entity.mark_changed(locale)
+    translation_a.mark_changed()
     assert ChangedEntityLocale.objects.count() == 0