diff options
Diffstat (limited to 'packages/views/search.py')
| -rw-r--r-- | packages/views/search.py | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/packages/views/search.py b/packages/views/search.py new file mode 100644 index 00000000..6e892251 --- /dev/null +++ b/packages/views/search.py @@ -0,0 +1,172 @@ +import json + +from django import forms +from django.contrib.auth.models import User +from django.db.models import Q +from django.http import HttpResponse +from django.views.generic import ListView + +from devel.models import UserProfile +from main.models import Package, Arch, Repo +from main.utils import empty_response, make_choice +from ..models import PackageRelation +from ..utils import attach_maintainers, PackageJSONEncoder + + +class PackageSearchForm(forms.Form): + repo = forms.MultipleChoiceField(required=False) + arch = forms.MultipleChoiceField(required=False) + name = forms.CharField(required=False) + desc = forms.CharField(required=False) + q = forms.CharField(required=False) + sort = forms.CharField(required=False, widget=forms.HiddenInput()) + maintainer = forms.ChoiceField(required=False) + packager = forms.ChoiceField(required=False) + flagged = forms.ChoiceField( + choices=[('', 'All')] + make_choice(['Flagged', 'Not Flagged']), + required=False) + + def __init__(self, *args, **kwargs): + show_staging = kwargs.pop('show_staging', False) + super(PackageSearchForm, self).__init__(*args, **kwargs) + repos = Repo.objects.all() + if not show_staging: + repos = repos.filter(staging=False) + self.fields['repo'].choices = make_choice( + [repo.name for repo in repos]) + self.fields['arch'].choices = make_choice( + [arch.name for arch in Arch.objects.all()]) + self.fields['q'].widget.attrs.update({"size": "30"}) + + profile_ids = UserProfile.allowed_repos.through.objects.values('userprofile_id') + people = User.objects.filter( + is_active=True, userprofile__id__in=profile_ids).order_by( + 'first_name', 'last_name') + maintainers = [('', 'All'), ('orphan', 'Orphan')] + \ + [(p.username, p.get_full_name()) for p in people] + packagers = [('', 'All'), ('unknown', 'Unknown')] + \ + [(p.username, p.get_full_name()) for p in people] + + self.fields['maintainer'].choices = maintainers + self.fields['packager'].choices = packagers + + def exact_matches(self): + # only do exact match search if 'q' is sole parameter + if self.changed_data != ['q']: + return [] + return Package.objects.normal().filter(pkgname=self.cleaned_data['q']) + + +def parse_form(form, packages): + if form.cleaned_data['repo']: + packages = packages.filter( + repo__name__in=form.cleaned_data['repo']) + + if form.cleaned_data['arch']: + packages = packages.filter( + arch__name__in=form.cleaned_data['arch']) + + if form.cleaned_data['maintainer'] == 'orphan': + inner_q = PackageRelation.objects.all().values('pkgbase') + packages = packages.exclude(pkgbase__in=inner_q) + elif form.cleaned_data['maintainer']: + inner_q = PackageRelation.objects.filter( + user__username=form.cleaned_data['maintainer']).values('pkgbase') + packages = packages.filter(pkgbase__in=inner_q) + + if form.cleaned_data['packager'] == 'unknown': + packages = packages.filter(packager__isnull=True) + elif form.cleaned_data['packager']: + packages = packages.filter( + packager__username=form.cleaned_data['packager']) + + if form.cleaned_data['flagged'] == 'Flagged': + packages = packages.filter(flag_date__isnull=False) + elif form.cleaned_data['flagged'] == 'Not Flagged': + packages = packages.filter(flag_date__isnull=True) + + if form.cleaned_data['name']: + name = form.cleaned_data['name'] + packages = packages.filter(pkgname=name) + + if form.cleaned_data['desc']: + desc = form.cleaned_data['desc'] + packages = packages.filter(pkgdesc__icontains=desc) + + if form.cleaned_data['q']: + query = form.cleaned_data['q'] + q = Q(pkgname__icontains=query) | Q(pkgdesc__icontains=query) + packages = packages.filter(q) + + return packages + + +class SearchListView(ListView): + template_name = "packages/search.html" + paginate_by = 100 + + sort_fields = ("arch", "repo", "pkgname", "pkgbase", "compressed_size", + "installed_size", "build_date", "last_update", "flag_date") + allowed_sort = list(sort_fields) + ["-" + s for s in sort_fields] + + def get(self, request, *args, **kwargs): + if request.method == 'HEAD': + return empty_response() + self.form = PackageSearchForm(data=request.GET, + show_staging=self.request.user.is_authenticated()) + return super(SearchListView, self).get(request, *args, **kwargs) + + def get_queryset(self): + packages = Package.objects.normal() + if not self.request.user.is_authenticated(): + packages = packages.filter(repo__staging=False) + if self.form.is_valid(): + packages = parse_form(self.form, packages) + sort = self.form.cleaned_data['sort'] + if sort in self.allowed_sort: + packages = packages.order_by(sort) + else: + packages = packages.order_by('pkgname') + return packages + + # Form had errors so don't return any results + return Package.objects.none() + + def get_context_data(self, **kwargs): + context = super(SearchListView, self).get_context_data(**kwargs) + query_params = self.request.GET.copy() + query_params.pop('page', None) + context['current_query'] = query_params.urlencode() + context['search_form'] = self.form + return context + + +def search_json(request): + limit = 250 + + container = { + 'version': 2, + 'limit': limit, + 'valid': False, + 'results': [], + } + + if request.GET: + form = PackageSearchForm(data=request.GET, + show_staging=request.user.is_authenticated()) + if form.is_valid(): + packages = Package.objects.select_related('arch', 'repo', + 'packager') + if not request.user.is_authenticated(): + packages = packages.filter(repo__staging=False) + packages = parse_form(form, packages)[:limit] + packages = packages.prefetch_related('groups', 'licenses', + 'conflicts', 'provides', 'replaces', 'depends') + attach_maintainers(packages) + container['results'] = packages + container['valid'] = True + + to_json = json.dumps(container, ensure_ascii=False, cls=PackageJSONEncoder) + return HttpResponse(to_json, content_type='application/json') + +# vim: set ts=4 sw=4 et: |
