We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Deliver content of mirrored page via API
So far the content of the mirrored page isn't delivered via the API

Steps to reproduce:

1. Add mirrored content to page
2. Save
3. Access API (for example http://0.0.0.0:8000/api/augsburg/de-de/pages/)

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `backend/cms/models/pages/page.py`
Content:
```
1 """Models representing a page and page translation with content
2 """
3 import logging
4 
5 from django.conf import settings
6 from django.db import models
7 from django.urls import reverse
8 from django.utils import timezone
9 from django.utils.translation import get_language
10 
11 from mptt.models import MPTTModel, TreeForeignKey
12 
13 from ..regions.region import Region
14 from ...constants import status
15 
16 logger = logging.getLogger(__name__)
17 
18 
19 class Page(MPTTModel):
20     """Class that represents an Page database object
21 
22     Args:
23         MPTTModel : Library for hierachical data structures
24     """
25 
26     parent = TreeForeignKey(
27         'self',
28         blank=True,
29         null=True,
30         related_name='children',
31         on_delete=models.PROTECT
32     )
33     icon = models.ImageField(
34         blank=True,
35         null=True,
36         upload_to='pages/%Y/%m/%d'
37     )
38     region = models.ForeignKey(Region, related_name='pages', on_delete=models.CASCADE)
39     archived = models.BooleanField(default=False)
40     mirrored_page = models.ForeignKey('self', null=True, blank=True, on_delete=models.PROTECT)
41     mirrored_page_first = models.BooleanField(default=True, null=True, blank=True)
42     editors = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='editors', blank=True)
43     publishers = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='publishers', blank=True)
44     created_date = models.DateTimeField(default=timezone.now)
45     last_updated = models.DateTimeField(auto_now=True)
46 
47     @property
48     def depth(self):
49         """Provide level of inheritance
50 
51         Returns:
52             Int : Number of ancestors
53         """
54 
55         return len(self.get_ancestors())
56 
57     @property
58     def languages(self):
59         page_translations = self.translations.prefetch_related('language').all()
60         languages = []
61         for page_translation in page_translations:
62             if page_translation.language not in languages:
63                 languages.append(page_translation.language)
64         return languages
65 
66     def get_translation(self, language_code):
67         return self.translations.filter(
68             language__code=language_code
69         ).first()
70 
71     # Helper function for page labels, second level paths etc. where the ancestor translation might not exist
72     def get_first_translation(self, priority_language_codes=None):
73         # Taking [] directly as default parameter would be dangerous because it is mutable
74         if not priority_language_codes:
75             priority_language_codes = []
76         for language_code in priority_language_codes + ['en-us', 'de-de']:
77             if self.translations.filter(language__code=language_code).exists():
78                 return self.translations.filter(language__code=language_code).first()
79         return self.translations.first()
80 
81     def get_public_translation(self, language_code):
82         return self.translations.filter(
83             language__code=language_code,
84             status=status.PUBLIC,
85         ).first()
86 
87     def get_mirrored_text(self, language_code):
88         """
89         This content needs to be added when delivering content to end users
90         """
91         return self.mirrored_page.get_translation(language_code).text
92 
93     def get_absolute_url(self):
94         return reverse('edit_page', kwargs={
95             'page_id': self.id,
96             'region_slug': self.region.slug,
97             'language_code': self.region.default_language.code,
98         })
99 
100     @staticmethod
101     def get_archived(region_slug):
102         return Page.objects.filter(archived=True, region__slug=region_slug)
103 
104     @staticmethod
105     def archived_count(region_slug):
106         return Page.objects.filter(archived=True, region__slug=region_slug).count()
107 
108     def __str__(self):
109         if self.id:
110             first_translation = self.get_first_translation()
111             if first_translation:
112                 return '(id: {}, slug: {} ({}))'.format(self.id, first_translation.slug, first_translation.language.code)
113             return '(id: {})'.format(self.id)
114         return super(Page, self).__str__()
115 
116     @classmethod
117     def get_tree(cls, region_slug, archived=False):
118         """Function for building up a Treeview of all pages
119 
120         Args:
121             region_slug: slug of the region the page belongs to
122             archived:  if true archived pages will be included
123 
124         Returns:
125             [pages]: Array of pages connected with their relations
126         """
127 
128         return cls.objects.all().prefetch_related(
129             'translations'
130         ).filter(
131             region__slug=region_slug,
132             archived=archived
133         )
134 
135     def best_language_title(self):
136         page_translation = self.translations.filter(language__code=get_language())
137         if not page_translation:
138             alt_code = self.region.default_language.code
139             page_translation = self.translations.filter(language__code=alt_code)
140         return page_translation.first().title
141 
142     class Meta:
143         default_permissions = ()
144         permissions = (
145             ('view_pages', 'Can view pages'),
146             ('edit_pages', 'Can edit pages'),
147             ('publish_pages', 'Can publish pages'),
148             ('grant_page_permissions', 'Can grant page permissions'),
149         )
150
```

Path: `backend/api/v3/pages.py`
Content:
```
1 from django.http import JsonResponse
2 
3 from cms.models import Region
4 
5 
6 def transform_page(page_translation):
7     if page_translation.page.parent:
8         parent = {
9             'id': page_translation.page.parent.id,
10             'url': page_translation.page.parent.get_translation(
11                 page_translation.language.code
12             ).permalink,
13             'path': page_translation.page.parent.get_translation(
14                 page_translation.language.code
15             ).slug,
16         }
17     else:
18         parent = None
19     return {
20         'id': page_translation.id,
21         'url': page_translation.permalink,
22         'path': page_translation.slug,
23         'title': page_translation.title,
24         'modified_gmt': page_translation.last_updated,
25         'excerpt': page_translation.text,
26         'content': page_translation.text,
27         'parent': parent,
28         'order': page_translation.page.lft, # use left edge indicator of mptt model for order
29         'available_languages': page_translation.available_languages,
30         'thumbnail': None,
31         'hash': None
32     }
33 
34 def pages(request, region_slug, language_code):
35     region = Region.objects.get(slug=region_slug)
36     result = []
37     for page in region.pages.all():
38         page_translation = page.get_public_translation(language_code)
39         if page_translation:
40             result.append(transform_page(page_translation))
41     return JsonResponse(result, safe=False)  # Turn off Safe-Mode to allow serializing arrays
42
```

Path: `backend/cms/models/pages/page_translation.py`
Content:
```
1 """Models representing a page and page translation with content
2 """
3 import logging
4 
5 from django.conf import settings
6 from django.db import models
7 from django.utils import timezone
8 
9 from .page import Page
10 from ..languages.language import Language
11 from ...constants import status
12 
13 
14 logger = logging.getLogger(__name__)
15 
16 
17 class PageTranslation(models.Model):
18     """Class defining a Translation of a Page
19 
20     Args:
21         models : Class inherit of django-Models
22     """
23 
24     page = models.ForeignKey(Page, related_name='translations', on_delete=models.CASCADE)
25     language = models.ForeignKey(
26         Language,
27         related_name='page_translations',
28         on_delete=models.CASCADE
29     )
30     slug = models.SlugField(max_length=200, blank=True, allow_unicode=True)
31     title = models.CharField(max_length=250)
32     text = models.TextField(blank=True)
33     status = models.CharField(max_length=6, choices=status.CHOICES, default=status.DRAFT)
34     currently_in_translation = models.BooleanField(default=False)
35     version = models.PositiveIntegerField(default=0)
36     minor_edit = models.BooleanField(default=False)
37     creator = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.SET_NULL)
38     created_date = models.DateTimeField(default=timezone.now)
39     last_updated = models.DateTimeField(auto_now=True)
40 
41     @property
42     def foreign_object(self):
43         return self.page
44 
45     @property
46     def ancestor_path(self):
47         return '/'.join([
48             ancestor.get_first_translation([self.language.code]).slug
49             for ancestor in self.page.get_ancestors()
50         ])
51 
52     @property
53     def permalink(self):
54         return '/'.join(filter(None, [
55             self.page.region.slug,
56             self.language.code,
57             self.ancestor_path,
58             self.slug
59         ]))
60 
61     @property
62     def available_languages(self):
63         languages = self.page.languages
64         languages.remove(self.language)
65         available_languages = {}
66         for language in languages:
67             other_translation = self.page.get_public_translation(language.code)
68             if other_translation:
69                 available_languages[language.code] = {
70                     'id': other_translation.id,
71                     'url': other_translation.permalink
72                 }
73         return available_languages
74 
75     @property
76     def source_translation(self):
77         source_language_tree_node = self.page.region.language_tree_nodes.get(language=self.language).parent
78         if source_language_tree_node:
79             return self.page.get_translation(source_language_tree_node.code)
80         return None
81 
82     @property
83     def latest_public_revision(self):
84         return self.page.translations.filter(
85             language=self.language,
86             status=status.PUBLIC,
87         ).first()
88 
89     @property
90     def latest_major_revision(self):
91         return self.page.translations.filter(
92             language=self.language,
93             minor_edit=False,
94         ).first()
95 
96     @property
97     def latest_major_public_revision(self):
98         return self.page.translations.filter(
99             language=self.language,
100             status=status.PUBLIC,
101             minor_edit=False,
102         ).first()
103 
104     @property
105     def previous_revision(self):
106         version = self.version - 1
107         return self.page.translations.filter(
108             language=self.language,
109             version=version,
110         ).first()
111 
112     @property
113     def is_outdated(self):
114         source_translation = self.source_translation
115         # If self.language is the root language, this translation can never be outdated
116         if not source_translation:
117             return False
118         # If the source translation is outdated, this translation can not be up to date
119         if source_translation.is_outdated:
120             return True
121         self_revision = self.latest_major_public_revision
122         source_revision = source_translation.latest_major_public_revision
123         # If on of the translations has no major public revision, it cannot be outdated
124         if not self_revision or not source_revision:
125             return False
126         return self_revision.last_updated < source_revision.last_updated
127 
128     @property
129     def combined_text(self):
130         """
131         Combines the text from the PageTranslation with the text from the mirrored page.
132         """
133         if self.page.mirrored_page_first:
134             return self.page.get_mirrored_text(self.language.code) + self.text
135         return self.text + self.page.get_mirrored_text(self.language.code)
136 
137     def __str__(self):
138         if self.id:
139             return '(id: {}, lang: {}, slug: {})'.format(self.id, self.language.code, self.slug)
140         return super(PageTranslation, self).__str__()
141 
142     class Meta:
143         ordering = ['page', '-version']
144         default_permissions = ()
145
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/backend/api/v3/pages.py b/backend/api/v3/pages.py
--- a/backend/api/v3/pages.py
+++ b/backend/api/v3/pages.py
@@ -23,7 +23,7 @@
         'title': page_translation.title,
         'modified_gmt': page_translation.last_updated,
         'excerpt': page_translation.text,
-        'content': page_translation.text,
+        'content': page_translation.combined_text,
         'parent': parent,
         'order': page_translation.page.lft, # use left edge indicator of mptt model for order
         'available_languages': page_translation.available_languages,
diff --git a/backend/cms/models/pages/page.py b/backend/cms/models/pages/page.py
--- a/backend/cms/models/pages/page.py
+++ b/backend/cms/models/pages/page.py
@@ -88,7 +88,9 @@
         """
         This content needs to be added when delivering content to end users
         """
-        return self.mirrored_page.get_translation(language_code).text
+        if self.mirrored_page:
+            return self.mirrored_page.get_translation(language_code).text
+        return None
 
     def get_absolute_url(self):
         return reverse('edit_page', kwargs={
diff --git a/backend/cms/models/pages/page_translation.py b/backend/cms/models/pages/page_translation.py
--- a/backend/cms/models/pages/page_translation.py
+++ b/backend/cms/models/pages/page_translation.py
@@ -130,9 +130,12 @@
         """
         Combines the text from the PageTranslation with the text from the mirrored page.
         """
+        attached_text = self.page.get_mirrored_text(self.language.code)
+        if attached_text is None:
+            return self.text
         if self.page.mirrored_page_first:
-            return self.page.get_mirrored_text(self.language.code) + self.text
-        return self.text + self.page.get_mirrored_text(self.language.code)
+            return attached_text + self.text
+        return self.text + attached_text
 
     def __str__(self):
         if self.id:

{"golden_diff": "diff --git a/backend/api/v3/pages.py b/backend/api/v3/pages.py\n--- a/backend/api/v3/pages.py\n+++ b/backend/api/v3/pages.py\n@@ -23,7 +23,7 @@\n         'title': page_translation.title,\n         'modified_gmt': page_translation.last_updated,\n         'excerpt': page_translation.text,\n-        'content': page_translation.text,\n+        'content': page_translation.combined_text,\n         'parent': parent,\n         'order': page_translation.page.lft, # use left edge indicator of mptt model for order\n         'available_languages': page_translation.available_languages,\ndiff --git a/backend/cms/models/pages/page.py b/backend/cms/models/pages/page.py\n--- a/backend/cms/models/pages/page.py\n+++ b/backend/cms/models/pages/page.py\n@@ -88,7 +88,9 @@\n         \"\"\"\n         This content needs to be added when delivering content to end users\n         \"\"\"\n-        return self.mirrored_page.get_translation(language_code).text\n+        if self.mirrored_page:\n+            return self.mirrored_page.get_translation(language_code).text\n+        return None\n \n     def get_absolute_url(self):\n         return reverse('edit_page', kwargs={\ndiff --git a/backend/cms/models/pages/page_translation.py b/backend/cms/models/pages/page_translation.py\n--- a/backend/cms/models/pages/page_translation.py\n+++ b/backend/cms/models/pages/page_translation.py\n@@ -130,9 +130,12 @@\n         \"\"\"\n         Combines the text from the PageTranslation with the text from the mirrored page.\n         \"\"\"\n+        attached_text = self.page.get_mirrored_text(self.language.code)\n+        if attached_text is None:\n+            return self.text\n         if self.page.mirrored_page_first:\n-            return self.page.get_mirrored_text(self.language.code) + self.text\n-        return self.text + self.page.get_mirrored_text(self.language.code)\n+            return attached_text + self.text\n+        return self.text + attached_text\n \n     def __str__(self):\n         if self.id:\n", "issue": "Deliver content of mirrored page via API\nSo far the content of the mirrored page isn't delivered via the API\r\n\r\nSteps to reproduce:\r\n\r\n1. Add mirrored content to page\r\n2. Save\r\n3. Access API (for example http://0.0.0.0:8000/api/augsburg/de-de/pages/)\n", "before_files": [{"content": "\"\"\"Models representing a page and page translation with content\n\"\"\"\nimport logging\n\nfrom django.conf import settings\nfrom django.db import models\nfrom django.urls import reverse\nfrom django.utils import timezone\nfrom django.utils.translation import get_language\n\nfrom mptt.models import MPTTModel, TreeForeignKey\n\nfrom ..regions.region import Region\nfrom ...constants import status\n\nlogger = logging.getLogger(__name__)\n\n\nclass Page(MPTTModel):\n    \"\"\"Class that represents an Page database object\n\n    Args:\n        MPTTModel : Library for hierachical data structures\n    \"\"\"\n\n    parent = TreeForeignKey(\n        'self',\n        blank=True,\n        null=True,\n        related_name='children',\n        on_delete=models.PROTECT\n    )\n    icon = models.ImageField(\n        blank=True,\n        null=True,\n        upload_to='pages/%Y/%m/%d'\n    )\n    region = models.ForeignKey(Region, related_name='pages', on_delete=models.CASCADE)\n    archived = models.BooleanField(default=False)\n    mirrored_page = models.ForeignKey('self', null=True, blank=True, on_delete=models.PROTECT)\n    mirrored_page_first = models.BooleanField(default=True, null=True, blank=True)\n    editors = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='editors', blank=True)\n    publishers = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='publishers', blank=True)\n    created_date = models.DateTimeField(default=timezone.now)\n    last_updated = models.DateTimeField(auto_now=True)\n\n    @property\n    def depth(self):\n        \"\"\"Provide level of inheritance\n\n        Returns:\n            Int : Number of ancestors\n        \"\"\"\n\n        return len(self.get_ancestors())\n\n    @property\n    def languages(self):\n        page_translations = self.translations.prefetch_related('language').all()\n        languages = []\n        for page_translation in page_translations:\n            if page_translation.language not in languages:\n                languages.append(page_translation.language)\n        return languages\n\n    def get_translation(self, language_code):\n        return self.translations.filter(\n            language__code=language_code\n        ).first()\n\n    # Helper function for page labels, second level paths etc. where the ancestor translation might not exist\n    def get_first_translation(self, priority_language_codes=None):\n        # Taking [] directly as default parameter would be dangerous because it is mutable\n        if not priority_language_codes:\n            priority_language_codes = []\n        for language_code in priority_language_codes + ['en-us', 'de-de']:\n            if self.translations.filter(language__code=language_code).exists():\n                return self.translations.filter(language__code=language_code).first()\n        return self.translations.first()\n\n    def get_public_translation(self, language_code):\n        return self.translations.filter(\n            language__code=language_code,\n            status=status.PUBLIC,\n        ).first()\n\n    def get_mirrored_text(self, language_code):\n        \"\"\"\n        This content needs to be added when delivering content to end users\n        \"\"\"\n        return self.mirrored_page.get_translation(language_code).text\n\n    def get_absolute_url(self):\n        return reverse('edit_page', kwargs={\n            'page_id': self.id,\n            'region_slug': self.region.slug,\n            'language_code': self.region.default_language.code,\n        })\n\n    @staticmethod\n    def get_archived(region_slug):\n        return Page.objects.filter(archived=True, region__slug=region_slug)\n\n    @staticmethod\n    def archived_count(region_slug):\n        return Page.objects.filter(archived=True, region__slug=region_slug).count()\n\n    def __str__(self):\n        if self.id:\n            first_translation = self.get_first_translation()\n            if first_translation:\n                return '(id: {}, slug: {} ({}))'.format(self.id, first_translation.slug, first_translation.language.code)\n            return '(id: {})'.format(self.id)\n        return super(Page, self).__str__()\n\n    @classmethod\n    def get_tree(cls, region_slug, archived=False):\n        \"\"\"Function for building up a Treeview of all pages\n\n        Args:\n            region_slug: slug of the region the page belongs to\n            archived:  if true archived pages will be included\n\n        Returns:\n            [pages]: Array of pages connected with their relations\n        \"\"\"\n\n        return cls.objects.all().prefetch_related(\n            'translations'\n        ).filter(\n            region__slug=region_slug,\n            archived=archived\n        )\n\n    def best_language_title(self):\n        page_translation = self.translations.filter(language__code=get_language())\n        if not page_translation:\n            alt_code = self.region.default_language.code\n            page_translation = self.translations.filter(language__code=alt_code)\n        return page_translation.first().title\n\n    class Meta:\n        default_permissions = ()\n        permissions = (\n            ('view_pages', 'Can view pages'),\n            ('edit_pages', 'Can edit pages'),\n            ('publish_pages', 'Can publish pages'),\n            ('grant_page_permissions', 'Can grant page permissions'),\n        )\n", "path": "backend/cms/models/pages/page.py"}, {"content": "from django.http import JsonResponse\n\nfrom cms.models import Region\n\n\ndef transform_page(page_translation):\n    if page_translation.page.parent:\n        parent = {\n            'id': page_translation.page.parent.id,\n            'url': page_translation.page.parent.get_translation(\n                page_translation.language.code\n            ).permalink,\n            'path': page_translation.page.parent.get_translation(\n                page_translation.language.code\n            ).slug,\n        }\n    else:\n        parent = None\n    return {\n        'id': page_translation.id,\n        'url': page_translation.permalink,\n        'path': page_translation.slug,\n        'title': page_translation.title,\n        'modified_gmt': page_translation.last_updated,\n        'excerpt': page_translation.text,\n        'content': page_translation.text,\n        'parent': parent,\n        'order': page_translation.page.lft, # use left edge indicator of mptt model for order\n        'available_languages': page_translation.available_languages,\n        'thumbnail': None,\n        'hash': None\n    }\n\ndef pages(request, region_slug, language_code):\n    region = Region.objects.get(slug=region_slug)\n    result = []\n    for page in region.pages.all():\n        page_translation = page.get_public_translation(language_code)\n        if page_translation:\n            result.append(transform_page(page_translation))\n    return JsonResponse(result, safe=False)  # Turn off Safe-Mode to allow serializing arrays\n", "path": "backend/api/v3/pages.py"}, {"content": "\"\"\"Models representing a page and page translation with content\n\"\"\"\nimport logging\n\nfrom django.conf import settings\nfrom django.db import models\nfrom django.utils import timezone\n\nfrom .page import Page\nfrom ..languages.language import Language\nfrom ...constants import status\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass PageTranslation(models.Model):\n    \"\"\"Class defining a Translation of a Page\n\n    Args:\n        models : Class inherit of django-Models\n    \"\"\"\n\n    page = models.ForeignKey(Page, related_name='translations', on_delete=models.CASCADE)\n    language = models.ForeignKey(\n        Language,\n        related_name='page_translations',\n        on_delete=models.CASCADE\n    )\n    slug = models.SlugField(max_length=200, blank=True, allow_unicode=True)\n    title = models.CharField(max_length=250)\n    text = models.TextField(blank=True)\n    status = models.CharField(max_length=6, choices=status.CHOICES, default=status.DRAFT)\n    currently_in_translation = models.BooleanField(default=False)\n    version = models.PositiveIntegerField(default=0)\n    minor_edit = models.BooleanField(default=False)\n    creator = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.SET_NULL)\n    created_date = models.DateTimeField(default=timezone.now)\n    last_updated = models.DateTimeField(auto_now=True)\n\n    @property\n    def foreign_object(self):\n        return self.page\n\n    @property\n    def ancestor_path(self):\n        return '/'.join([\n            ancestor.get_first_translation([self.language.code]).slug\n            for ancestor in self.page.get_ancestors()\n        ])\n\n    @property\n    def permalink(self):\n        return '/'.join(filter(None, [\n            self.page.region.slug,\n            self.language.code,\n            self.ancestor_path,\n            self.slug\n        ]))\n\n    @property\n    def available_languages(self):\n        languages = self.page.languages\n        languages.remove(self.language)\n        available_languages = {}\n        for language in languages:\n            other_translation = self.page.get_public_translation(language.code)\n            if other_translation:\n                available_languages[language.code] = {\n                    'id': other_translation.id,\n                    'url': other_translation.permalink\n                }\n        return available_languages\n\n    @property\n    def source_translation(self):\n        source_language_tree_node = self.page.region.language_tree_nodes.get(language=self.language).parent\n        if source_language_tree_node:\n            return self.page.get_translation(source_language_tree_node.code)\n        return None\n\n    @property\n    def latest_public_revision(self):\n        return self.page.translations.filter(\n            language=self.language,\n            status=status.PUBLIC,\n        ).first()\n\n    @property\n    def latest_major_revision(self):\n        return self.page.translations.filter(\n            language=self.language,\n            minor_edit=False,\n        ).first()\n\n    @property\n    def latest_major_public_revision(self):\n        return self.page.translations.filter(\n            language=self.language,\n            status=status.PUBLIC,\n            minor_edit=False,\n        ).first()\n\n    @property\n    def previous_revision(self):\n        version = self.version - 1\n        return self.page.translations.filter(\n            language=self.language,\n            version=version,\n        ).first()\n\n    @property\n    def is_outdated(self):\n        source_translation = self.source_translation\n        # If self.language is the root language, this translation can never be outdated\n        if not source_translation:\n            return False\n        # If the source translation is outdated, this translation can not be up to date\n        if source_translation.is_outdated:\n            return True\n        self_revision = self.latest_major_public_revision\n        source_revision = source_translation.latest_major_public_revision\n        # If on of the translations has no major public revision, it cannot be outdated\n        if not self_revision or not source_revision:\n            return False\n        return self_revision.last_updated < source_revision.last_updated\n\n    @property\n    def combined_text(self):\n        \"\"\"\n        Combines the text from the PageTranslation with the text from the mirrored page.\n        \"\"\"\n        if self.page.mirrored_page_first:\n            return self.page.get_mirrored_text(self.language.code) + self.text\n        return self.text + self.page.get_mirrored_text(self.language.code)\n\n    def __str__(self):\n        if self.id:\n            return '(id: {}, lang: {}, slug: {})'.format(self.id, self.language.code, self.slug)\n        return super(PageTranslation, self).__str__()\n\n    class Meta:\n        ordering = ['page', '-version']\n        default_permissions = ()\n", "path": "backend/cms/models/pages/page_translation.py"}], "after_files": [{"content": "\"\"\"Models representing a page and page translation with content\n\"\"\"\nimport logging\n\nfrom django.conf import settings\nfrom django.db import models\nfrom django.urls import reverse\nfrom django.utils import timezone\nfrom django.utils.translation import get_language\n\nfrom mptt.models import MPTTModel, TreeForeignKey\n\nfrom ..regions.region import Region\nfrom ...constants import status\n\nlogger = logging.getLogger(__name__)\n\n\nclass Page(MPTTModel):\n    \"\"\"Class that represents an Page database object\n\n    Args:\n        MPTTModel : Library for hierachical data structures\n    \"\"\"\n\n    parent = TreeForeignKey(\n        'self',\n        blank=True,\n        null=True,\n        related_name='children',\n        on_delete=models.PROTECT\n    )\n    icon = models.ImageField(\n        blank=True,\n        null=True,\n        upload_to='pages/%Y/%m/%d'\n    )\n    region = models.ForeignKey(Region, related_name='pages', on_delete=models.CASCADE)\n    archived = models.BooleanField(default=False)\n    mirrored_page = models.ForeignKey('self', null=True, blank=True, on_delete=models.PROTECT)\n    mirrored_page_first = models.BooleanField(default=True, null=True, blank=True)\n    editors = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='editors', blank=True)\n    publishers = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='publishers', blank=True)\n    created_date = models.DateTimeField(default=timezone.now)\n    last_updated = models.DateTimeField(auto_now=True)\n\n    @property\n    def depth(self):\n        \"\"\"Provide level of inheritance\n\n        Returns:\n            Int : Number of ancestors\n        \"\"\"\n\n        return len(self.get_ancestors())\n\n    @property\n    def languages(self):\n        page_translations = self.translations.prefetch_related('language').all()\n        languages = []\n        for page_translation in page_translations:\n            if page_translation.language not in languages:\n                languages.append(page_translation.language)\n        return languages\n\n    def get_translation(self, language_code):\n        return self.translations.filter(\n            language__code=language_code\n        ).first()\n\n    # Helper function for page labels, second level paths etc. where the ancestor translation might not exist\n    def get_first_translation(self, priority_language_codes=None):\n        # Taking [] directly as default parameter would be dangerous because it is mutable\n        if not priority_language_codes:\n            priority_language_codes = []\n        for language_code in priority_language_codes + ['en-us', 'de-de']:\n            if self.translations.filter(language__code=language_code).exists():\n                return self.translations.filter(language__code=language_code).first()\n        return self.translations.first()\n\n    def get_public_translation(self, language_code):\n        return self.translations.filter(\n            language__code=language_code,\n            status=status.PUBLIC,\n        ).first()\n\n    def get_mirrored_text(self, language_code):\n        \"\"\"\n        This content needs to be added when delivering content to end users\n        \"\"\"\n        if self.mirrored_page:\n            return self.mirrored_page.get_translation(language_code).text\n        return None\n\n    def get_absolute_url(self):\n        return reverse('edit_page', kwargs={\n            'page_id': self.id,\n            'region_slug': self.region.slug,\n            'language_code': self.region.default_language.code,\n        })\n\n    @staticmethod\n    def get_archived(region_slug):\n        return Page.objects.filter(archived=True, region__slug=region_slug)\n\n    @staticmethod\n    def archived_count(region_slug):\n        return Page.objects.filter(archived=True, region__slug=region_slug).count()\n\n    def __str__(self):\n        if self.id:\n            first_translation = self.get_first_translation()\n            if first_translation:\n                return '(id: {}, slug: {} ({}))'.format(self.id, first_translation.slug, first_translation.language.code)\n            return '(id: {})'.format(self.id)\n        return super(Page, self).__str__()\n\n    @classmethod\n    def get_tree(cls, region_slug, archived=False):\n        \"\"\"Function for building up a Treeview of all pages\n\n        Args:\n            region_slug: slug of the region the page belongs to\n            archived:  if true archived pages will be included\n\n        Returns:\n            [pages]: Array of pages connected with their relations\n        \"\"\"\n\n        return cls.objects.all().prefetch_related(\n            'translations'\n        ).filter(\n            region__slug=region_slug,\n            archived=archived\n        )\n\n    def best_language_title(self):\n        page_translation = self.translations.filter(language__code=get_language())\n        if not page_translation:\n            alt_code = self.region.default_language.code\n            page_translation = self.translations.filter(language__code=alt_code)\n        return page_translation.first().title\n\n    class Meta:\n        default_permissions = ()\n        permissions = (\n            ('view_pages', 'Can view pages'),\n            ('edit_pages', 'Can edit pages'),\n            ('publish_pages', 'Can publish pages'),\n            ('grant_page_permissions', 'Can grant page permissions'),\n        )\n", "path": "backend/cms/models/pages/page.py"}, {"content": "from django.http import JsonResponse\n\nfrom cms.models import Region\n\n\ndef transform_page(page_translation):\n    if page_translation.page.parent:\n        parent = {\n            'id': page_translation.page.parent.id,\n            'url': page_translation.page.parent.get_translation(\n                page_translation.language.code\n            ).permalink,\n            'path': page_translation.page.parent.get_translation(\n                page_translation.language.code\n            ).slug,\n        }\n    else:\n        parent = None\n    return {\n        'id': page_translation.id,\n        'url': page_translation.permalink,\n        'path': page_translation.slug,\n        'title': page_translation.title,\n        'modified_gmt': page_translation.last_updated,\n        'excerpt': page_translation.text,\n        'content': page_translation.combined_text,\n        'parent': parent,\n        'order': page_translation.page.lft, # use left edge indicator of mptt model for order\n        'available_languages': page_translation.available_languages,\n        'thumbnail': None,\n        'hash': None\n    }\n\ndef pages(request, region_slug, language_code):\n    region = Region.objects.get(slug=region_slug)\n    result = []\n    for page in region.pages.all():\n        page_translation = page.get_public_translation(language_code)\n        if page_translation:\n            result.append(transform_page(page_translation))\n    return JsonResponse(result, safe=False)  # Turn off Safe-Mode to allow serializing arrays\n", "path": "backend/api/v3/pages.py"}, {"content": "\"\"\"Models representing a page and page translation with content\n\"\"\"\nimport logging\n\nfrom django.conf import settings\nfrom django.db import models\nfrom django.utils import timezone\n\nfrom .page import Page\nfrom ..languages.language import Language\nfrom ...constants import status\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass PageTranslation(models.Model):\n    \"\"\"Class defining a Translation of a Page\n\n    Args:\n        models : Class inherit of django-Models\n    \"\"\"\n\n    page = models.ForeignKey(Page, related_name='translations', on_delete=models.CASCADE)\n    language = models.ForeignKey(\n        Language,\n        related_name='page_translations',\n        on_delete=models.CASCADE\n    )\n    slug = models.SlugField(max_length=200, blank=True, allow_unicode=True)\n    title = models.CharField(max_length=250)\n    text = models.TextField(blank=True)\n    status = models.CharField(max_length=6, choices=status.CHOICES, default=status.DRAFT)\n    currently_in_translation = models.BooleanField(default=False)\n    version = models.PositiveIntegerField(default=0)\n    minor_edit = models.BooleanField(default=False)\n    creator = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.SET_NULL)\n    created_date = models.DateTimeField(default=timezone.now)\n    last_updated = models.DateTimeField(auto_now=True)\n\n    @property\n    def foreign_object(self):\n        return self.page\n\n    @property\n    def ancestor_path(self):\n        return '/'.join([\n            ancestor.get_first_translation([self.language.code]).slug\n            for ancestor in self.page.get_ancestors()\n        ])\n\n    @property\n    def permalink(self):\n        return '/'.join(filter(None, [\n            self.page.region.slug,\n            self.language.code,\n            self.ancestor_path,\n            self.slug\n        ]))\n\n    @property\n    def available_languages(self):\n        languages = self.page.languages\n        languages.remove(self.language)\n        available_languages = {}\n        for language in languages:\n            other_translation = self.page.get_public_translation(language.code)\n            if other_translation:\n                available_languages[language.code] = {\n                    'id': other_translation.id,\n                    'url': other_translation.permalink\n                }\n        return available_languages\n\n    @property\n    def source_translation(self):\n        source_language_tree_node = self.page.region.language_tree_nodes.get(language=self.language).parent\n        if source_language_tree_node:\n            return self.page.get_translation(source_language_tree_node.code)\n        return None\n\n    @property\n    def latest_public_revision(self):\n        return self.page.translations.filter(\n            language=self.language,\n            status=status.PUBLIC,\n        ).first()\n\n    @property\n    def latest_major_revision(self):\n        return self.page.translations.filter(\n            language=self.language,\n            minor_edit=False,\n        ).first()\n\n    @property\n    def latest_major_public_revision(self):\n        return self.page.translations.filter(\n            language=self.language,\n            status=status.PUBLIC,\n            minor_edit=False,\n        ).first()\n\n    @property\n    def previous_revision(self):\n        version = self.version - 1\n        return self.page.translations.filter(\n            language=self.language,\n            version=version,\n        ).first()\n\n    @property\n    def is_outdated(self):\n        source_translation = self.source_translation\n        # If self.language is the root language, this translation can never be outdated\n        if not source_translation:\n            return False\n        # If the source translation is outdated, this translation can not be up to date\n        if source_translation.is_outdated:\n            return True\n        self_revision = self.latest_major_public_revision\n        source_revision = source_translation.latest_major_public_revision\n        # If on of the translations has no major public revision, it cannot be outdated\n        if not self_revision or not source_revision:\n            return False\n        return self_revision.last_updated < source_revision.last_updated\n\n    @property\n    def combined_text(self):\n        \"\"\"\n        Combines the text from the PageTranslation with the text from the mirrored page.\n        \"\"\"\n        attached_text = self.page.get_mirrored_text(self.language.code)\n        if attached_text is None:\n            return self.text\n        if self.page.mirrored_page_first:\n            return attached_text + self.text\n        return self.text + attached_text\n\n    def __str__(self):\n        if self.id:\n            return '(id: {}, lang: {}, slug: {})'.format(self.id, self.language.code, self.slug)\n        return super(PageTranslation, self).__str__()\n\n    class Meta:\n        ordering = ['page', '-version']\n        default_permissions = ()\n", "path": "backend/cms/models/pages/page_translation.py"}]}