We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Autosave changes unversioned `Page` model
### Describe the Bug
<!-- A clear and concise description of what the bug is. -->
When an autosave is triggered, the complete `Page` and `PageTranslation` model instances are saved.
Since just the `PageTranslation` is versioned, this might lead to unexpected changes on public pages.

### Steps to Reproduce

1. Go to a page form
2. Edit something in the content textarea to trigger the tinymce autosave
3. Change some field in the page form, e.g. embed live content
4. Wait for the autosave to get triggered
5. Return without saving

### Expected Behavior
<!-- A clear and concise description of what you expected to happen. -->
All page fields should be unchanged, since they are not versioned and there is no backup of the "public" state. If the page field is exited without saving, the page model instance should be exactly the same as before.

### Actual Behavior
<!-- A clear and concise description of what actually happened. -->
All fields are automatically saved and the page instance is saved as well.

### Additional Information
<!-- Add any other context (e.g. logs, screenshots, etc.) about the problem here. -->
Probably, this can be solved by limiting the `FormData` in [src/frontend/js/forms/autosave.ts](https://github.com/Integreat/integreat-cms/blob/8219586acbb98c681635210d0c45817285a0c13e/src/frontend/js/forms/autosave.ts#L7) so only the fields `slug`, `title` and `text`/`description` are saved.
_Edit:_ Probably not, since this would cause the validation to fail or remove specific values... so maybe we need a completely new view for the autosave?

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/cms/views/pages/page_view.py`
Content:
```
1 import logging
2 
3 from django.contrib import messages
4 from django.contrib.auth.decorators import login_required
5 from django.core.exceptions import PermissionDenied
6 from django.shortcuts import render, redirect, get_object_or_404
7 from django.urls import reverse
8 from django.utils.decorators import method_decorator
9 from django.utils.translation import ugettext as _
10 from django.views.generic import TemplateView
11 
12 from ...constants import status, text_directions
13 from ...decorators import region_permission_required, permission_required
14 from ...forms import PageForm, PageTranslationForm
15 from ...models import PageTranslation, Region
16 from .page_context_mixin import PageContextMixin
17 from ..media.media_context_mixin import MediaContextMixin
18 
19 logger = logging.getLogger(__name__)
20 
21 
22 @method_decorator(login_required, name="dispatch")
23 @method_decorator(region_permission_required, name="dispatch")
24 @method_decorator(permission_required("cms.view_page"), name="dispatch")
25 class PageView(TemplateView, PageContextMixin, MediaContextMixin):
26     """
27     View for the page form and page translation form
28     """
29 
30     #: The template to render (see :class:`~django.views.generic.base.TemplateResponseMixin`)
31     template_name = "pages/page_form.html"
32     #: The context dict passed to the template (see :class:`~django.views.generic.base.ContextMixin`)
33     base_context = {
34         "current_menu_item": "new_page",
35         "PUBLIC": status.PUBLIC,
36     }
37 
38     # pylint: disable=too-many-locals
39     def get(self, request, *args, **kwargs):
40         """
41         Render :class:`~cms.forms.pages.page_form.PageForm` and :class:`~cms.forms.pages.page_translation_form.PageTranslationForm`
42 
43         :param request: The current request
44         :type request: ~django.http.HttpResponse
45 
46         :param args: The supplied arguments
47         :type args: list
48 
49         :param kwargs: The supplied keyword arguments
50         :type kwargs: dict
51 
52         :raises ~django.core.exceptions.PermissionDenied: If user does not have the permission to edit the specific page
53 
54         :return: The rendered template response
55         :rtype: ~django.template.response.TemplateResponse
56         """
57 
58         region = Region.get_current_region(request)
59         language = get_object_or_404(region.languages, slug=kwargs.get("language_slug"))
60 
61         # get page and translation objects if they exist
62         page = region.pages.filter(id=kwargs.get("page_id")).first()
63         page_translation = PageTranslation.objects.filter(
64             page=page,
65             language=language,
66         ).first()
67 
68         disabled = False
69         if page:
70             # Make form disabled if page is archived
71             if page.explicitly_archived:
72                 disabled = True
73                 messages.warning(
74                     request, _("You cannot edit this page because it is archived.")
75                 )
76             elif page.implicitly_archived:
77                 disabled = True
78                 messages.warning(
79                     request,
80                     _(
81                         "You cannot edit this page, because one of its parent pages is archived and therefore, this page is archived as well."
82                     ),
83                 )
84             # Show information if latest changes are only saved as draft
85             public_translation = page.get_public_translation(language.slug)
86             if public_translation and page_translation != public_translation:
87                 messages.info(
88                     request,
89                     _(
90                         "The latest changes have only been saved as a draft. Currently, <a href='%(revision_url)s' class='underline hover:no-underline'>version %(revision)s</a> of this page is displayed in the app."
91                     )
92                     % {
93                         "revision_url": reverse(
94                             "page_revisions",
95                             kwargs={
96                                 "region_slug": region.slug,
97                                 "language_slug": language.slug,
98                                 "page_id": page.id,
99                                 "selected_revision": public_translation.version,
100                             },
101                         ),
102                         "revision": public_translation.version,
103                     },
104                 )
105 
106         # Make form disabled if user has no permission to edit the page
107         if not request.user.has_perm("cms.change_page_object", page):
108             disabled = True
109             messages.warning(
110                 request,
111                 _("You don't have the permission to edit this page."),
112             )
113         # Show warning if user has no permission to publish the page
114         if not request.user.has_perm("cms.publish_page_object", page):
115             messages.warning(
116                 request,
117                 _(
118                     "You don't have the permission to publish this page, but you can propose changes and submit them for review instead."
119                 ),
120             )
121 
122         page_form = PageForm(
123             instance=page,
124             disabled=disabled,
125             additional_instance_attributes={
126                 "region": region,
127             },
128         )
129         page_translation_form = PageTranslationForm(
130             instance=page_translation, disabled=disabled
131         )
132 
133         # Pass side by side language options
134         side_by_side_language_options = self.get_side_by_side_language_options(
135             region, language, page
136         )
137 
138         # Pass siblings to template to enable rendering of page order table
139         if not page or not page.parent:
140             siblings = region.pages.filter(level=0)
141         else:
142             siblings = page.parent.children.all()
143         context = self.get_context_data(**kwargs)
144         return render(
145             request,
146             self.template_name,
147             {
148                 **self.base_context,
149                 **context,
150                 "page_form": page_form,
151                 "page_translation_form": page_translation_form,
152                 "page": page,
153                 "siblings": siblings,
154                 "language": language,
155                 # Languages for tab view
156                 "languages": region.languages if page else [language],
157                 "side_by_side_language_options": side_by_side_language_options,
158                 "right_to_left": (
159                     language.text_direction == text_directions.RIGHT_TO_LEFT
160                 ),
161             },
162         )
163 
164     # pylint: disable=too-many-branches,unused-argument
165     def post(self, request, *args, **kwargs):
166         """
167         Submit :class:`~cms.forms.pages.page_form.PageForm` and
168         :class:`~cms.forms.pages.page_translation_form.PageTranslationForm` and save :class:`~cms.models.pages.page.Page`
169         and :class:`~cms.models.pages.page_translation.PageTranslation` objects.
170         Forms containing images/files need to be additionally instantiated with the FILES attribute of request objects,
171         see :doc:`django:topics/http/file-uploads`
172 
173         :param request: The current request
174         :type request: ~django.http.HttpResponse
175 
176         :param args: The supplied arguments
177         :type args: list
178 
179         :param kwargs: The supplied keyword arguments
180         :type kwargs: dict
181 
182         :raises ~django.core.exceptions.PermissionDenied: If user does not have the permission to edit the specific page
183 
184         :return: The rendered template response
185         :rtype: ~django.template.response.TemplateResponse
186         """
187 
188         region = Region.get_current_region(request)
189         language = get_object_or_404(region.languages, slug=kwargs.get("language_slug"))
190 
191         page_instance = region.pages.filter(id=kwargs.get("page_id")).first()
192 
193         if not request.user.has_perm("cms.change_page_object", page_instance):
194             raise PermissionDenied(
195                 f"{request.user.profile!r} does not have the permission to edit {page_instance!r}"
196             )
197 
198         page_translation_instance = PageTranslation.objects.filter(
199             page=page_instance,
200             language=language,
201         ).first()
202 
203         # Pass siblings to template to enable rendering of page order table
204         if not page_instance or not page_instance.parent:
205             siblings = region.pages.filter(level=0)
206         else:
207             siblings = page_instance.parent.children.all()
208 
209         page_form = PageForm(
210             data=request.POST,
211             files=request.FILES,
212             instance=page_instance,
213             additional_instance_attributes={
214                 "region": region,
215             },
216         )
217         page_translation_form = PageTranslationForm(
218             data=request.POST,
219             instance=page_translation_instance,
220             additional_instance_attributes={
221                 "creator": request.user,
222                 "language": language,
223                 "page": page_form.instance,
224             },
225         )
226 
227         if not page_form.is_valid() or not page_translation_form.is_valid():
228             # Add error messages
229             page_form.add_error_messages(request)
230             page_translation_form.add_error_messages(request)
231         elif (
232             not request.user.has_perm("cms.publish_page_object", page_form.instance)
233             and page_translation_form.cleaned_data.get("status") == status.PUBLIC
234         ):
235             # Raise PermissionDenied if user wants to publish page but doesn't have the permission
236             raise PermissionDenied(
237                 f"{request.user.profile!r} does not have the permission to publish {page_form.instance!r}"
238             )
239         elif (
240             page_translation_form.instance.status == status.AUTO_SAVE
241             and not page_form.has_changed()
242             and not page_translation_form.has_changed()
243         ):
244             messages.info(request, _("No changes detected, autosave skipped"))
245 
246         else:
247             # Save forms
248             page_translation_form.instance.page = page_form.save()
249             page_translation_form.save()
250             # Add the success message and redirect to the edit page
251             if not page_instance:
252                 messages.success(
253                     request,
254                     _('Page "{}" was successfully created').format(
255                         page_translation_form.instance.title
256                     ),
257                 )
258                 return redirect(
259                     "edit_page",
260                     **{
261                         "page_id": page_form.instance.id,
262                         "region_slug": region.slug,
263                         "language_slug": language.slug,
264                     },
265                 )
266 
267             if not page_form.has_changed() and not page_translation_form.has_changed():
268                 messages.info(request, _("No changes detected, but date refreshed"))
269             else:
270                 # Add the success message
271                 page_translation_form.add_success_message(request)
272 
273         return render(
274             request,
275             self.template_name,
276             {
277                 **self.base_context,
278                 "page_form": page_form,
279                 "page_translation_form": page_translation_form,
280                 "page": page_instance,
281                 "siblings": siblings,
282                 "language": language,
283                 # Languages for tab view
284                 "languages": region.languages if page_instance else [language],
285                 "side_by_side_language_options": self.get_side_by_side_language_options(
286                     region, language, page_instance
287                 ),
288                 "right_to_left": (
289                     language.text_direction == text_directions.RIGHT_TO_LEFT
290                 ),
291             },
292         )
293 
294     @staticmethod
295     def get_side_by_side_language_options(region, language, page):
296         """
297         This is a helper function to generate the side-by-side language options for both the get and post requests.
298 
299         :param region: The current region
300         :type region: ~cms.models.regions.region.Region
301 
302         :param language: The current language
303         :type language: ~cms.models.languages.language.Language
304 
305         :param page: The current page
306         :type page: ~cms.models.pages.page.Page
307 
308         :return: The list of language options, each represented by a dict
309         :rtype: list
310         """
311 
312         side_by_side_language_options = []
313         for language_node in region.language_tree_nodes.all():
314             if language_node.parent:
315                 source_translation = PageTranslation.objects.filter(
316                     page=page,
317                     language=language_node.parent.language,
318                 )
319                 side_by_side_language_options.append(
320                     {
321                         "value": language_node.language.slug,
322                         "label": _("{source_language} to {target_language}").format(
323                             source_language=language_node.parent.language.translated_name,
324                             target_language=language_node.language.translated_name,
325                         ),
326                         "selected": language_node.language == language,
327                         "disabled": not source_translation.exists(),
328                     }
329                 )
330         return side_by_side_language_options
331
```
--- 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/src/cms/views/pages/page_view.py b/src/cms/views/pages/page_view.py
--- a/src/cms/views/pages/page_view.py
+++ b/src/cms/views/pages/page_view.py
@@ -244,8 +244,13 @@
             messages.info(request, _("No changes detected, autosave skipped"))
 
         else:
-            # Save forms
-            page_translation_form.instance.page = page_form.save()
+            # Only save page form if page does not yet exist or if translation is no auto save
+            if (
+                not page_instance
+                or page_translation_form.instance.status != status.AUTO_SAVE
+            ):
+                page_translation_form.instance.page = page_form.save()
+            # Save page translation form
             page_translation_form.save()
             # Add the success message and redirect to the edit page
             if not page_instance:

{"golden_diff": "diff --git a/src/cms/views/pages/page_view.py b/src/cms/views/pages/page_view.py\n--- a/src/cms/views/pages/page_view.py\n+++ b/src/cms/views/pages/page_view.py\n@@ -244,8 +244,13 @@\n             messages.info(request, _(\"No changes detected, autosave skipped\"))\n \n         else:\n-            # Save forms\n-            page_translation_form.instance.page = page_form.save()\n+            # Only save page form if page does not yet exist or if translation is no auto save\n+            if (\n+                not page_instance\n+                or page_translation_form.instance.status != status.AUTO_SAVE\n+            ):\n+                page_translation_form.instance.page = page_form.save()\n+            # Save page translation form\n             page_translation_form.save()\n             # Add the success message and redirect to the edit page\n             if not page_instance:\n", "issue": "Autosave changes unversioned `Page` model\n### Describe the Bug\r\n<!-- A clear and concise description of what the bug is. -->\r\nWhen an autosave is triggered, the complete `Page` and `PageTranslation` model instances are saved.\r\nSince just the `PageTranslation` is versioned, this might lead to unexpected changes on public pages.\r\n\r\n### Steps to Reproduce\r\n\r\n1. Go to a page form\r\n2. Edit something in the content textarea to trigger the tinymce autosave\r\n3. Change some field in the page form, e.g. embed live content\r\n4. Wait for the autosave to get triggered\r\n5. Return without saving\r\n\r\n### Expected Behavior\r\n<!-- A clear and concise description of what you expected to happen. -->\r\nAll page fields should be unchanged, since they are not versioned and there is no backup of the \"public\" state. If the page field is exited without saving, the page model instance should be exactly the same as before.\r\n\r\n### Actual Behavior\r\n<!-- A clear and concise description of what actually happened. -->\r\nAll fields are automatically saved and the page instance is saved as well.\r\n\r\n### Additional Information\r\n<!-- Add any other context (e.g. logs, screenshots, etc.) about the problem here. -->\r\nProbably, this can be solved by limiting the `FormData` in [src/frontend/js/forms/autosave.ts](https://github.com/Integreat/integreat-cms/blob/8219586acbb98c681635210d0c45817285a0c13e/src/frontend/js/forms/autosave.ts#L7) so only the fields `slug`, `title` and `text`/`description` are saved.\r\n_Edit:_ Probably not, since this would cause the validation to fail or remove specific values... so maybe we need a completely new view for the autosave?\n", "before_files": [{"content": "import logging\n\nfrom django.contrib import messages\nfrom django.contrib.auth.decorators import login_required\nfrom django.core.exceptions import PermissionDenied\nfrom django.shortcuts import render, redirect, get_object_or_404\nfrom django.urls import reverse\nfrom django.utils.decorators import method_decorator\nfrom django.utils.translation import ugettext as _\nfrom django.views.generic import TemplateView\n\nfrom ...constants import status, text_directions\nfrom ...decorators import region_permission_required, permission_required\nfrom ...forms import PageForm, PageTranslationForm\nfrom ...models import PageTranslation, Region\nfrom .page_context_mixin import PageContextMixin\nfrom ..media.media_context_mixin import MediaContextMixin\n\nlogger = logging.getLogger(__name__)\n\n\n@method_decorator(login_required, name=\"dispatch\")\n@method_decorator(region_permission_required, name=\"dispatch\")\n@method_decorator(permission_required(\"cms.view_page\"), name=\"dispatch\")\nclass PageView(TemplateView, PageContextMixin, MediaContextMixin):\n    \"\"\"\n    View for the page form and page translation form\n    \"\"\"\n\n    #: The template to render (see :class:`~django.views.generic.base.TemplateResponseMixin`)\n    template_name = \"pages/page_form.html\"\n    #: The context dict passed to the template (see :class:`~django.views.generic.base.ContextMixin`)\n    base_context = {\n        \"current_menu_item\": \"new_page\",\n        \"PUBLIC\": status.PUBLIC,\n    }\n\n    # pylint: disable=too-many-locals\n    def get(self, request, *args, **kwargs):\n        \"\"\"\n        Render :class:`~cms.forms.pages.page_form.PageForm` and :class:`~cms.forms.pages.page_translation_form.PageTranslationForm`\n\n        :param request: The current request\n        :type request: ~django.http.HttpResponse\n\n        :param args: The supplied arguments\n        :type args: list\n\n        :param kwargs: The supplied keyword arguments\n        :type kwargs: dict\n\n        :raises ~django.core.exceptions.PermissionDenied: If user does not have the permission to edit the specific page\n\n        :return: The rendered template response\n        :rtype: ~django.template.response.TemplateResponse\n        \"\"\"\n\n        region = Region.get_current_region(request)\n        language = get_object_or_404(region.languages, slug=kwargs.get(\"language_slug\"))\n\n        # get page and translation objects if they exist\n        page = region.pages.filter(id=kwargs.get(\"page_id\")).first()\n        page_translation = PageTranslation.objects.filter(\n            page=page,\n            language=language,\n        ).first()\n\n        disabled = False\n        if page:\n            # Make form disabled if page is archived\n            if page.explicitly_archived:\n                disabled = True\n                messages.warning(\n                    request, _(\"You cannot edit this page because it is archived.\")\n                )\n            elif page.implicitly_archived:\n                disabled = True\n                messages.warning(\n                    request,\n                    _(\n                        \"You cannot edit this page, because one of its parent pages is archived and therefore, this page is archived as well.\"\n                    ),\n                )\n            # Show information if latest changes are only saved as draft\n            public_translation = page.get_public_translation(language.slug)\n            if public_translation and page_translation != public_translation:\n                messages.info(\n                    request,\n                    _(\n                        \"The latest changes have only been saved as a draft. Currently, <a href='%(revision_url)s' class='underline hover:no-underline'>version %(revision)s</a> of this page is displayed in the app.\"\n                    )\n                    % {\n                        \"revision_url\": reverse(\n                            \"page_revisions\",\n                            kwargs={\n                                \"region_slug\": region.slug,\n                                \"language_slug\": language.slug,\n                                \"page_id\": page.id,\n                                \"selected_revision\": public_translation.version,\n                            },\n                        ),\n                        \"revision\": public_translation.version,\n                    },\n                )\n\n        # Make form disabled if user has no permission to edit the page\n        if not request.user.has_perm(\"cms.change_page_object\", page):\n            disabled = True\n            messages.warning(\n                request,\n                _(\"You don't have the permission to edit this page.\"),\n            )\n        # Show warning if user has no permission to publish the page\n        if not request.user.has_perm(\"cms.publish_page_object\", page):\n            messages.warning(\n                request,\n                _(\n                    \"You don't have the permission to publish this page, but you can propose changes and submit them for review instead.\"\n                ),\n            )\n\n        page_form = PageForm(\n            instance=page,\n            disabled=disabled,\n            additional_instance_attributes={\n                \"region\": region,\n            },\n        )\n        page_translation_form = PageTranslationForm(\n            instance=page_translation, disabled=disabled\n        )\n\n        # Pass side by side language options\n        side_by_side_language_options = self.get_side_by_side_language_options(\n            region, language, page\n        )\n\n        # Pass siblings to template to enable rendering of page order table\n        if not page or not page.parent:\n            siblings = region.pages.filter(level=0)\n        else:\n            siblings = page.parent.children.all()\n        context = self.get_context_data(**kwargs)\n        return render(\n            request,\n            self.template_name,\n            {\n                **self.base_context,\n                **context,\n                \"page_form\": page_form,\n                \"page_translation_form\": page_translation_form,\n                \"page\": page,\n                \"siblings\": siblings,\n                \"language\": language,\n                # Languages for tab view\n                \"languages\": region.languages if page else [language],\n                \"side_by_side_language_options\": side_by_side_language_options,\n                \"right_to_left\": (\n                    language.text_direction == text_directions.RIGHT_TO_LEFT\n                ),\n            },\n        )\n\n    # pylint: disable=too-many-branches,unused-argument\n    def post(self, request, *args, **kwargs):\n        \"\"\"\n        Submit :class:`~cms.forms.pages.page_form.PageForm` and\n        :class:`~cms.forms.pages.page_translation_form.PageTranslationForm` and save :class:`~cms.models.pages.page.Page`\n        and :class:`~cms.models.pages.page_translation.PageTranslation` objects.\n        Forms containing images/files need to be additionally instantiated with the FILES attribute of request objects,\n        see :doc:`django:topics/http/file-uploads`\n\n        :param request: The current request\n        :type request: ~django.http.HttpResponse\n\n        :param args: The supplied arguments\n        :type args: list\n\n        :param kwargs: The supplied keyword arguments\n        :type kwargs: dict\n\n        :raises ~django.core.exceptions.PermissionDenied: If user does not have the permission to edit the specific page\n\n        :return: The rendered template response\n        :rtype: ~django.template.response.TemplateResponse\n        \"\"\"\n\n        region = Region.get_current_region(request)\n        language = get_object_or_404(region.languages, slug=kwargs.get(\"language_slug\"))\n\n        page_instance = region.pages.filter(id=kwargs.get(\"page_id\")).first()\n\n        if not request.user.has_perm(\"cms.change_page_object\", page_instance):\n            raise PermissionDenied(\n                f\"{request.user.profile!r} does not have the permission to edit {page_instance!r}\"\n            )\n\n        page_translation_instance = PageTranslation.objects.filter(\n            page=page_instance,\n            language=language,\n        ).first()\n\n        # Pass siblings to template to enable rendering of page order table\n        if not page_instance or not page_instance.parent:\n            siblings = region.pages.filter(level=0)\n        else:\n            siblings = page_instance.parent.children.all()\n\n        page_form = PageForm(\n            data=request.POST,\n            files=request.FILES,\n            instance=page_instance,\n            additional_instance_attributes={\n                \"region\": region,\n            },\n        )\n        page_translation_form = PageTranslationForm(\n            data=request.POST,\n            instance=page_translation_instance,\n            additional_instance_attributes={\n                \"creator\": request.user,\n                \"language\": language,\n                \"page\": page_form.instance,\n            },\n        )\n\n        if not page_form.is_valid() or not page_translation_form.is_valid():\n            # Add error messages\n            page_form.add_error_messages(request)\n            page_translation_form.add_error_messages(request)\n        elif (\n            not request.user.has_perm(\"cms.publish_page_object\", page_form.instance)\n            and page_translation_form.cleaned_data.get(\"status\") == status.PUBLIC\n        ):\n            # Raise PermissionDenied if user wants to publish page but doesn't have the permission\n            raise PermissionDenied(\n                f\"{request.user.profile!r} does not have the permission to publish {page_form.instance!r}\"\n            )\n        elif (\n            page_translation_form.instance.status == status.AUTO_SAVE\n            and not page_form.has_changed()\n            and not page_translation_form.has_changed()\n        ):\n            messages.info(request, _(\"No changes detected, autosave skipped\"))\n\n        else:\n            # Save forms\n            page_translation_form.instance.page = page_form.save()\n            page_translation_form.save()\n            # Add the success message and redirect to the edit page\n            if not page_instance:\n                messages.success(\n                    request,\n                    _('Page \"{}\" was successfully created').format(\n                        page_translation_form.instance.title\n                    ),\n                )\n                return redirect(\n                    \"edit_page\",\n                    **{\n                        \"page_id\": page_form.instance.id,\n                        \"region_slug\": region.slug,\n                        \"language_slug\": language.slug,\n                    },\n                )\n\n            if not page_form.has_changed() and not page_translation_form.has_changed():\n                messages.info(request, _(\"No changes detected, but date refreshed\"))\n            else:\n                # Add the success message\n                page_translation_form.add_success_message(request)\n\n        return render(\n            request,\n            self.template_name,\n            {\n                **self.base_context,\n                \"page_form\": page_form,\n                \"page_translation_form\": page_translation_form,\n                \"page\": page_instance,\n                \"siblings\": siblings,\n                \"language\": language,\n                # Languages for tab view\n                \"languages\": region.languages if page_instance else [language],\n                \"side_by_side_language_options\": self.get_side_by_side_language_options(\n                    region, language, page_instance\n                ),\n                \"right_to_left\": (\n                    language.text_direction == text_directions.RIGHT_TO_LEFT\n                ),\n            },\n        )\n\n    @staticmethod\n    def get_side_by_side_language_options(region, language, page):\n        \"\"\"\n        This is a helper function to generate the side-by-side language options for both the get and post requests.\n\n        :param region: The current region\n        :type region: ~cms.models.regions.region.Region\n\n        :param language: The current language\n        :type language: ~cms.models.languages.language.Language\n\n        :param page: The current page\n        :type page: ~cms.models.pages.page.Page\n\n        :return: The list of language options, each represented by a dict\n        :rtype: list\n        \"\"\"\n\n        side_by_side_language_options = []\n        for language_node in region.language_tree_nodes.all():\n            if language_node.parent:\n                source_translation = PageTranslation.objects.filter(\n                    page=page,\n                    language=language_node.parent.language,\n                )\n                side_by_side_language_options.append(\n                    {\n                        \"value\": language_node.language.slug,\n                        \"label\": _(\"{source_language} to {target_language}\").format(\n                            source_language=language_node.parent.language.translated_name,\n                            target_language=language_node.language.translated_name,\n                        ),\n                        \"selected\": language_node.language == language,\n                        \"disabled\": not source_translation.exists(),\n                    }\n                )\n        return side_by_side_language_options\n", "path": "src/cms/views/pages/page_view.py"}], "after_files": [{"content": "import logging\n\nfrom django.contrib import messages\nfrom django.contrib.auth.decorators import login_required\nfrom django.core.exceptions import PermissionDenied\nfrom django.shortcuts import render, redirect, get_object_or_404\nfrom django.urls import reverse\nfrom django.utils.decorators import method_decorator\nfrom django.utils.translation import ugettext as _\nfrom django.views.generic import TemplateView\n\nfrom ...constants import status, text_directions\nfrom ...decorators import region_permission_required, permission_required\nfrom ...forms import PageForm, PageTranslationForm\nfrom ...models import PageTranslation, Region\nfrom .page_context_mixin import PageContextMixin\nfrom ..media.media_context_mixin import MediaContextMixin\n\nlogger = logging.getLogger(__name__)\n\n\n@method_decorator(login_required, name=\"dispatch\")\n@method_decorator(region_permission_required, name=\"dispatch\")\n@method_decorator(permission_required(\"cms.view_page\"), name=\"dispatch\")\nclass PageView(TemplateView, PageContextMixin, MediaContextMixin):\n    \"\"\"\n    View for the page form and page translation form\n    \"\"\"\n\n    #: The template to render (see :class:`~django.views.generic.base.TemplateResponseMixin`)\n    template_name = \"pages/page_form.html\"\n    #: The context dict passed to the template (see :class:`~django.views.generic.base.ContextMixin`)\n    base_context = {\n        \"current_menu_item\": \"new_page\",\n        \"PUBLIC\": status.PUBLIC,\n    }\n\n    # pylint: disable=too-many-locals\n    def get(self, request, *args, **kwargs):\n        \"\"\"\n        Render :class:`~cms.forms.pages.page_form.PageForm` and :class:`~cms.forms.pages.page_translation_form.PageTranslationForm`\n\n        :param request: The current request\n        :type request: ~django.http.HttpResponse\n\n        :param args: The supplied arguments\n        :type args: list\n\n        :param kwargs: The supplied keyword arguments\n        :type kwargs: dict\n\n        :raises ~django.core.exceptions.PermissionDenied: If user does not have the permission to edit the specific page\n\n        :return: The rendered template response\n        :rtype: ~django.template.response.TemplateResponse\n        \"\"\"\n\n        region = Region.get_current_region(request)\n        language = get_object_or_404(region.languages, slug=kwargs.get(\"language_slug\"))\n\n        # get page and translation objects if they exist\n        page = region.pages.filter(id=kwargs.get(\"page_id\")).first()\n        page_translation = PageTranslation.objects.filter(\n            page=page,\n            language=language,\n        ).first()\n\n        disabled = False\n        if page:\n            # Make form disabled if page is archived\n            if page.explicitly_archived:\n                disabled = True\n                messages.warning(\n                    request, _(\"You cannot edit this page because it is archived.\")\n                )\n            elif page.implicitly_archived:\n                disabled = True\n                messages.warning(\n                    request,\n                    _(\n                        \"You cannot edit this page, because one of its parent pages is archived and therefore, this page is archived as well.\"\n                    ),\n                )\n            # Show information if latest changes are only saved as draft\n            public_translation = page.get_public_translation(language.slug)\n            if public_translation and page_translation != public_translation:\n                messages.info(\n                    request,\n                    _(\n                        \"The latest changes have only been saved as a draft. Currently, <a href='%(revision_url)s' class='underline hover:no-underline'>version %(revision)s</a> of this page is displayed in the app.\"\n                    )\n                    % {\n                        \"revision_url\": reverse(\n                            \"page_revisions\",\n                            kwargs={\n                                \"region_slug\": region.slug,\n                                \"language_slug\": language.slug,\n                                \"page_id\": page.id,\n                                \"selected_revision\": public_translation.version,\n                            },\n                        ),\n                        \"revision\": public_translation.version,\n                    },\n                )\n\n        # Make form disabled if user has no permission to edit the page\n        if not request.user.has_perm(\"cms.change_page_object\", page):\n            disabled = True\n            messages.warning(\n                request,\n                _(\"You don't have the permission to edit this page.\"),\n            )\n        # Show warning if user has no permission to publish the page\n        if not request.user.has_perm(\"cms.publish_page_object\", page):\n            messages.warning(\n                request,\n                _(\n                    \"You don't have the permission to publish this page, but you can propose changes and submit them for review instead.\"\n                ),\n            )\n\n        page_form = PageForm(\n            instance=page,\n            disabled=disabled,\n            additional_instance_attributes={\n                \"region\": region,\n            },\n        )\n        page_translation_form = PageTranslationForm(\n            instance=page_translation, disabled=disabled\n        )\n\n        # Pass side by side language options\n        side_by_side_language_options = self.get_side_by_side_language_options(\n            region, language, page\n        )\n\n        # Pass siblings to template to enable rendering of page order table\n        if not page or not page.parent:\n            siblings = region.pages.filter(level=0)\n        else:\n            siblings = page.parent.children.all()\n        context = self.get_context_data(**kwargs)\n        return render(\n            request,\n            self.template_name,\n            {\n                **self.base_context,\n                **context,\n                \"page_form\": page_form,\n                \"page_translation_form\": page_translation_form,\n                \"page\": page,\n                \"siblings\": siblings,\n                \"language\": language,\n                # Languages for tab view\n                \"languages\": region.languages if page else [language],\n                \"side_by_side_language_options\": side_by_side_language_options,\n                \"right_to_left\": (\n                    language.text_direction == text_directions.RIGHT_TO_LEFT\n                ),\n            },\n        )\n\n    # pylint: disable=too-many-branches,unused-argument\n    def post(self, request, *args, **kwargs):\n        \"\"\"\n        Submit :class:`~cms.forms.pages.page_form.PageForm` and\n        :class:`~cms.forms.pages.page_translation_form.PageTranslationForm` and save :class:`~cms.models.pages.page.Page`\n        and :class:`~cms.models.pages.page_translation.PageTranslation` objects.\n        Forms containing images/files need to be additionally instantiated with the FILES attribute of request objects,\n        see :doc:`django:topics/http/file-uploads`\n\n        :param request: The current request\n        :type request: ~django.http.HttpResponse\n\n        :param args: The supplied arguments\n        :type args: list\n\n        :param kwargs: The supplied keyword arguments\n        :type kwargs: dict\n\n        :raises ~django.core.exceptions.PermissionDenied: If user does not have the permission to edit the specific page\n\n        :return: The rendered template response\n        :rtype: ~django.template.response.TemplateResponse\n        \"\"\"\n\n        region = Region.get_current_region(request)\n        language = get_object_or_404(region.languages, slug=kwargs.get(\"language_slug\"))\n\n        page_instance = region.pages.filter(id=kwargs.get(\"page_id\")).first()\n\n        if not request.user.has_perm(\"cms.change_page_object\", page_instance):\n            raise PermissionDenied(\n                f\"{request.user.profile!r} does not have the permission to edit {page_instance!r}\"\n            )\n\n        page_translation_instance = PageTranslation.objects.filter(\n            page=page_instance,\n            language=language,\n        ).first()\n\n        # Pass siblings to template to enable rendering of page order table\n        if not page_instance or not page_instance.parent:\n            siblings = region.pages.filter(level=0)\n        else:\n            siblings = page_instance.parent.children.all()\n\n        page_form = PageForm(\n            data=request.POST,\n            files=request.FILES,\n            instance=page_instance,\n            additional_instance_attributes={\n                \"region\": region,\n            },\n        )\n        page_translation_form = PageTranslationForm(\n            data=request.POST,\n            instance=page_translation_instance,\n            additional_instance_attributes={\n                \"creator\": request.user,\n                \"language\": language,\n                \"page\": page_form.instance,\n            },\n        )\n\n        if not page_form.is_valid() or not page_translation_form.is_valid():\n            # Add error messages\n            page_form.add_error_messages(request)\n            page_translation_form.add_error_messages(request)\n        elif (\n            not request.user.has_perm(\"cms.publish_page_object\", page_form.instance)\n            and page_translation_form.cleaned_data.get(\"status\") == status.PUBLIC\n        ):\n            # Raise PermissionDenied if user wants to publish page but doesn't have the permission\n            raise PermissionDenied(\n                f\"{request.user.profile!r} does not have the permission to publish {page_form.instance!r}\"\n            )\n        elif (\n            page_translation_form.instance.status == status.AUTO_SAVE\n            and not page_form.has_changed()\n            and not page_translation_form.has_changed()\n        ):\n            messages.info(request, _(\"No changes detected, autosave skipped\"))\n\n        else:\n            # Only save page form if page does not yet exist or if translation is no auto save\n            if (\n                not page_instance\n                or page_translation_form.instance.status != status.AUTO_SAVE\n            ):\n                page_translation_form.instance.page = page_form.save()\n            # Save page translation form\n            page_translation_form.save()\n            # Add the success message and redirect to the edit page\n            if not page_instance:\n                messages.success(\n                    request,\n                    _('Page \"{}\" was successfully created').format(\n                        page_translation_form.instance.title\n                    ),\n                )\n                return redirect(\n                    \"edit_page\",\n                    **{\n                        \"page_id\": page_form.instance.id,\n                        \"region_slug\": region.slug,\n                        \"language_slug\": language.slug,\n                    },\n                )\n\n            if not page_form.has_changed() and not page_translation_form.has_changed():\n                messages.info(request, _(\"No changes detected, but date refreshed\"))\n            else:\n                # Add the success message\n                page_translation_form.add_success_message(request)\n\n        return render(\n            request,\n            self.template_name,\n            {\n                **self.base_context,\n                \"page_form\": page_form,\n                \"page_translation_form\": page_translation_form,\n                \"page\": page_instance,\n                \"siblings\": siblings,\n                \"language\": language,\n                # Languages for tab view\n                \"languages\": region.languages if page_instance else [language],\n                \"side_by_side_language_options\": self.get_side_by_side_language_options(\n                    region, language, page_instance\n                ),\n                \"right_to_left\": (\n                    language.text_direction == text_directions.RIGHT_TO_LEFT\n                ),\n            },\n        )\n\n    @staticmethod\n    def get_side_by_side_language_options(region, language, page):\n        \"\"\"\n        This is a helper function to generate the side-by-side language options for both the get and post requests.\n\n        :param region: The current region\n        :type region: ~cms.models.regions.region.Region\n\n        :param language: The current language\n        :type language: ~cms.models.languages.language.Language\n\n        :param page: The current page\n        :type page: ~cms.models.pages.page.Page\n\n        :return: The list of language options, each represented by a dict\n        :rtype: list\n        \"\"\"\n\n        side_by_side_language_options = []\n        for language_node in region.language_tree_nodes.all():\n            if language_node.parent:\n                source_translation = PageTranslation.objects.filter(\n                    page=page,\n                    language=language_node.parent.language,\n                )\n                side_by_side_language_options.append(\n                    {\n                        \"value\": language_node.language.slug,\n                        \"label\": _(\"{source_language} to {target_language}\").format(\n                            source_language=language_node.parent.language.translated_name,\n                            target_language=language_node.language.translated_name,\n                        ),\n                        \"selected\": language_node.language == language,\n                        \"disabled\": not source_translation.exists(),\n                    }\n                )\n        return side_by_side_language_options\n", "path": "src/cms/views/pages/page_view.py"}]}