<commit_before>from urllib.parse import urlencode

from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Q
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, redirect
from django.utils.functional import cached_property
from django.utils.translation import get_language, get_language_info
from django.views.generic.base import TemplateView
from django.views.generic.detail import DetailView
from django.views.generic.list import ListView
from rest_framework.generics import ListAPIView
from semantic_version import Version

from nextcloudappstore.core.api.v1.serializers import AppRatingSerializer
from nextcloudappstore.core.forms import AppRatingForm
from nextcloudappstore.core.models import App, Category, AppRating
from nextcloudappstore.core.versioning import pad_min_version


def app_description(request, id):
    app = get_object_or_404(App, id=id)
    return HttpResponse(app.description, content_type='text/plain')


class AppRatingApi(ListAPIView):
    serializer_class = AppRatingSerializer

    def get_queryset(self):
        id = self.kwargs.get('id')
        app = get_object_or_404(App, id=id)
        return AppRating.objects.language(self.request.LANGUAGE_CODE).filter(
            app=app)


class LegalNoticeView(TemplateView):
    template_name = 'legal.html'


class AppDetailView(DetailView):
    model = App
    template_name = 'app/detail.html'
    slug_field = 'id'
    slug_url_kwarg = 'id'

    def post(self, request, id):
        form = AppRatingForm(request.POST, id=id, user=request.user,
                             language_code=request.LANGUAGE_CODE)
        # there is no way that a rating can be invalid by default
        if form.is_valid() and request.user.is_authenticated():
            form.save()
        return redirect('app-detail', id=id)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['rating_form'] = AppRatingForm()
        context['user_has_rated_app'] = False
        if self.request.user.is_authenticated():
            try:
                app_rating = AppRating.objects.get(user=self.request.user,
                                                   app=context['app'])
                # when accessing an empty comment django-parler tries to
                # fall back to the default language. However for comments
                # the default (English) does not always exist. Unfortunately
                # it throws the same exception as non existing models,
                # so we need to access it beforehand
                try:
                    comment = app_rating.comment
                except AppRating.DoesNotExist:
                    comment = ''

                context['rating_form'] = AppRatingForm(initial={
                    'rating': app_rating.rating,
                    'comment': comment
                })
                context['user_has_rated_app'] = True
            except AppRating.DoesNotExist:
                pass
        context['categories'] = Category.objects.all()
        context['latest_releases_by_platform_v'] = \
            self.object.latest_releases_by_platform_v()
        return context


class AppReleasesView(DetailView):
    model = App
    template_name = 'app/releases.html'
    slug_field = 'id'
    slug_url_kwarg = 'id'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['categories'] = Category.objects.all()

        releases = self.object.releases_by_platform_v()
        nightlies = self.object.nightly_releases_by_platform_v()
        versions = set(list(releases.keys()) + list(nightlies.keys()))
        all_releases = list(map(
            lambda v: (v, releases.get(v, []) + nightlies.get(v, [])),
            versions))
        context['releases_by_platform_v'] = \
            self._sort_by_platform_v(all_releases)

        return context

    def _sort_by_platform_v(self, releases_by_platform, reverse=True):
        """Sorts a list of tuples like (<platform version>, [releases]) by
        platform version.

        :param releases_by_platform: A list of tuples.
        :param reverse: Descending order if True, ascending otherwise.
        :return sorted list of tuples.
        """

        return sorted(releases_by_platform, reverse=reverse,
                      key=lambda v: Version(pad_min_version(v[0])))


class CategoryAppListView(ListView):
    model = App
    template_name = 'app/list.html'
    allow_empty = True

    def get_queryset(self):
        order_by = self.request.GET.get('order_by', 'rating_overall')
        ordering = self.request.GET.get('ordering', 'desc')
        featured = self.request.GET.get('featured', False)
        maintainer = self.request.GET.get('maintainer', False)
        sort_columns = []

        allowed_order_by = {'name', 'last_release', 'rating_overall',
                            'rating_recent'}
        if order_by in allowed_order_by:
            if order_by == 'name':
                order_by = 'translations__name'
            if ordering == 'desc':
                sort_columns.append('-' + order_by)
            else:
                sort_columns.append(order_by)

        lang = get_language_info(get_language())['code']
        category_id = self.kwargs['id']
        queryset = App.objects.search(self.search_terms, lang).order_by(
            *sort_columns)
        if maintainer:
            try:
                user = User.objects.get_by_natural_key(maintainer)
                queryset = queryset.filter(Q(owner=user) |
                                           Q(co_maintainers=user))
            except ObjectDoesNotExist:<commit_msg>Only show apps with releases in app list<commit_after>from urllib.parse import urlencode

from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Q
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, redirect
from django.utils.functional import cached_property
from django.utils.translation import get_language, get_language_info
from django.views.generic.base import TemplateView
from django.views.generic.detail import DetailView
from django.views.generic.list import ListView
from rest_framework.generics import ListAPIView
from semantic_version import Version

from nextcloudappstore.core.api.v1.serializers import AppRatingSerializer
from nextcloudappstore.core.forms import AppRatingForm
from nextcloudappstore.core.models import App, Category, AppRating
from nextcloudappstore.core.versioning import pad_min_version


def app_description(request, id):
    app = get_object_or_404(App, id=id)
    return HttpResponse(app.description, content_type='text/plain')


class AppRatingApi(ListAPIView):
    serializer_class = AppRatingSerializer

    def get_queryset(self):
        id = self.kwargs.get('id')
        app = get_object_or_404(App, id=id)
        return AppRating.objects.language(self.request.LANGUAGE_CODE).filter(
            app=app)


class LegalNoticeView(TemplateView):
    template_name = 'legal.html'


class AppDetailView(DetailView):
    model = App
    template_name = 'app/detail.html'
    slug_field = 'id'
    slug_url_kwarg = 'id'

    def post(self, request, id):
        form = AppRatingForm(request.POST, id=id, user=request.user,
                             language_code=request.LANGUAGE_CODE)
        # there is no way that a rating can be invalid by default
        if form.is_valid() and request.user.is_authenticated():
            form.save()
        return redirect('app-detail', id=id)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['rating_form'] = AppRatingForm()
        context['user_has_rated_app'] = False
        if self.request.user.is_authenticated():
            try:
                app_rating = AppRating.objects.get(user=self.request.user,
                                                   app=context['app'])
                # when accessing an empty comment django-parler tries to
                # fall back to the default language. However for comments
                # the default (English) does not always exist. Unfortunately
                # it throws the same exception as non existing models,
                # so we need to access it beforehand
                try:
                    comment = app_rating.comment
                except AppRating.DoesNotExist:
                    comment = ''

                context['rating_form'] = AppRatingForm(initial={
                    'rating': app_rating.rating,
                    'comment': comment
                })
                context['user_has_rated_app'] = True
            except AppRating.DoesNotExist:
                pass
        context['categories'] = Category.objects.all()
        context['latest_releases_by_platform_v'] = \
            self.object.latest_releases_by_platform_v()
        return context


class AppReleasesView(DetailView):
    model = App
    template_name = 'app/releases.html'
    slug_field = 'id'
    slug_url_kwarg = 'id'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['categories'] = Category.objects.all()

        releases = self.object.releases_by_platform_v()
        nightlies = self.object.nightly_releases_by_platform_v()
        versions = set(list(releases.keys()) + list(nightlies.keys()))
        all_releases = list(map(
            lambda v: (v, releases.get(v, []) + nightlies.get(v, [])),
            versions))
        context['releases_by_platform_v'] = \
            self._sort_by_platform_v(all_releases)

        return context

    def _sort_by_platform_v(self, releases_by_platform, reverse=True):
        """Sorts a list of tuples like (<platform version>, [releases]) by
        platform version.

        :param releases_by_platform: A list of tuples.
        :param reverse: Descending order if True, ascending otherwise.
        :return sorted list of tuples.
        """

        return sorted(releases_by_platform, reverse=reverse,
                      key=lambda v: Version(pad_min_version(v[0])))


class CategoryAppListView(ListView):
    model = App
    template_name = 'app/list.html'
    allow_empty = True

    def get_queryset(self):
        order_by = self.request.GET.get('order_by', 'rating_overall')
        ordering = self.request.GET.get('ordering', 'desc')
        featured = self.request.GET.get('featured', False)
        maintainer = self.request.GET.get('maintainer', False)
        sort_columns = []

        allowed_order_by = {'name', 'last_release', 'rating_overall',
                            'rating_recent'}
        if order_by in allowed_order_by:
            if order_by == 'name':
                order_by = 'translations__name'
            if ordering == 'desc':
                sort_columns.append('-' + order_by)
            else:
                sort_columns.append(order_by)

        lang = get_language_info(get_language())['code']
        category_id = self.kwargs['id']
        queryset = App.objects.search(self.search_terms, lang).order_by(
            *sort_columns).filter(releases__gt=0)
        if maintainer:
            try:
                user = User.objects.get_by_natural_key(maintainer)
                queryset = queryset.filter(Q(owner=user) |
                                           Q(co_maintainers=user))
            except ObjectDoesNotExist:
{'fraction_non_alphanumeric': 0.09183321847002067, 'fraction_numerical': 0.001981392143349414, 'mean_word_length': 2.48095952023988, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2112737', 'n_tokens_mistral': 3326, 'n_tokens_neox': 3117, 'n_words': 718}