We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
add "Featured" category
In order to find "Featured" labeled apps better, there should be a separate category, making all official apps accessible on one screen.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `nextcloudappstore/core/views.py`
Content:
```
1 from urllib.parse import urlencode
2 
3 from django.conf import settings
4 from django.contrib.auth.mixins import LoginRequiredMixin
5 from django.contrib.auth.models import User
6 from django.core.exceptions import ObjectDoesNotExist
7 from django.db.models import Q
8 from django.http import HttpResponse
9 from django.shortcuts import get_object_or_404, redirect
10 from django.utils.functional import cached_property
11 from django.utils.translation import get_language, get_language_info
12 from django.views.decorators.http import etag
13 from django.views.generic.base import TemplateView
14 from django.views.generic.detail import DetailView
15 from django.views.generic.list import ListView
16 from rest_framework.generics import ListAPIView
17 from semantic_version import Version
18 
19 from nextcloudappstore.core.caching import app_etag
20 from nextcloudappstore.core.facades import flatmap
21 from nextcloudappstore.core.forms import AppRatingForm, AppReleaseUploadForm, \
22     AppRegisterForm
23 from nextcloudappstore.core.models import App, Category, AppRating
24 from nextcloudappstore.core.serializers import AppRatingSerializer
25 from nextcloudappstore.core.versioning import pad_min_version
26 
27 
28 @etag(app_etag)
29 def app_description(request, id):
30     app = get_object_or_404(App, id=id)
31     return HttpResponse(app.description, content_type='text/plain')
32 
33 
34 class AppRatingApi(ListAPIView):
35     serializer_class = AppRatingSerializer
36 
37     def get_queryset(self):
38         id = self.kwargs.get('id')
39         lang = self.request.GET.get('lang', self.request.LANGUAGE_CODE)
40         app = get_object_or_404(App, id=id)
41         queryset = AppRating.objects.language(lang).filter(app=app)
42 
43         current_user = self.request.GET.get('current_user', 'false')
44         if current_user == 'true':
45             return queryset.filter(user=self.request.user)
46         else:
47             return queryset
48 
49 
50 class AppDetailView(DetailView):
51     queryset = App.objects.prefetch_related(
52         'releases',
53         'screenshots',
54         'co_maintainers',
55         'translations',
56     ).select_related('owner')
57     template_name = 'app/detail.html'
58     slug_field = 'id'
59     slug_url_kwarg = 'id'
60 
61     def post(self, request, id):
62         form = AppRatingForm(request.POST, id=id, user=request.user)
63         # there is no way that a rating can be invalid by default
64         if form.is_valid() and request.user.is_authenticated:
65             form.save()
66         return redirect('app-detail', id=id)
67 
68     def get_context_data(self, **kwargs):
69         context = super().get_context_data(**kwargs)
70         context['DISCOURSE_URL'] = settings.DISCOURSE_URL.rstrip('/')
71         context['rating_form'] = AppRatingForm(
72             initial={'language_code': get_language()})
73 
74         ratings = AppRating.objects.filter(app=context['app'])
75         rating_languages = flatmap(
76             lambda r: r.get_available_languages(), ratings)
77 
78         # make sure current session language is in the list even if there are
79         # no comments.
80         rating_languages = list(rating_languages)
81         if get_language() not in rating_languages:
82             rating_languages.append(get_language())
83 
84         context['languages'] = set(sorted(rating_languages))
85         context['fallbackLang'] = 'en' if 'en' in context['languages'] else ''
86         context['user_has_rated_app'] = False
87         if self.request.user.is_authenticated:
88             try:
89                 app_rating = AppRating.objects.get(user=self.request.user,
90                                                    app=context['app'])
91 
92                 # if parler fallsback to a fallback language
93                 # it doesn't set the language as current language
94                 # and we can't select the correct language in the
95                 # frontend. So we try and find a languge that is
96                 # available
97                 language_code = app_rating.get_current_language()
98                 if not app_rating.has_translation(language_code):
99                     for fallback in app_rating.get_fallback_languages():
100                         if app_rating.has_translation(fallback):
101                             app_rating.set_current_language(fallback)
102 
103                 # when accessing an empty comment django-parler tries to
104                 # fall back to the default language. However for comments
105                 # the default (English) does not always exist. Unfortunately
106                 # it throws the same exception as non existing models,
107                 # so we need to access it beforehand
108                 try:
109                     comment = app_rating.comment
110                 except AppRating.DoesNotExist:
111                     comment = ''
112 
113                 context['rating_form'] = AppRatingForm({
114                     'rating': app_rating.rating,
115                     'comment': comment,
116                     'language_code': app_rating.get_current_language(),
117                 })
118                 context['user_has_rated_app'] = True
119             except AppRating.DoesNotExist:
120                 pass
121         context['categories'] = Category.objects.prefetch_related(
122             'translations').all()
123         context['latest_releases_by_platform_v'] = \
124             self.object.latest_releases_by_platform_v()
125         return context
126 
127 
128 class AppReleasesView(DetailView):
129     queryset = App.objects.prefetch_related(
130         'translations',
131         'releases__translations',
132         'releases__phpextensiondependencies__php_extension',
133         'releases__databasedependencies__database',
134         'releases__shell_commands',
135         'releases__licenses',
136     )
137     template_name = 'app/releases.html'
138     slug_field = 'id'
139     slug_url_kwarg = 'id'
140 
141     def get_context_data(self, **kwargs):
142         context = super().get_context_data(**kwargs)
143         context['categories'] = Category.objects.prefetch_related(
144             'translations').all()
145 
146         releases = self.object.releases_by_platform_v()
147         unstables = self.object.unstable_releases_by_platform_v()
148         versions = set(list(releases.keys()) + list(unstables.keys()))
149         all_releases = list(map(
150             lambda v: (v, releases.get(v, []) + unstables.get(v, [])),
151             versions))
152         context['releases_by_platform_v'] = \
153             self._sort_by_platform_v(all_releases)
154         return context
155 
156     def _sort_by_platform_v(self, releases_by_platform, reverse=True):
157         """Sorts a list of tuples like (<platform version>, [releases]) by
158         platform version.
159 
160         :param releases_by_platform: A list of tuples.
161         :param reverse: Descending order if True, ascending otherwise.
162         :return sorted list of tuples.
163         """
164 
165         return sorted(releases_by_platform, reverse=reverse,
166                       key=lambda v: Version(pad_min_version(v[0])))
167 
168 
169 class CategoryAppListView(ListView):
170     model = App
171     template_name = 'app/list.html'
172     allow_empty = True
173 
174     def get_queryset(self):
175         order_by = self.request.GET.get('order_by', 'rating_overall')
176         ordering = self.request.GET.get('ordering', 'desc')
177         is_featured = self.request.GET.get('is_featured', False)
178         maintainer = self.request.GET.get('maintainer', False)
179         sort_columns = []
180 
181         allowed_order_by = {'name', 'last_release', 'rating_overall',
182                             'rating_recent'}
183         if order_by in allowed_order_by:
184             if order_by == 'name':
185                 order_by = 'translations__name'
186             if ordering == 'desc':
187                 sort_columns.append('-' + order_by)
188             else:
189                 sort_columns.append(order_by)
190 
191         lang = get_language_info(get_language())['code']
192         category_id = self.kwargs['id']
193         queryset = App.objects.search(self.search_terms, lang).order_by(
194             *sort_columns).filter(releases__gt=0)
195         if maintainer:
196             try:
197                 user = User.objects.get_by_natural_key(maintainer)
198                 queryset = queryset.filter(Q(owner=user) |
199                                            Q(co_maintainers=user))
200             except ObjectDoesNotExist:
201                 return queryset.none()
202         if category_id:
203             queryset = queryset.filter(categories__id=category_id)
204         if is_featured == "true":
205             queryset = queryset.filter(is_featured=True)
206         return queryset.prefetch_related('screenshots', 'translations')
207 
208     def get_context_data(self, **kwargs):
209         context = super().get_context_data(**kwargs)
210         context['categories'] = Category.objects.prefetch_related(
211             'translations').all()
212         category_id = self.kwargs['id']
213         if category_id:
214             context['current_category'] = Category.objects.get(id=category_id)
215         if self.search_terms:
216             context['search_query'] = ' '.join(self.search_terms)
217         context['url_params'] = self.url_params
218         return context
219 
220     @cached_property
221     def url_params(self):
222         """URL encoded strings with the GET params of the last request.
223 
224         Intended for preserving GET params upon clicking a link by including
225         one (and only one) of these strings in the "href" attribute.
226 
227         The parameters are divided into three groups: search, filters and
228         ordering. In addition to these three, the returned dict also contains
229         some combinations of them, as specified by the dict keys.
230 
231         No leading "?" or "&".
232 
233         :return dict with URL encoded strings.
234         """
235 
236         search = self._url_params_str('search')
237         filters = self._url_params_str('is_featured', 'maintainer')
238         ordering = self._url_params_str('order_by', 'ordering')
239 
240         return {
241             'search': search,
242             'filters': filters,
243             'ordering': ordering,
244             'search_filters': self._join_url_params_strs(search, filters),
245             'filters_ordering': self._join_url_params_strs(filters, ordering),
246         }
247 
248     def _url_params_str(self, *params):
249         args = map(lambda param: (param, self.request.GET.get(param, '')),
250                    params)
251         present_args = filter(lambda a: a[1], args)
252         return urlencode(dict(present_args))
253 
254     def _join_url_params_strs(self, *strings):
255         return '&'.join(filter(None, strings))
256 
257     @cached_property
258     def search_terms(self):
259         return self.request.GET.get('search', '').strip().split()
260 
261 
262 class AppUploadView(LoginRequiredMixin, TemplateView):
263     template_name = 'app/upload.html'
264 
265     def get_context_data(self, **kwargs):
266         context = super().get_context_data(**kwargs)
267         context['form'] = AppReleaseUploadForm()
268         return context
269 
270 
271 class AppRegisterView(LoginRequiredMixin, TemplateView):
272     template_name = 'app/register.html'
273 
274     def get_context_data(self, **kwargs):
275         context = super().get_context_data(**kwargs)
276         context['form'] = AppRegisterForm()
277         return context
278
```

Path: `nextcloudappstore/urls.py`
Content:
```
1 from allauth.account.views import signup
2 from allauth.socialaccount.views import signup as social_signup
3 from csp.decorators import csp_update
4 from django.conf import settings
5 from django.conf.urls import url, include
6 from django.conf.urls.i18n import i18n_patterns
7 from django.contrib import admin
8 from django.contrib.auth.decorators import login_required
9 from django.views.decorators.http import etag
10 
11 from nextcloudappstore.core.caching import app_rating_etag
12 from nextcloudappstore.core.feeds import AppReleaseAtomFeed, AppReleaseRssFeed
13 from nextcloudappstore.core.views import CategoryAppListView, AppDetailView, \
14     app_description, AppReleasesView, AppUploadView, AppRatingApi, \
15     AppRegisterView
16 from nextcloudappstore.scaffolding.views import AppScaffoldingView
17 
18 admin.site.login = login_required(admin.site.login)
19 
20 urlpatterns = [
21     url(r'^$', CategoryAppListView.as_view(), {'id': None}, name='home'),
22     url(r"^signup/$", csp_update(**settings.CSP_SIGNUP)(signup),
23         name="account_signup"),
24     url(r"^social/signup/$", csp_update(**settings.CSP_SIGNUP)(social_signup),
25         name="socialaccount_signup"),
26     url(r'^', include('allauth.urls')),
27     url(r'^categories/(?P<id>[\w]*)/?$', CategoryAppListView.as_view(),
28         name='category-app-list'),
29     url(r'^developer/apps/generate/?$', AppScaffoldingView.as_view(),
30         name='app-scaffold'),
31     url(r'^developer/apps/releases/new/?$', AppUploadView.as_view(),
32         name='app-upload'),
33     url(r'^developer/apps/new/?$', AppRegisterView.as_view(),
34         name='app-register'),
35     url(r'^apps/(?P<id>[\w_]+)/?$', AppDetailView.as_view(),
36         name='app-detail'),
37     url(r'^apps/(?P<id>[\w_]+)/releases/?$', AppReleasesView.as_view(),
38         name='app-releases'),
39     url(r'^apps/(?P<id>[\w_]+)/description/?$', app_description,
40         name='app-description'),
41     url(r'^apps/(?P<id>[\w_]+)/ratings.json$',
42         etag(app_rating_etag)(AppRatingApi.as_view()), name='app-ratings'),
43     url(r'^api/', include('nextcloudappstore.api.urls',
44                           namespace='api')),
45     url(r'^account/',
46         include('nextcloudappstore.user.urls', namespace='user')),
47     url(r'^admin/', admin.site.urls),
48     url(r'^i18n/', include('django.conf.urls.i18n')),
49 ]
50 
51 urlpatterns += i18n_patterns(
52     url(r'feeds/releases.rss', AppReleaseRssFeed(), name='feeds-releases-rss'),
53     url(r'feeds/releases.atom', AppReleaseAtomFeed(),
54         name='feeds-releases-atom'),
55 )
56 
57 if settings.DEBUG:
58     try:
59         import debug_toolbar
60 
61         urlpatterns += [url(r'^__debug__/', include(debug_toolbar.urls)), ]
62     except ImportError:
63         pass
64
```
--- 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/nextcloudappstore/core/views.py b/nextcloudappstore/core/views.py
--- a/nextcloudappstore/core/views.py
+++ b/nextcloudappstore/core/views.py
@@ -174,7 +174,8 @@
     def get_queryset(self):
         order_by = self.request.GET.get('order_by', 'rating_overall')
         ordering = self.request.GET.get('ordering', 'desc')
-        is_featured = self.request.GET.get('is_featured', False)
+        is_featured = self.request.GET.get('is_featured', self.kwargs
+                                           .get('is_featured_category', False))
         maintainer = self.request.GET.get('maintainer', False)
         sort_columns = []
 
@@ -210,6 +211,8 @@
         context['categories'] = Category.objects.prefetch_related(
             'translations').all()
         category_id = self.kwargs['id']
+        context['is_featured_category'] = self.kwargs\
+            .get('is_featured_category', False)
         if category_id:
             context['current_category'] = Category.objects.get(id=category_id)
         if self.search_terms:
diff --git a/nextcloudappstore/urls.py b/nextcloudappstore/urls.py
--- a/nextcloudappstore/urls.py
+++ b/nextcloudappstore/urls.py
@@ -19,6 +19,10 @@
 
 urlpatterns = [
     url(r'^$', CategoryAppListView.as_view(), {'id': None}, name='home'),
+    url(r"^featured$", CategoryAppListView.as_view(), {'id': None,
+                                                       'is_featured_category':
+                                                           True},
+        name='featured'),
     url(r"^signup/$", csp_update(**settings.CSP_SIGNUP)(signup),
         name="account_signup"),
     url(r"^social/signup/$", csp_update(**settings.CSP_SIGNUP)(social_signup),

{"golden_diff": "diff --git a/nextcloudappstore/core/views.py b/nextcloudappstore/core/views.py\n--- a/nextcloudappstore/core/views.py\n+++ b/nextcloudappstore/core/views.py\n@@ -174,7 +174,8 @@\n     def get_queryset(self):\n         order_by = self.request.GET.get('order_by', 'rating_overall')\n         ordering = self.request.GET.get('ordering', 'desc')\n-        is_featured = self.request.GET.get('is_featured', False)\n+        is_featured = self.request.GET.get('is_featured', self.kwargs\n+                                           .get('is_featured_category', False))\n         maintainer = self.request.GET.get('maintainer', False)\n         sort_columns = []\n \n@@ -210,6 +211,8 @@\n         context['categories'] = Category.objects.prefetch_related(\n             'translations').all()\n         category_id = self.kwargs['id']\n+        context['is_featured_category'] = self.kwargs\\\n+            .get('is_featured_category', False)\n         if category_id:\n             context['current_category'] = Category.objects.get(id=category_id)\n         if self.search_terms:\ndiff --git a/nextcloudappstore/urls.py b/nextcloudappstore/urls.py\n--- a/nextcloudappstore/urls.py\n+++ b/nextcloudappstore/urls.py\n@@ -19,6 +19,10 @@\n \n urlpatterns = [\n     url(r'^$', CategoryAppListView.as_view(), {'id': None}, name='home'),\n+    url(r\"^featured$\", CategoryAppListView.as_view(), {'id': None,\n+                                                       'is_featured_category':\n+                                                           True},\n+        name='featured'),\n     url(r\"^signup/$\", csp_update(**settings.CSP_SIGNUP)(signup),\n         name=\"account_signup\"),\n     url(r\"^social/signup/$\", csp_update(**settings.CSP_SIGNUP)(social_signup),\n", "issue": "add \"Featured\" category\nIn order to find \"Featured\" labeled apps better, there should be a separate category, making all official apps accessible on one screen.\n", "before_files": [{"content": "from urllib.parse import urlencode\n\nfrom django.conf import settings\nfrom django.contrib.auth.mixins import LoginRequiredMixin\nfrom django.contrib.auth.models import User\nfrom django.core.exceptions import ObjectDoesNotExist\nfrom django.db.models import Q\nfrom django.http import HttpResponse\nfrom django.shortcuts import get_object_or_404, redirect\nfrom django.utils.functional import cached_property\nfrom django.utils.translation import get_language, get_language_info\nfrom django.views.decorators.http import etag\nfrom django.views.generic.base import TemplateView\nfrom django.views.generic.detail import DetailView\nfrom django.views.generic.list import ListView\nfrom rest_framework.generics import ListAPIView\nfrom semantic_version import Version\n\nfrom nextcloudappstore.core.caching import app_etag\nfrom nextcloudappstore.core.facades import flatmap\nfrom nextcloudappstore.core.forms import AppRatingForm, AppReleaseUploadForm, \\\n    AppRegisterForm\nfrom nextcloudappstore.core.models import App, Category, AppRating\nfrom nextcloudappstore.core.serializers import AppRatingSerializer\nfrom nextcloudappstore.core.versioning import pad_min_version\n\n\n@etag(app_etag)\ndef app_description(request, id):\n    app = get_object_or_404(App, id=id)\n    return HttpResponse(app.description, content_type='text/plain')\n\n\nclass AppRatingApi(ListAPIView):\n    serializer_class = AppRatingSerializer\n\n    def get_queryset(self):\n        id = self.kwargs.get('id')\n        lang = self.request.GET.get('lang', self.request.LANGUAGE_CODE)\n        app = get_object_or_404(App, id=id)\n        queryset = AppRating.objects.language(lang).filter(app=app)\n\n        current_user = self.request.GET.get('current_user', 'false')\n        if current_user == 'true':\n            return queryset.filter(user=self.request.user)\n        else:\n            return queryset\n\n\nclass AppDetailView(DetailView):\n    queryset = App.objects.prefetch_related(\n        'releases',\n        'screenshots',\n        'co_maintainers',\n        'translations',\n    ).select_related('owner')\n    template_name = 'app/detail.html'\n    slug_field = 'id'\n    slug_url_kwarg = 'id'\n\n    def post(self, request, id):\n        form = AppRatingForm(request.POST, id=id, user=request.user)\n        # there is no way that a rating can be invalid by default\n        if form.is_valid() and request.user.is_authenticated:\n            form.save()\n        return redirect('app-detail', id=id)\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n        context['DISCOURSE_URL'] = settings.DISCOURSE_URL.rstrip('/')\n        context['rating_form'] = AppRatingForm(\n            initial={'language_code': get_language()})\n\n        ratings = AppRating.objects.filter(app=context['app'])\n        rating_languages = flatmap(\n            lambda r: r.get_available_languages(), ratings)\n\n        # make sure current session language is in the list even if there are\n        # no comments.\n        rating_languages = list(rating_languages)\n        if get_language() not in rating_languages:\n            rating_languages.append(get_language())\n\n        context['languages'] = set(sorted(rating_languages))\n        context['fallbackLang'] = 'en' if 'en' in context['languages'] else ''\n        context['user_has_rated_app'] = False\n        if self.request.user.is_authenticated:\n            try:\n                app_rating = AppRating.objects.get(user=self.request.user,\n                                                   app=context['app'])\n\n                # if parler fallsback to a fallback language\n                # it doesn't set the language as current language\n                # and we can't select the correct language in the\n                # frontend. So we try and find a languge that is\n                # available\n                language_code = app_rating.get_current_language()\n                if not app_rating.has_translation(language_code):\n                    for fallback in app_rating.get_fallback_languages():\n                        if app_rating.has_translation(fallback):\n                            app_rating.set_current_language(fallback)\n\n                # when accessing an empty comment django-parler tries to\n                # fall back to the default language. However for comments\n                # the default (English) does not always exist. Unfortunately\n                # it throws the same exception as non existing models,\n                # so we need to access it beforehand\n                try:\n                    comment = app_rating.comment\n                except AppRating.DoesNotExist:\n                    comment = ''\n\n                context['rating_form'] = AppRatingForm({\n                    'rating': app_rating.rating,\n                    'comment': comment,\n                    'language_code': app_rating.get_current_language(),\n                })\n                context['user_has_rated_app'] = True\n            except AppRating.DoesNotExist:\n                pass\n        context['categories'] = Category.objects.prefetch_related(\n            'translations').all()\n        context['latest_releases_by_platform_v'] = \\\n            self.object.latest_releases_by_platform_v()\n        return context\n\n\nclass AppReleasesView(DetailView):\n    queryset = App.objects.prefetch_related(\n        'translations',\n        'releases__translations',\n        'releases__phpextensiondependencies__php_extension',\n        'releases__databasedependencies__database',\n        'releases__shell_commands',\n        'releases__licenses',\n    )\n    template_name = 'app/releases.html'\n    slug_field = 'id'\n    slug_url_kwarg = 'id'\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n        context['categories'] = Category.objects.prefetch_related(\n            'translations').all()\n\n        releases = self.object.releases_by_platform_v()\n        unstables = self.object.unstable_releases_by_platform_v()\n        versions = set(list(releases.keys()) + list(unstables.keys()))\n        all_releases = list(map(\n            lambda v: (v, releases.get(v, []) + unstables.get(v, [])),\n            versions))\n        context['releases_by_platform_v'] = \\\n            self._sort_by_platform_v(all_releases)\n        return context\n\n    def _sort_by_platform_v(self, releases_by_platform, reverse=True):\n        \"\"\"Sorts a list of tuples like (<platform version>, [releases]) by\n        platform version.\n\n        :param releases_by_platform: A list of tuples.\n        :param reverse: Descending order if True, ascending otherwise.\n        :return sorted list of tuples.\n        \"\"\"\n\n        return sorted(releases_by_platform, reverse=reverse,\n                      key=lambda v: Version(pad_min_version(v[0])))\n\n\nclass CategoryAppListView(ListView):\n    model = App\n    template_name = 'app/list.html'\n    allow_empty = True\n\n    def get_queryset(self):\n        order_by = self.request.GET.get('order_by', 'rating_overall')\n        ordering = self.request.GET.get('ordering', 'desc')\n        is_featured = self.request.GET.get('is_featured', False)\n        maintainer = self.request.GET.get('maintainer', False)\n        sort_columns = []\n\n        allowed_order_by = {'name', 'last_release', 'rating_overall',\n                            'rating_recent'}\n        if order_by in allowed_order_by:\n            if order_by == 'name':\n                order_by = 'translations__name'\n            if ordering == 'desc':\n                sort_columns.append('-' + order_by)\n            else:\n                sort_columns.append(order_by)\n\n        lang = get_language_info(get_language())['code']\n        category_id = self.kwargs['id']\n        queryset = App.objects.search(self.search_terms, lang).order_by(\n            *sort_columns).filter(releases__gt=0)\n        if maintainer:\n            try:\n                user = User.objects.get_by_natural_key(maintainer)\n                queryset = queryset.filter(Q(owner=user) |\n                                           Q(co_maintainers=user))\n            except ObjectDoesNotExist:\n                return queryset.none()\n        if category_id:\n            queryset = queryset.filter(categories__id=category_id)\n        if is_featured == \"true\":\n            queryset = queryset.filter(is_featured=True)\n        return queryset.prefetch_related('screenshots', 'translations')\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n        context['categories'] = Category.objects.prefetch_related(\n            'translations').all()\n        category_id = self.kwargs['id']\n        if category_id:\n            context['current_category'] = Category.objects.get(id=category_id)\n        if self.search_terms:\n            context['search_query'] = ' '.join(self.search_terms)\n        context['url_params'] = self.url_params\n        return context\n\n    @cached_property\n    def url_params(self):\n        \"\"\"URL encoded strings with the GET params of the last request.\n\n        Intended for preserving GET params upon clicking a link by including\n        one (and only one) of these strings in the \"href\" attribute.\n\n        The parameters are divided into three groups: search, filters and\n        ordering. In addition to these three, the returned dict also contains\n        some combinations of them, as specified by the dict keys.\n\n        No leading \"?\" or \"&\".\n\n        :return dict with URL encoded strings.\n        \"\"\"\n\n        search = self._url_params_str('search')\n        filters = self._url_params_str('is_featured', 'maintainer')\n        ordering = self._url_params_str('order_by', 'ordering')\n\n        return {\n            'search': search,\n            'filters': filters,\n            'ordering': ordering,\n            'search_filters': self._join_url_params_strs(search, filters),\n            'filters_ordering': self._join_url_params_strs(filters, ordering),\n        }\n\n    def _url_params_str(self, *params):\n        args = map(lambda param: (param, self.request.GET.get(param, '')),\n                   params)\n        present_args = filter(lambda a: a[1], args)\n        return urlencode(dict(present_args))\n\n    def _join_url_params_strs(self, *strings):\n        return '&'.join(filter(None, strings))\n\n    @cached_property\n    def search_terms(self):\n        return self.request.GET.get('search', '').strip().split()\n\n\nclass AppUploadView(LoginRequiredMixin, TemplateView):\n    template_name = 'app/upload.html'\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n        context['form'] = AppReleaseUploadForm()\n        return context\n\n\nclass AppRegisterView(LoginRequiredMixin, TemplateView):\n    template_name = 'app/register.html'\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n        context['form'] = AppRegisterForm()\n        return context\n", "path": "nextcloudappstore/core/views.py"}, {"content": "from allauth.account.views import signup\nfrom allauth.socialaccount.views import signup as social_signup\nfrom csp.decorators import csp_update\nfrom django.conf import settings\nfrom django.conf.urls import url, include\nfrom django.conf.urls.i18n import i18n_patterns\nfrom django.contrib import admin\nfrom django.contrib.auth.decorators import login_required\nfrom django.views.decorators.http import etag\n\nfrom nextcloudappstore.core.caching import app_rating_etag\nfrom nextcloudappstore.core.feeds import AppReleaseAtomFeed, AppReleaseRssFeed\nfrom nextcloudappstore.core.views import CategoryAppListView, AppDetailView, \\\n    app_description, AppReleasesView, AppUploadView, AppRatingApi, \\\n    AppRegisterView\nfrom nextcloudappstore.scaffolding.views import AppScaffoldingView\n\nadmin.site.login = login_required(admin.site.login)\n\nurlpatterns = [\n    url(r'^$', CategoryAppListView.as_view(), {'id': None}, name='home'),\n    url(r\"^signup/$\", csp_update(**settings.CSP_SIGNUP)(signup),\n        name=\"account_signup\"),\n    url(r\"^social/signup/$\", csp_update(**settings.CSP_SIGNUP)(social_signup),\n        name=\"socialaccount_signup\"),\n    url(r'^', include('allauth.urls')),\n    url(r'^categories/(?P<id>[\\w]*)/?$', CategoryAppListView.as_view(),\n        name='category-app-list'),\n    url(r'^developer/apps/generate/?$', AppScaffoldingView.as_view(),\n        name='app-scaffold'),\n    url(r'^developer/apps/releases/new/?$', AppUploadView.as_view(),\n        name='app-upload'),\n    url(r'^developer/apps/new/?$', AppRegisterView.as_view(),\n        name='app-register'),\n    url(r'^apps/(?P<id>[\\w_]+)/?$', AppDetailView.as_view(),\n        name='app-detail'),\n    url(r'^apps/(?P<id>[\\w_]+)/releases/?$', AppReleasesView.as_view(),\n        name='app-releases'),\n    url(r'^apps/(?P<id>[\\w_]+)/description/?$', app_description,\n        name='app-description'),\n    url(r'^apps/(?P<id>[\\w_]+)/ratings.json$',\n        etag(app_rating_etag)(AppRatingApi.as_view()), name='app-ratings'),\n    url(r'^api/', include('nextcloudappstore.api.urls',\n                          namespace='api')),\n    url(r'^account/',\n        include('nextcloudappstore.user.urls', namespace='user')),\n    url(r'^admin/', admin.site.urls),\n    url(r'^i18n/', include('django.conf.urls.i18n')),\n]\n\nurlpatterns += i18n_patterns(\n    url(r'feeds/releases.rss', AppReleaseRssFeed(), name='feeds-releases-rss'),\n    url(r'feeds/releases.atom', AppReleaseAtomFeed(),\n        name='feeds-releases-atom'),\n)\n\nif settings.DEBUG:\n    try:\n        import debug_toolbar\n\n        urlpatterns += [url(r'^__debug__/', include(debug_toolbar.urls)), ]\n    except ImportError:\n        pass\n", "path": "nextcloudappstore/urls.py"}], "after_files": [{"content": "from urllib.parse import urlencode\n\nfrom django.conf import settings\nfrom django.contrib.auth.mixins import LoginRequiredMixin\nfrom django.contrib.auth.models import User\nfrom django.core.exceptions import ObjectDoesNotExist\nfrom django.db.models import Q\nfrom django.http import HttpResponse\nfrom django.shortcuts import get_object_or_404, redirect\nfrom django.utils.functional import cached_property\nfrom django.utils.translation import get_language, get_language_info\nfrom django.views.decorators.http import etag\nfrom django.views.generic.base import TemplateView\nfrom django.views.generic.detail import DetailView\nfrom django.views.generic.list import ListView\nfrom rest_framework.generics import ListAPIView\nfrom semantic_version import Version\n\nfrom nextcloudappstore.core.caching import app_etag\nfrom nextcloudappstore.core.facades import flatmap\nfrom nextcloudappstore.core.forms import AppRatingForm, AppReleaseUploadForm, \\\n    AppRegisterForm\nfrom nextcloudappstore.core.models import App, Category, AppRating\nfrom nextcloudappstore.core.serializers import AppRatingSerializer\nfrom nextcloudappstore.core.versioning import pad_min_version\n\n\n@etag(app_etag)\ndef app_description(request, id):\n    app = get_object_or_404(App, id=id)\n    return HttpResponse(app.description, content_type='text/plain')\n\n\nclass AppRatingApi(ListAPIView):\n    serializer_class = AppRatingSerializer\n\n    def get_queryset(self):\n        id = self.kwargs.get('id')\n        lang = self.request.GET.get('lang', self.request.LANGUAGE_CODE)\n        app = get_object_or_404(App, id=id)\n        queryset = AppRating.objects.language(lang).filter(app=app)\n\n        current_user = self.request.GET.get('current_user', 'false')\n        if current_user == 'true':\n            return queryset.filter(user=self.request.user)\n        else:\n            return queryset\n\n\nclass AppDetailView(DetailView):\n    queryset = App.objects.prefetch_related(\n        'releases',\n        'screenshots',\n        'co_maintainers',\n        'translations',\n    ).select_related('owner')\n    template_name = 'app/detail.html'\n    slug_field = 'id'\n    slug_url_kwarg = 'id'\n\n    def post(self, request, id):\n        form = AppRatingForm(request.POST, id=id, user=request.user)\n        # there is no way that a rating can be invalid by default\n        if form.is_valid() and request.user.is_authenticated:\n            form.save()\n        return redirect('app-detail', id=id)\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n        context['DISCOURSE_URL'] = settings.DISCOURSE_URL.rstrip('/')\n        context['rating_form'] = AppRatingForm(\n            initial={'language_code': get_language()})\n\n        ratings = AppRating.objects.filter(app=context['app'])\n        rating_languages = flatmap(\n            lambda r: r.get_available_languages(), ratings)\n\n        # make sure current session language is in the list even if there are\n        # no comments.\n        rating_languages = list(rating_languages)\n        if get_language() not in rating_languages:\n            rating_languages.append(get_language())\n\n        context['languages'] = set(sorted(rating_languages))\n        context['fallbackLang'] = 'en' if 'en' in context['languages'] else ''\n        context['user_has_rated_app'] = False\n        if self.request.user.is_authenticated:\n            try:\n                app_rating = AppRating.objects.get(user=self.request.user,\n                                                   app=context['app'])\n\n                # if parler fallsback to a fallback language\n                # it doesn't set the language as current language\n                # and we can't select the correct language in the\n                # frontend. So we try and find a languge that is\n                # available\n                language_code = app_rating.get_current_language()\n                if not app_rating.has_translation(language_code):\n                    for fallback in app_rating.get_fallback_languages():\n                        if app_rating.has_translation(fallback):\n                            app_rating.set_current_language(fallback)\n\n                # when accessing an empty comment django-parler tries to\n                # fall back to the default language. However for comments\n                # the default (English) does not always exist. Unfortunately\n                # it throws the same exception as non existing models,\n                # so we need to access it beforehand\n                try:\n                    comment = app_rating.comment\n                except AppRating.DoesNotExist:\n                    comment = ''\n\n                context['rating_form'] = AppRatingForm({\n                    'rating': app_rating.rating,\n                    'comment': comment,\n                    'language_code': app_rating.get_current_language(),\n                })\n                context['user_has_rated_app'] = True\n            except AppRating.DoesNotExist:\n                pass\n        context['categories'] = Category.objects.prefetch_related(\n            'translations').all()\n        context['latest_releases_by_platform_v'] = \\\n            self.object.latest_releases_by_platform_v()\n        return context\n\n\nclass AppReleasesView(DetailView):\n    queryset = App.objects.prefetch_related(\n        'translations',\n        'releases__translations',\n        'releases__phpextensiondependencies__php_extension',\n        'releases__databasedependencies__database',\n        'releases__shell_commands',\n        'releases__licenses',\n    )\n    template_name = 'app/releases.html'\n    slug_field = 'id'\n    slug_url_kwarg = 'id'\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n        context['categories'] = Category.objects.prefetch_related(\n            'translations').all()\n\n        releases = self.object.releases_by_platform_v()\n        unstables = self.object.unstable_releases_by_platform_v()\n        versions = set(list(releases.keys()) + list(unstables.keys()))\n        all_releases = list(map(\n            lambda v: (v, releases.get(v, []) + unstables.get(v, [])),\n            versions))\n        context['releases_by_platform_v'] = \\\n            self._sort_by_platform_v(all_releases)\n        return context\n\n    def _sort_by_platform_v(self, releases_by_platform, reverse=True):\n        \"\"\"Sorts a list of tuples like (<platform version>, [releases]) by\n        platform version.\n\n        :param releases_by_platform: A list of tuples.\n        :param reverse: Descending order if True, ascending otherwise.\n        :return sorted list of tuples.\n        \"\"\"\n\n        return sorted(releases_by_platform, reverse=reverse,\n                      key=lambda v: Version(pad_min_version(v[0])))\n\n\nclass CategoryAppListView(ListView):\n    model = App\n    template_name = 'app/list.html'\n    allow_empty = True\n\n    def get_queryset(self):\n        order_by = self.request.GET.get('order_by', 'rating_overall')\n        ordering = self.request.GET.get('ordering', 'desc')\n        is_featured = self.request.GET.get('is_featured', self.kwargs\n                                           .get('is_featured_category', False))\n        maintainer = self.request.GET.get('maintainer', False)\n        sort_columns = []\n\n        allowed_order_by = {'name', 'last_release', 'rating_overall',\n                            'rating_recent'}\n        if order_by in allowed_order_by:\n            if order_by == 'name':\n                order_by = 'translations__name'\n            if ordering == 'desc':\n                sort_columns.append('-' + order_by)\n            else:\n                sort_columns.append(order_by)\n\n        lang = get_language_info(get_language())['code']\n        category_id = self.kwargs['id']\n        queryset = App.objects.search(self.search_terms, lang).order_by(\n            *sort_columns).filter(releases__gt=0)\n        if maintainer:\n            try:\n                user = User.objects.get_by_natural_key(maintainer)\n                queryset = queryset.filter(Q(owner=user) |\n                                           Q(co_maintainers=user))\n            except ObjectDoesNotExist:\n                return queryset.none()\n        if category_id:\n            queryset = queryset.filter(categories__id=category_id)\n        if is_featured == \"true\":\n            queryset = queryset.filter(is_featured=True)\n        return queryset.prefetch_related('screenshots', 'translations')\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n        context['categories'] = Category.objects.prefetch_related(\n            'translations').all()\n        category_id = self.kwargs['id']\n        context['is_featured_category'] = self.kwargs\\\n            .get('is_featured_category', False)\n        if category_id:\n            context['current_category'] = Category.objects.get(id=category_id)\n        if self.search_terms:\n            context['search_query'] = ' '.join(self.search_terms)\n        context['url_params'] = self.url_params\n        return context\n\n    @cached_property\n    def url_params(self):\n        \"\"\"URL encoded strings with the GET params of the last request.\n\n        Intended for preserving GET params upon clicking a link by including\n        one (and only one) of these strings in the \"href\" attribute.\n\n        The parameters are divided into three groups: search, filters and\n        ordering. In addition to these three, the returned dict also contains\n        some combinations of them, as specified by the dict keys.\n\n        No leading \"?\" or \"&\".\n\n        :return dict with URL encoded strings.\n        \"\"\"\n\n        search = self._url_params_str('search')\n        filters = self._url_params_str('is_featured', 'maintainer')\n        ordering = self._url_params_str('order_by', 'ordering')\n\n        return {\n            'search': search,\n            'filters': filters,\n            'ordering': ordering,\n            'search_filters': self._join_url_params_strs(search, filters),\n            'filters_ordering': self._join_url_params_strs(filters, ordering),\n        }\n\n    def _url_params_str(self, *params):\n        args = map(lambda param: (param, self.request.GET.get(param, '')),\n                   params)\n        present_args = filter(lambda a: a[1], args)\n        return urlencode(dict(present_args))\n\n    def _join_url_params_strs(self, *strings):\n        return '&'.join(filter(None, strings))\n\n    @cached_property\n    def search_terms(self):\n        return self.request.GET.get('search', '').strip().split()\n\n\nclass AppUploadView(LoginRequiredMixin, TemplateView):\n    template_name = 'app/upload.html'\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n        context['form'] = AppReleaseUploadForm()\n        return context\n\n\nclass AppRegisterView(LoginRequiredMixin, TemplateView):\n    template_name = 'app/register.html'\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n        context['form'] = AppRegisterForm()\n        return context\n", "path": "nextcloudappstore/core/views.py"}, {"content": "from allauth.account.views import signup\nfrom allauth.socialaccount.views import signup as social_signup\nfrom csp.decorators import csp_update\nfrom django.conf import settings\nfrom django.conf.urls import url, include\nfrom django.conf.urls.i18n import i18n_patterns\nfrom django.contrib import admin\nfrom django.contrib.auth.decorators import login_required\nfrom django.views.decorators.http import etag\n\nfrom nextcloudappstore.core.caching import app_rating_etag\nfrom nextcloudappstore.core.feeds import AppReleaseAtomFeed, AppReleaseRssFeed\nfrom nextcloudappstore.core.views import CategoryAppListView, AppDetailView, \\\n    app_description, AppReleasesView, AppUploadView, AppRatingApi, \\\n    AppRegisterView\nfrom nextcloudappstore.scaffolding.views import AppScaffoldingView\n\nadmin.site.login = login_required(admin.site.login)\n\nurlpatterns = [\n    url(r'^$', CategoryAppListView.as_view(), {'id': None}, name='home'),\n    url(r\"^featured$\", CategoryAppListView.as_view(), {'id': None,\n                                                       'is_featured_category':\n                                                           True},\n        name='featured'),\n    url(r\"^signup/$\", csp_update(**settings.CSP_SIGNUP)(signup),\n        name=\"account_signup\"),\n    url(r\"^social/signup/$\", csp_update(**settings.CSP_SIGNUP)(social_signup),\n        name=\"socialaccount_signup\"),\n    url(r'^', include('allauth.urls')),\n    url(r'^categories/(?P<id>[\\w]*)/?$', CategoryAppListView.as_view(),\n        name='category-app-list'),\n    url(r'^developer/apps/generate/?$', AppScaffoldingView.as_view(),\n        name='app-scaffold'),\n    url(r'^developer/apps/releases/new/?$', AppUploadView.as_view(),\n        name='app-upload'),\n    url(r'^developer/apps/new/?$', AppRegisterView.as_view(),\n        name='app-register'),\n    url(r'^apps/(?P<id>[\\w_]+)/?$', AppDetailView.as_view(),\n        name='app-detail'),\n    url(r'^apps/(?P<id>[\\w_]+)/releases/?$', AppReleasesView.as_view(),\n        name='app-releases'),\n    url(r'^apps/(?P<id>[\\w_]+)/description/?$', app_description,\n        name='app-description'),\n    url(r'^apps/(?P<id>[\\w_]+)/ratings.json$',\n        etag(app_rating_etag)(AppRatingApi.as_view()), name='app-ratings'),\n    url(r'^api/', include('nextcloudappstore.api.urls',\n                          namespace='api')),\n    url(r'^account/',\n        include('nextcloudappstore.user.urls', namespace='user')),\n    url(r'^admin/', admin.site.urls),\n    url(r'^i18n/', include('django.conf.urls.i18n')),\n]\n\nurlpatterns += i18n_patterns(\n    url(r'feeds/releases.rss', AppReleaseRssFeed(), name='feeds-releases-rss'),\n    url(r'feeds/releases.atom', AppReleaseAtomFeed(),\n        name='feeds-releases-atom'),\n)\n\nif settings.DEBUG:\n    try:\n        import debug_toolbar\n\n        urlpatterns += [url(r'^__debug__/', include(debug_toolbar.urls)), ]\n    except ImportError:\n        pass\n", "path": "nextcloudappstore/urls.py"}]}