We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Setting FORCE_SCRIPT_NAME breaks views
Seems like a number of views are not parsing path correctly when FORCE_SCRIPT_NAME is set.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pootle/apps/pootle_translationproject/views.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) Pootle contributors.
4 #
5 # This file is a part of the Pootle project. It is distributed under the GPL3
6 # or later license. See the LICENSE file for a copy of the license and the
7 # AUTHORS file for copyright and authorship information.
8 
9 import functools
10 
11 from django.conf import settings
12 from django.http import Http404
13 from django.shortcuts import get_object_or_404, redirect
14 from django.urls import resolve, reverse
15 from django.utils.functional import cached_property
16 from django.utils.lru_cache import lru_cache
17 
18 from pootle.core.browser import (
19     get_parent, make_directory_item, make_store_item)
20 from pootle.core.decorators import get_path_obj, permission_required
21 from pootle.core.helpers import get_sidebar_announcements_context
22 from pootle.core.views import PootleBrowseView, PootleTranslateView
23 from pootle.core.views.display import StatsDisplay
24 from pootle_app.models import Directory
25 from pootle_app.models.permissions import get_matching_permissions
26 from pootle_app.views.admin.permissions import admin_permissions as admin_perms
27 from pootle_language.models import Language
28 from pootle_store.models import Store
29 
30 from .apps import PootleTPConfig
31 from .models import TranslationProject
32 
33 
34 @get_path_obj
35 @permission_required('administrate')
36 def admin_permissions(request, translation_project):
37     ctx = {
38         'page': 'admin-permissions',
39 
40         'browse_url': reverse('pootle-tp-browse', kwargs={
41             'language_code': translation_project.language.code,
42             'project_code': translation_project.project.code,
43         }),
44         'translate_url': reverse('pootle-tp-translate', kwargs={
45             'language_code': translation_project.language.code,
46             'project_code': translation_project.project.code,
47         }),
48 
49         'translation_project': translation_project,
50         'project': translation_project.project,
51         'language': translation_project.language,
52         'directory': translation_project.directory,
53     }
54     return admin_perms(request, translation_project.directory,
55                        'translation_projects/admin/permissions.html', ctx)
56 
57 
58 def redirect_to_tp_on_404(f):
59 
60     @functools.wraps(f)
61     def method_wrapper(self, request, *args, **kwargs):
62         try:
63             request.permissions = get_matching_permissions(
64                 request.user,
65                 self.permission_context) or []
66         except Http404 as e:
67             # Test if lang code is not canonical but valid
68             lang = Language.get_canonical(kwargs['language_code'])
69             if lang is not None and lang.code != kwargs['language_code']:
70                 kwargs["language_code"] = lang.code
71                 return redirect(
72                     resolve(request.path).view_name,
73                     permanent=True,
74                     **kwargs)
75 
76             elif kwargs["dir_path"] or kwargs.get("filename", None):
77                 try:
78                     TranslationProject.objects.get(
79                         project__code=kwargs["project_code"],
80                         language__code=kwargs["language_code"])
81                     # the TP exists so redirect to it
82                     return redirect(
83                         reverse(
84                             'pootle-tp-browse',
85                             kwargs={
86                                 k: v
87                                 for k, v
88                                 in kwargs.items()
89                                 if k in [
90                                     "language_code",
91                                     "project_code"]}))
92                 except TranslationProject.DoesNotExist:
93                     pass
94 
95             # if we get here - the TP does not exist
96             user_choice = self.request.COOKIES.get(
97                 'user-choice', None)
98             if user_choice:
99                 url = None
100                 if user_choice == 'language':
101                     url = reverse(
102                         'pootle-language-browse',
103                         args=[kwargs["language_code"]])
104                 elif user_choice == "project":
105                     url = reverse(
106                         'pootle-project-browse',
107                         args=[kwargs["project_code"], '', ''])
108                 if url:
109                     response = redirect(url)
110                     response.delete_cookie('user-choice')
111                     return response
112             raise e
113         return f(self, request, *args, **kwargs)
114     return method_wrapper
115 
116 
117 class TPMixin(object):
118     """This Mixin is used by all TP views.
119 
120     The context object may be a resource with the TP, ie a Directory or Store.
121     """
122 
123     ns = "pootle.tp"
124     sw_version = PootleTPConfig.version
125 
126     @redirect_to_tp_on_404
127     def dispatch(self, request, *args, **kwargs):
128         return super(TPMixin, self).dispatch(request, *args, **kwargs)
129 
130     @property
131     def ctx_path(self):
132         return self.tp.pootle_path
133 
134     @property
135     def resource_path(self):
136         return self.object.pootle_path.replace(self.ctx_path, "")
137 
138     @property
139     def dir_path(self):
140         return self.resource_path
141 
142     @cached_property
143     def tp(self):
144         if not self.object.tp:
145             return self.object.translation_project
146         return self.object.tp
147 
148     @cached_property
149     def project(self):
150         if self.tp.project.disabled and not self.request.user.is_superuser:
151             raise Http404
152         return self.tp.project
153 
154     @cached_property
155     def language(self):
156         return self.tp.language
157 
158     @cached_property
159     def sidebar_announcements(self):
160         return get_sidebar_announcements_context(
161             self.request,
162             (self.project, self.language, self.tp))
163 
164 
165 class TPDirectoryMixin(TPMixin):
166     model = Directory
167     browse_url_path = "pootle-tp-browse"
168     translate_url_path = "pootle-tp-translate"
169 
170     @property
171     def object_related(self):
172         return [
173             "parent",
174             "tp",
175             "tp__language",
176             "tp__language__directory",
177             "tp__project"]
178 
179     @lru_cache()
180     def get_object(self):
181         return get_object_or_404(
182             Directory.objects.select_related(*self.object_related),
183             pootle_path=self.path)
184 
185     @property
186     def url_kwargs(self):
187         return {
188             "language_code": self.language.code,
189             "project_code": self.project.code,
190             "dir_path": self.dir_path}
191 
192     @cached_property
193     def vfolders_data_view(self):
194         if 'virtualfolder' not in settings.INSTALLED_APPS:
195             return
196         from virtualfolder.delegate import vfolders_data_view
197 
198         return vfolders_data_view.get(self.object.__class__)(
199             self.object, self.request.user, self.has_admin_access)
200 
201 
202 class TPStoreMixin(TPMixin):
203     model = Store
204     browse_url_path = "pootle-tp-store-browse"
205     translate_url_path = "pootle-tp-store-translate"
206     is_store = True
207     panels = ()
208 
209     @property
210     def permission_context(self):
211         return self.get_object().parent
212 
213     @cached_property
214     def tp(self):
215         return self.object.translation_project
216 
217     @property
218     def dir_path(self):
219         return self.resource_path.replace(self.object.name, "")
220 
221     @property
222     def url_kwargs(self):
223         return {
224             "language_code": self.language.code,
225             "project_code": self.project.code,
226             "dir_path": self.dir_path,
227             "filename": self.object.name}
228 
229     @lru_cache()
230     def get_object(self):
231         path = (
232             "/%(language_code)s/%(project_code)s/%(dir_path)s%(filename)s"
233             % self.kwargs)
234         return get_object_or_404(
235             Store.objects.select_related(
236                 "parent",
237                 "translation_project__language",
238                 "translation_project__project"),
239             pootle_path=path)
240 
241 
242 class TPBrowseBaseView(PootleBrowseView):
243     template_extends = 'translation_projects/base.html'
244 
245     def get_context_data(self, *args, **kwargs):
246         upload_widget = self.get_upload_widget()
247         ctx = super(TPBrowseBaseView, self).get_context_data(*args, **kwargs)
248         ctx.update(upload_widget)
249         ctx.update(
250             {'parent': get_parent(self.object)})
251         return ctx
252 
253     @property
254     def can_upload(self):
255         return (
256             "import_export" in settings.INSTALLED_APPS
257             and self.request.user.is_authenticated
258             and (self.request.user.is_superuser
259                  or "translate" in self.request.permissions
260                  or "administrate" in self.request.permissions))
261 
262     def get_upload_widget(self):
263         ctx = {}
264         if self.can_upload:
265             from import_export.views import handle_upload_form
266 
267             ctx.update(handle_upload_form(self.request, self.tp))
268             ctx.update(
269                 {'display_download': True,
270                  'has_sidebar': True})
271         return ctx
272 
273     def post(self, *args, **kwargs):
274         return self.get(*args, **kwargs)
275 
276     @property
277     def score_context(self):
278         return self.tp
279 
280 
281 class TPBrowseStoreView(TPStoreMixin, TPBrowseBaseView):
282 
283     disabled_items = False
284 
285     @property
286     def cache_key(self):
287         return ""
288 
289 
290 class TPBrowseView(TPDirectoryMixin, TPBrowseBaseView):
291     view_name = "tp"
292     panel_names = ('vfolders', 'children')
293 
294     @cached_property
295     def object_children(self):
296         dirs_with_vfolders = []
297         if 'virtualfolder' in settings.INSTALLED_APPS:
298             stores = self.tp.stores
299             if self.object.tp_path != "/":
300                 stores = stores.filter(
301                     tp_path__startswith=self.object.tp_path)
302             vf_stores = stores.filter(
303                 vfolders__isnull=False).exclude(parent=self.object)
304             dirs_with_vfolders = set(
305                 [path.replace(self.object.pootle_path, "").split("/")[0]
306                  for path
307                  in vf_stores.values_list(
308                      "pootle_path", flat=True)])
309         directories = [
310             make_directory_item(
311                 child,
312                 **(dict(sort="priority")
313                    if child.name in dirs_with_vfolders
314                    else {}))
315             for child in self.object.children
316             if isinstance(child, Directory)]
317         stores = [
318             make_store_item(child)
319             for child in self.object.children
320             if isinstance(child, Store)]
321         return self.add_child_stats(directories + stores)
322 
323     @cached_property
324     def has_vfolders(self):
325         vfdata = self.vfolders_data_view
326         return bool(
327             vfdata
328             and vfdata.table_data
329             and vfdata.table_data.get("children"))
330 
331     @cached_property
332     def stats(self):
333         stats_ob = (
334             self.object.tp
335             if self.object.tp_path == "/"
336             else self.object)
337         return StatsDisplay(
338             stats_ob,
339             stats=stats_ob.data_tool.get_stats(
340                 user=self.request.user)).stats
341 
342 
343 class TPTranslateBaseView(PootleTranslateView):
344     translate_url_path = "pootle-tp-translate"
345     browse_url_path = "pootle-tp-browse"
346     template_extends = 'translation_projects/base.html'
347 
348     @property
349     def pootle_path(self):
350         return "%s%s" % (self.ctx_path, self.resource_path)
351 
352 
353 class TPTranslateView(TPDirectoryMixin, TPTranslateBaseView):
354 
355     @property
356     def request_path(self):
357         return "/%(language_code)s/%(project_code)s/%(dir_path)s" % self.kwargs
358 
359     @cached_property
360     def display_vfolder_priority(self):
361         return self.vfolders_data_view.has_data
362 
363     @property
364     def path(self):
365         return self.request_path
366 
367 
368 class TPTranslateStoreView(TPStoreMixin, TPTranslateBaseView):
369     pass
370
```
--- 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/pootle/apps/pootle_translationproject/views.py b/pootle/apps/pootle_translationproject/views.py
--- a/pootle/apps/pootle_translationproject/views.py
+++ b/pootle/apps/pootle_translationproject/views.py
@@ -291,6 +291,15 @@
     view_name = "tp"
     panel_names = ('vfolders', 'children')
 
+    @property
+    def path(self):
+        kwargs = self.kwargs
+        kwargs["dir_path"] = kwargs.get("dir_path", "")
+        kwargs["filename"] = kwargs.get("filename", "")
+        return (
+            "/%(language_code)s/%(project_code)s/%(dir_path)s%(filename)s"
+            % kwargs)
+
     @cached_property
     def object_children(self):
         dirs_with_vfolders = []

{"golden_diff": "diff --git a/pootle/apps/pootle_translationproject/views.py b/pootle/apps/pootle_translationproject/views.py\n--- a/pootle/apps/pootle_translationproject/views.py\n+++ b/pootle/apps/pootle_translationproject/views.py\n@@ -291,6 +291,15 @@\n     view_name = \"tp\"\n     panel_names = ('vfolders', 'children')\n \n+    @property\n+    def path(self):\n+        kwargs = self.kwargs\n+        kwargs[\"dir_path\"] = kwargs.get(\"dir_path\", \"\")\n+        kwargs[\"filename\"] = kwargs.get(\"filename\", \"\")\n+        return (\n+            \"/%(language_code)s/%(project_code)s/%(dir_path)s%(filename)s\"\n+            % kwargs)\n+\n     @cached_property\n     def object_children(self):\n         dirs_with_vfolders = []\n", "issue": "Setting FORCE_SCRIPT_NAME breaks views\nSeems like a number of views are not parsing path correctly when FORCE_SCRIPT_NAME is set.\r\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# Copyright (C) Pootle contributors.\n#\n# This file is a part of the Pootle project. It is distributed under the GPL3\n# or later license. See the LICENSE file for a copy of the license and the\n# AUTHORS file for copyright and authorship information.\n\nimport functools\n\nfrom django.conf import settings\nfrom django.http import Http404\nfrom django.shortcuts import get_object_or_404, redirect\nfrom django.urls import resolve, reverse\nfrom django.utils.functional import cached_property\nfrom django.utils.lru_cache import lru_cache\n\nfrom pootle.core.browser import (\n    get_parent, make_directory_item, make_store_item)\nfrom pootle.core.decorators import get_path_obj, permission_required\nfrom pootle.core.helpers import get_sidebar_announcements_context\nfrom pootle.core.views import PootleBrowseView, PootleTranslateView\nfrom pootle.core.views.display import StatsDisplay\nfrom pootle_app.models import Directory\nfrom pootle_app.models.permissions import get_matching_permissions\nfrom pootle_app.views.admin.permissions import admin_permissions as admin_perms\nfrom pootle_language.models import Language\nfrom pootle_store.models import Store\n\nfrom .apps import PootleTPConfig\nfrom .models import TranslationProject\n\n\n@get_path_obj\n@permission_required('administrate')\ndef admin_permissions(request, translation_project):\n    ctx = {\n        'page': 'admin-permissions',\n\n        'browse_url': reverse('pootle-tp-browse', kwargs={\n            'language_code': translation_project.language.code,\n            'project_code': translation_project.project.code,\n        }),\n        'translate_url': reverse('pootle-tp-translate', kwargs={\n            'language_code': translation_project.language.code,\n            'project_code': translation_project.project.code,\n        }),\n\n        'translation_project': translation_project,\n        'project': translation_project.project,\n        'language': translation_project.language,\n        'directory': translation_project.directory,\n    }\n    return admin_perms(request, translation_project.directory,\n                       'translation_projects/admin/permissions.html', ctx)\n\n\ndef redirect_to_tp_on_404(f):\n\n    @functools.wraps(f)\n    def method_wrapper(self, request, *args, **kwargs):\n        try:\n            request.permissions = get_matching_permissions(\n                request.user,\n                self.permission_context) or []\n        except Http404 as e:\n            # Test if lang code is not canonical but valid\n            lang = Language.get_canonical(kwargs['language_code'])\n            if lang is not None and lang.code != kwargs['language_code']:\n                kwargs[\"language_code\"] = lang.code\n                return redirect(\n                    resolve(request.path).view_name,\n                    permanent=True,\n                    **kwargs)\n\n            elif kwargs[\"dir_path\"] or kwargs.get(\"filename\", None):\n                try:\n                    TranslationProject.objects.get(\n                        project__code=kwargs[\"project_code\"],\n                        language__code=kwargs[\"language_code\"])\n                    # the TP exists so redirect to it\n                    return redirect(\n                        reverse(\n                            'pootle-tp-browse',\n                            kwargs={\n                                k: v\n                                for k, v\n                                in kwargs.items()\n                                if k in [\n                                    \"language_code\",\n                                    \"project_code\"]}))\n                except TranslationProject.DoesNotExist:\n                    pass\n\n            # if we get here - the TP does not exist\n            user_choice = self.request.COOKIES.get(\n                'user-choice', None)\n            if user_choice:\n                url = None\n                if user_choice == 'language':\n                    url = reverse(\n                        'pootle-language-browse',\n                        args=[kwargs[\"language_code\"]])\n                elif user_choice == \"project\":\n                    url = reverse(\n                        'pootle-project-browse',\n                        args=[kwargs[\"project_code\"], '', ''])\n                if url:\n                    response = redirect(url)\n                    response.delete_cookie('user-choice')\n                    return response\n            raise e\n        return f(self, request, *args, **kwargs)\n    return method_wrapper\n\n\nclass TPMixin(object):\n    \"\"\"This Mixin is used by all TP views.\n\n    The context object may be a resource with the TP, ie a Directory or Store.\n    \"\"\"\n\n    ns = \"pootle.tp\"\n    sw_version = PootleTPConfig.version\n\n    @redirect_to_tp_on_404\n    def dispatch(self, request, *args, **kwargs):\n        return super(TPMixin, self).dispatch(request, *args, **kwargs)\n\n    @property\n    def ctx_path(self):\n        return self.tp.pootle_path\n\n    @property\n    def resource_path(self):\n        return self.object.pootle_path.replace(self.ctx_path, \"\")\n\n    @property\n    def dir_path(self):\n        return self.resource_path\n\n    @cached_property\n    def tp(self):\n        if not self.object.tp:\n            return self.object.translation_project\n        return self.object.tp\n\n    @cached_property\n    def project(self):\n        if self.tp.project.disabled and not self.request.user.is_superuser:\n            raise Http404\n        return self.tp.project\n\n    @cached_property\n    def language(self):\n        return self.tp.language\n\n    @cached_property\n    def sidebar_announcements(self):\n        return get_sidebar_announcements_context(\n            self.request,\n            (self.project, self.language, self.tp))\n\n\nclass TPDirectoryMixin(TPMixin):\n    model = Directory\n    browse_url_path = \"pootle-tp-browse\"\n    translate_url_path = \"pootle-tp-translate\"\n\n    @property\n    def object_related(self):\n        return [\n            \"parent\",\n            \"tp\",\n            \"tp__language\",\n            \"tp__language__directory\",\n            \"tp__project\"]\n\n    @lru_cache()\n    def get_object(self):\n        return get_object_or_404(\n            Directory.objects.select_related(*self.object_related),\n            pootle_path=self.path)\n\n    @property\n    def url_kwargs(self):\n        return {\n            \"language_code\": self.language.code,\n            \"project_code\": self.project.code,\n            \"dir_path\": self.dir_path}\n\n    @cached_property\n    def vfolders_data_view(self):\n        if 'virtualfolder' not in settings.INSTALLED_APPS:\n            return\n        from virtualfolder.delegate import vfolders_data_view\n\n        return vfolders_data_view.get(self.object.__class__)(\n            self.object, self.request.user, self.has_admin_access)\n\n\nclass TPStoreMixin(TPMixin):\n    model = Store\n    browse_url_path = \"pootle-tp-store-browse\"\n    translate_url_path = \"pootle-tp-store-translate\"\n    is_store = True\n    panels = ()\n\n    @property\n    def permission_context(self):\n        return self.get_object().parent\n\n    @cached_property\n    def tp(self):\n        return self.object.translation_project\n\n    @property\n    def dir_path(self):\n        return self.resource_path.replace(self.object.name, \"\")\n\n    @property\n    def url_kwargs(self):\n        return {\n            \"language_code\": self.language.code,\n            \"project_code\": self.project.code,\n            \"dir_path\": self.dir_path,\n            \"filename\": self.object.name}\n\n    @lru_cache()\n    def get_object(self):\n        path = (\n            \"/%(language_code)s/%(project_code)s/%(dir_path)s%(filename)s\"\n            % self.kwargs)\n        return get_object_or_404(\n            Store.objects.select_related(\n                \"parent\",\n                \"translation_project__language\",\n                \"translation_project__project\"),\n            pootle_path=path)\n\n\nclass TPBrowseBaseView(PootleBrowseView):\n    template_extends = 'translation_projects/base.html'\n\n    def get_context_data(self, *args, **kwargs):\n        upload_widget = self.get_upload_widget()\n        ctx = super(TPBrowseBaseView, self).get_context_data(*args, **kwargs)\n        ctx.update(upload_widget)\n        ctx.update(\n            {'parent': get_parent(self.object)})\n        return ctx\n\n    @property\n    def can_upload(self):\n        return (\n            \"import_export\" in settings.INSTALLED_APPS\n            and self.request.user.is_authenticated\n            and (self.request.user.is_superuser\n                 or \"translate\" in self.request.permissions\n                 or \"administrate\" in self.request.permissions))\n\n    def get_upload_widget(self):\n        ctx = {}\n        if self.can_upload:\n            from import_export.views import handle_upload_form\n\n            ctx.update(handle_upload_form(self.request, self.tp))\n            ctx.update(\n                {'display_download': True,\n                 'has_sidebar': True})\n        return ctx\n\n    def post(self, *args, **kwargs):\n        return self.get(*args, **kwargs)\n\n    @property\n    def score_context(self):\n        return self.tp\n\n\nclass TPBrowseStoreView(TPStoreMixin, TPBrowseBaseView):\n\n    disabled_items = False\n\n    @property\n    def cache_key(self):\n        return \"\"\n\n\nclass TPBrowseView(TPDirectoryMixin, TPBrowseBaseView):\n    view_name = \"tp\"\n    panel_names = ('vfolders', 'children')\n\n    @cached_property\n    def object_children(self):\n        dirs_with_vfolders = []\n        if 'virtualfolder' in settings.INSTALLED_APPS:\n            stores = self.tp.stores\n            if self.object.tp_path != \"/\":\n                stores = stores.filter(\n                    tp_path__startswith=self.object.tp_path)\n            vf_stores = stores.filter(\n                vfolders__isnull=False).exclude(parent=self.object)\n            dirs_with_vfolders = set(\n                [path.replace(self.object.pootle_path, \"\").split(\"/\")[0]\n                 for path\n                 in vf_stores.values_list(\n                     \"pootle_path\", flat=True)])\n        directories = [\n            make_directory_item(\n                child,\n                **(dict(sort=\"priority\")\n                   if child.name in dirs_with_vfolders\n                   else {}))\n            for child in self.object.children\n            if isinstance(child, Directory)]\n        stores = [\n            make_store_item(child)\n            for child in self.object.children\n            if isinstance(child, Store)]\n        return self.add_child_stats(directories + stores)\n\n    @cached_property\n    def has_vfolders(self):\n        vfdata = self.vfolders_data_view\n        return bool(\n            vfdata\n            and vfdata.table_data\n            and vfdata.table_data.get(\"children\"))\n\n    @cached_property\n    def stats(self):\n        stats_ob = (\n            self.object.tp\n            if self.object.tp_path == \"/\"\n            else self.object)\n        return StatsDisplay(\n            stats_ob,\n            stats=stats_ob.data_tool.get_stats(\n                user=self.request.user)).stats\n\n\nclass TPTranslateBaseView(PootleTranslateView):\n    translate_url_path = \"pootle-tp-translate\"\n    browse_url_path = \"pootle-tp-browse\"\n    template_extends = 'translation_projects/base.html'\n\n    @property\n    def pootle_path(self):\n        return \"%s%s\" % (self.ctx_path, self.resource_path)\n\n\nclass TPTranslateView(TPDirectoryMixin, TPTranslateBaseView):\n\n    @property\n    def request_path(self):\n        return \"/%(language_code)s/%(project_code)s/%(dir_path)s\" % self.kwargs\n\n    @cached_property\n    def display_vfolder_priority(self):\n        return self.vfolders_data_view.has_data\n\n    @property\n    def path(self):\n        return self.request_path\n\n\nclass TPTranslateStoreView(TPStoreMixin, TPTranslateBaseView):\n    pass\n", "path": "pootle/apps/pootle_translationproject/views.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# Copyright (C) Pootle contributors.\n#\n# This file is a part of the Pootle project. It is distributed under the GPL3\n# or later license. See the LICENSE file for a copy of the license and the\n# AUTHORS file for copyright and authorship information.\n\nimport functools\n\nfrom django.conf import settings\nfrom django.http import Http404\nfrom django.shortcuts import get_object_or_404, redirect\nfrom django.urls import resolve, reverse\nfrom django.utils.functional import cached_property\nfrom django.utils.lru_cache import lru_cache\n\nfrom pootle.core.browser import (\n    get_parent, make_directory_item, make_store_item)\nfrom pootle.core.decorators import get_path_obj, permission_required\nfrom pootle.core.helpers import get_sidebar_announcements_context\nfrom pootle.core.views import PootleBrowseView, PootleTranslateView\nfrom pootle.core.views.display import StatsDisplay\nfrom pootle_app.models import Directory\nfrom pootle_app.models.permissions import get_matching_permissions\nfrom pootle_app.views.admin.permissions import admin_permissions as admin_perms\nfrom pootle_language.models import Language\nfrom pootle_store.models import Store\n\nfrom .apps import PootleTPConfig\nfrom .models import TranslationProject\n\n\n@get_path_obj\n@permission_required('administrate')\ndef admin_permissions(request, translation_project):\n    ctx = {\n        'page': 'admin-permissions',\n\n        'browse_url': reverse('pootle-tp-browse', kwargs={\n            'language_code': translation_project.language.code,\n            'project_code': translation_project.project.code,\n        }),\n        'translate_url': reverse('pootle-tp-translate', kwargs={\n            'language_code': translation_project.language.code,\n            'project_code': translation_project.project.code,\n        }),\n\n        'translation_project': translation_project,\n        'project': translation_project.project,\n        'language': translation_project.language,\n        'directory': translation_project.directory,\n    }\n    return admin_perms(request, translation_project.directory,\n                       'translation_projects/admin/permissions.html', ctx)\n\n\ndef redirect_to_tp_on_404(f):\n\n    @functools.wraps(f)\n    def method_wrapper(self, request, *args, **kwargs):\n        try:\n            request.permissions = get_matching_permissions(\n                request.user,\n                self.permission_context) or []\n        except Http404 as e:\n            # Test if lang code is not canonical but valid\n            lang = Language.get_canonical(kwargs['language_code'])\n            if lang is not None and lang.code != kwargs['language_code']:\n                kwargs[\"language_code\"] = lang.code\n                return redirect(\n                    resolve(request.path).view_name,\n                    permanent=True,\n                    **kwargs)\n\n            elif kwargs[\"dir_path\"] or kwargs.get(\"filename\", None):\n                try:\n                    TranslationProject.objects.get(\n                        project__code=kwargs[\"project_code\"],\n                        language__code=kwargs[\"language_code\"])\n                    # the TP exists so redirect to it\n                    return redirect(\n                        reverse(\n                            'pootle-tp-browse',\n                            kwargs={\n                                k: v\n                                for k, v\n                                in kwargs.items()\n                                if k in [\n                                    \"language_code\",\n                                    \"project_code\"]}))\n                except TranslationProject.DoesNotExist:\n                    pass\n\n            # if we get here - the TP does not exist\n            user_choice = self.request.COOKIES.get(\n                'user-choice', None)\n            if user_choice:\n                url = None\n                if user_choice == 'language':\n                    url = reverse(\n                        'pootle-language-browse',\n                        args=[kwargs[\"language_code\"]])\n                elif user_choice == \"project\":\n                    url = reverse(\n                        'pootle-project-browse',\n                        args=[kwargs[\"project_code\"], '', ''])\n                if url:\n                    response = redirect(url)\n                    response.delete_cookie('user-choice')\n                    return response\n            raise e\n        return f(self, request, *args, **kwargs)\n    return method_wrapper\n\n\nclass TPMixin(object):\n    \"\"\"This Mixin is used by all TP views.\n\n    The context object may be a resource with the TP, ie a Directory or Store.\n    \"\"\"\n\n    ns = \"pootle.tp\"\n    sw_version = PootleTPConfig.version\n\n    @redirect_to_tp_on_404\n    def dispatch(self, request, *args, **kwargs):\n        return super(TPMixin, self).dispatch(request, *args, **kwargs)\n\n    @property\n    def ctx_path(self):\n        return self.tp.pootle_path\n\n    @property\n    def resource_path(self):\n        return self.object.pootle_path.replace(self.ctx_path, \"\")\n\n    @property\n    def dir_path(self):\n        return self.resource_path\n\n    @cached_property\n    def tp(self):\n        if not self.object.tp:\n            return self.object.translation_project\n        return self.object.tp\n\n    @cached_property\n    def project(self):\n        if self.tp.project.disabled and not self.request.user.is_superuser:\n            raise Http404\n        return self.tp.project\n\n    @cached_property\n    def language(self):\n        return self.tp.language\n\n    @cached_property\n    def sidebar_announcements(self):\n        return get_sidebar_announcements_context(\n            self.request,\n            (self.project, self.language, self.tp))\n\n\nclass TPDirectoryMixin(TPMixin):\n    model = Directory\n    browse_url_path = \"pootle-tp-browse\"\n    translate_url_path = \"pootle-tp-translate\"\n\n    @property\n    def object_related(self):\n        return [\n            \"parent\",\n            \"tp\",\n            \"tp__language\",\n            \"tp__language__directory\",\n            \"tp__project\"]\n\n    @lru_cache()\n    def get_object(self):\n        return get_object_or_404(\n            Directory.objects.select_related(*self.object_related),\n            pootle_path=self.path)\n\n    @property\n    def url_kwargs(self):\n        return {\n            \"language_code\": self.language.code,\n            \"project_code\": self.project.code,\n            \"dir_path\": self.dir_path}\n\n    @cached_property\n    def vfolders_data_view(self):\n        if 'virtualfolder' not in settings.INSTALLED_APPS:\n            return\n        from virtualfolder.delegate import vfolders_data_view\n\n        return vfolders_data_view.get(self.object.__class__)(\n            self.object, self.request.user, self.has_admin_access)\n\n\nclass TPStoreMixin(TPMixin):\n    model = Store\n    browse_url_path = \"pootle-tp-store-browse\"\n    translate_url_path = \"pootle-tp-store-translate\"\n    is_store = True\n    panels = ()\n\n    @property\n    def permission_context(self):\n        return self.get_object().parent\n\n    @cached_property\n    def tp(self):\n        return self.object.translation_project\n\n    @property\n    def dir_path(self):\n        return self.resource_path.replace(self.object.name, \"\")\n\n    @property\n    def url_kwargs(self):\n        return {\n            \"language_code\": self.language.code,\n            \"project_code\": self.project.code,\n            \"dir_path\": self.dir_path,\n            \"filename\": self.object.name}\n\n    @lru_cache()\n    def get_object(self):\n        path = (\n            \"/%(language_code)s/%(project_code)s/%(dir_path)s%(filename)s\"\n            % self.kwargs)\n        return get_object_or_404(\n            Store.objects.select_related(\n                \"parent\",\n                \"translation_project__language\",\n                \"translation_project__project\"),\n            pootle_path=path)\n\n\nclass TPBrowseBaseView(PootleBrowseView):\n    template_extends = 'translation_projects/base.html'\n\n    def get_context_data(self, *args, **kwargs):\n        upload_widget = self.get_upload_widget()\n        ctx = super(TPBrowseBaseView, self).get_context_data(*args, **kwargs)\n        ctx.update(upload_widget)\n        ctx.update(\n            {'parent': get_parent(self.object)})\n        return ctx\n\n    @property\n    def can_upload(self):\n        return (\n            \"import_export\" in settings.INSTALLED_APPS\n            and self.request.user.is_authenticated\n            and (self.request.user.is_superuser\n                 or \"translate\" in self.request.permissions\n                 or \"administrate\" in self.request.permissions))\n\n    def get_upload_widget(self):\n        ctx = {}\n        if self.can_upload:\n            from import_export.views import handle_upload_form\n\n            ctx.update(handle_upload_form(self.request, self.tp))\n            ctx.update(\n                {'display_download': True,\n                 'has_sidebar': True})\n        return ctx\n\n    def post(self, *args, **kwargs):\n        return self.get(*args, **kwargs)\n\n    @property\n    def score_context(self):\n        return self.tp\n\n\nclass TPBrowseStoreView(TPStoreMixin, TPBrowseBaseView):\n\n    disabled_items = False\n\n    @property\n    def cache_key(self):\n        return \"\"\n\n\nclass TPBrowseView(TPDirectoryMixin, TPBrowseBaseView):\n    view_name = \"tp\"\n    panel_names = ('vfolders', 'children')\n\n    @property\n    def path(self):\n        kwargs = self.kwargs\n        kwargs[\"dir_path\"] = kwargs.get(\"dir_path\", \"\")\n        kwargs[\"filename\"] = kwargs.get(\"filename\", \"\")\n        return (\n            \"/%(language_code)s/%(project_code)s/%(dir_path)s%(filename)s\"\n            % kwargs)\n\n    @cached_property\n    def object_children(self):\n        dirs_with_vfolders = []\n        if 'virtualfolder' in settings.INSTALLED_APPS:\n            stores = self.tp.stores\n            if self.object.tp_path != \"/\":\n                stores = stores.filter(\n                    tp_path__startswith=self.object.tp_path)\n            vf_stores = stores.filter(\n                vfolders__isnull=False).exclude(parent=self.object)\n            dirs_with_vfolders = set(\n                [path.replace(self.object.pootle_path, \"\").split(\"/\")[0]\n                 for path\n                 in vf_stores.values_list(\n                     \"pootle_path\", flat=True)])\n        directories = [\n            make_directory_item(\n                child,\n                **(dict(sort=\"priority\")\n                   if child.name in dirs_with_vfolders\n                   else {}))\n            for child in self.object.children\n            if isinstance(child, Directory)]\n        stores = [\n            make_store_item(child)\n            for child in self.object.children\n            if isinstance(child, Store)]\n        return self.add_child_stats(directories + stores)\n\n    @cached_property\n    def has_vfolders(self):\n        vfdata = self.vfolders_data_view\n        return bool(\n            vfdata\n            and vfdata.table_data\n            and vfdata.table_data.get(\"children\"))\n\n    @cached_property\n    def stats(self):\n        stats_ob = (\n            self.object.tp\n            if self.object.tp_path == \"/\"\n            else self.object)\n        return StatsDisplay(\n            stats_ob,\n            stats=stats_ob.data_tool.get_stats(\n                user=self.request.user)).stats\n\n\nclass TPTranslateBaseView(PootleTranslateView):\n    translate_url_path = \"pootle-tp-translate\"\n    browse_url_path = \"pootle-tp-browse\"\n    template_extends = 'translation_projects/base.html'\n\n    @property\n    def pootle_path(self):\n        return \"%s%s\" % (self.ctx_path, self.resource_path)\n\n\nclass TPTranslateView(TPDirectoryMixin, TPTranslateBaseView):\n\n    @property\n    def request_path(self):\n        return \"/%(language_code)s/%(project_code)s/%(dir_path)s\" % self.kwargs\n\n    @cached_property\n    def display_vfolder_priority(self):\n        return self.vfolders_data_view.has_data\n\n    @property\n    def path(self):\n        return self.request_path\n\n\nclass TPTranslateStoreView(TPStoreMixin, TPTranslateBaseView):\n    pass\n", "path": "pootle/apps/pootle_translationproject/views.py"}]}