from django.views.generic.detail import DetailView
from django.views.generic.list import ListView
from nextcloudappstore.core.models import App, Category
from django.db.models import Q
from django.utils.functional import cached_property


class AppDetailView(DetailView):
    model = App
    template_name = 'app/detail.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()
        return context


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

    def get_queryset(self):
        category_id = self.kwargs['id']
        queryset = super().get_queryset()

        if category_id:
            queryset = queryset.filter(categories__id=category_id)

        if self.search_terms:
            query = None

            for term in self.search_terms:
                q = Q(translations__name__contains=term) | \
                    Q(translations__description__contains=term)
                if query is None:
                    query = q
                else:
                    query = query | q

            queryset = queryset.filter(query)

            # Remove duplicates that for some reason sometimes occur
            queryset = list(set(queryset))

        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['categories'] = Category.objects.all()
        category_id = self.kwargs['id']
        if category_id:
            context['current_category'] = Category.objects.get(id=category_id)
        if self.search_terms:
            context['search_query'] = ' '.join(self.search_terms)
        return context

    @cached_property
    def search_terms(self):
        if ('search' in self.request.GET) \
                and self.request.GET['search'].strip():
            return self.request.GET['search'].strip().split()
        else:
            return []

@@ -230,16 +230,45 @@
 roperty%0A
+from functools import reduce%0A
 %0A%0Aclass 
@@ -795,17 +795,16 @@
 ryset()%0A
-%0A
         
@@ -886,25 +886,24 @@
 ory_id)%0A
-%0A
         
 if self.
@@ -898,222 +898,78 @@
     
-if self.search_terms:%0A            query = None%0A%0A            for term in self.search_terms:%0A                q = Q(translations__name__contains=term) %7C %5C%0A                    Q(translations__description__contains=
+queryset = queryset.filter(self.create_search_query(self.search_
 term
+s)
 )%0A  
@@ -978,284 +978,68 @@
     
-        if query is None:%0A                    query = q%0A                else:%0A                    query = query %7C q%0A%0A            queryset = queryset.filter(query)%0A%0A            # Remove duplicates that for some reason sometimes occur%0A            queryset = list(set(queryset))%0A
+queryset = list(set(queryset))  # Remove possible duplicates
 %0A   
@@ -1698,16 +1698,16 @@
   else:%0A
-
         
@@ -1720,8 +1720,295 @@
 turn %5B%5D%0A
+%0A    def create_search_query(self, terms):%0A        predicates = map(lambda t: (Q(translations__name__icontains=t) %7C%0A                                    Q(translations__description__icontains=t)),%0A                         terms)%0A        return reduce(lambda x, y: x & y, predicates, Q())%0A

Refactor search query creation