From d9e5cbf546536e4a14e7f3cb591631515112a205 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 2 Apr 2012 12:40:40 -0500 Subject: Make hidden 'name' search field match exactly This is much more useful than the old contains match if you are trying to narrow down your search to a specific package. Signed-off-by: Dan McGee --- packages/views/search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/views/search.py b/packages/views/search.py index 1431893d..a23c6b4a 100644 --- a/packages/views/search.py +++ b/packages/views/search.py @@ -101,7 +101,7 @@ def parse_form(form, packages): if form.cleaned_data['name']: name = form.cleaned_data['name'] - packages = packages.filter(pkgname__icontains=name) + packages = packages.filter(pkgname=name) if form.cleaned_data['desc']: desc = form.cleaned_data['desc'] -- cgit v1.2.3-2-g168b From b1a9818ddee0e3d0cd4d47b6dbf1c1409992227b Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 3 Apr 2012 14:44:02 -0500 Subject: Include category when linking to bug reports Also change the default category to something legit. Signed-off-by: Dan McGee --- packages/templatetags/package_extras.py | 1 + 1 file changed, 1 insertion(+) (limited to 'packages') diff --git a/packages/templatetags/package_extras.py b/packages/templatetags/package_extras.py index 5cc826ed..975f59f1 100644 --- a/packages/templatetags/package_extras.py +++ b/packages/templatetags/package_extras.py @@ -110,6 +110,7 @@ def bugs_list(package): url = "https://bugs.archlinux.org/" data = { 'project': package.repo.bugs_project, + 'cat[]': package.repo.bugs_category, 'string': package.pkgname, } return link_encode(url, data) -- cgit v1.2.3-2-g168b From ee2a587738f3e571f4e0e61153061ba6853475eb Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 3 Apr 2012 14:55:27 -0500 Subject: Use https:// links for all internal sites We already use HTTPS exclusively for wiki, bugs, forums, etc. and we have it available for our other sites, so link only to the https:// protocol locations when pointing users at other sites. Signed-off-by: Dan McGee --- packages/templatetags/package_extras.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/templatetags/package_extras.py b/packages/templatetags/package_extras.py index 975f59f1..9daecd96 100644 --- a/packages/templatetags/package_extras.py +++ b/packages/templatetags/package_extras.py @@ -93,7 +93,7 @@ def packager_link(user): def scm_link(package, operation): parts = (package.repo.svn_root, operation, package.pkgbase) linkbase = ( - "http://projects.archlinux.org/svntogit/%s.git/%s/trunk?" + "https://projects.archlinux.org/svntogit/%s.git/%s/trunk?" "h=packages/%s") return linkbase % tuple(urlquote(part) for part in parts) -- cgit v1.2.3-2-g168b From b5ab5b1e218219b09857b06f88e522bccb4b5600 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 7 Apr 2012 14:39:01 -0500 Subject: Choose an up-to-date mirror for download URLs Given that we collect a lot of mirror status data, we can utilize it to ensure the download link on the website actually works and newly-added packages have actually been mirrored out. Add a method that attempts to use the mirror status data to determine a mirror we should redirect our download requests to. This can change on a regular basis, and falls back to the old method if no mirror status data is available. Signed-off-by: Dan McGee --- packages/views/__init__.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'packages') diff --git a/packages/views/__init__.py b/packages/views/__init__.py index 2798fff1..abc86d78 100644 --- a/packages/views/__init__.py +++ b/packages/views/__init__.py @@ -14,6 +14,7 @@ from django.views.generic.simple import direct_to_template from main.models import Package, PackageFile, PackageDepend, Arch, Repo from mirrors.models import MirrorUrl +from mirrors.utils import get_mirror_url_for_download from ..models import (PackageRelation, PackageGroup, License, Conflict, Provision, Replacement) from ..utils import (get_group_info, get_differences_info, @@ -225,21 +226,15 @@ def files_json(request, name, repo, arch): def download(request, name, repo, arch): pkg = get_object_or_404(Package, pkgname=name, repo__name__iexact=repo, arch__name=arch) - mirror_urls = MirrorUrl.objects.filter( - mirror__public=True, mirror__active=True, - protocol__protocol__iexact='HTTP') - # look first for an 'Any' URL, then fall back to any HTTP URL - filtered_urls = mirror_urls.filter(mirror__country='Any')[:1] - if not filtered_urls: - filtered_urls = mirror_urls[:1] - if not filtered_urls: + url = get_mirror_url_for_download() + if not url: raise Http404 arch = pkg.arch.name if pkg.arch.agnostic: # grab the first non-any arch to fake the download path arch = Arch.objects.exclude(agnostic=True)[0].name values = { - 'host': filtered_urls[0].url, + 'host': url.url, 'arch': arch, 'repo': pkg.repo.name.lower(), 'file': pkg.filename, -- cgit v1.2.3-2-g168b From 068bc8db6bbfd9e1ed078d72169f34da97914c82 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 7 Apr 2012 14:44:06 -0500 Subject: Move PackageJSONEncoder into package.utils module This will allow it to be used elsewhere, and doesn't really belong in views anyway. Signed-off-by: Dan McGee --- packages/utils.py | 37 ++++++++++++++++++++++++++++++++++++- packages/views/__init__.py | 39 +++------------------------------------ 2 files changed, 39 insertions(+), 37 deletions(-) (limited to 'packages') diff --git a/packages/utils.py b/packages/utils.py index 2a43a08b..a3c13b17 100644 --- a/packages/utils.py +++ b/packages/utils.py @@ -2,13 +2,15 @@ from collections import defaultdict from itertools import chain from operator import itemgetter +from django.core.serializers.json import DjangoJSONEncoder from django.db import connection from django.db.models import Count, Max, F from django.contrib.auth.models import User -from main.models import Package, Arch, Repo +from main.models import Package, PackageDepend, PackageFile, Arch, Repo from main.utils import cache_function, groupby_preserve_order, PackageStandin from .models import (PackageGroup, PackageRelation, + License, Conflict, Provision, Replacement, SignoffSpecification, Signoff, DEFAULT_SIGNOFF_SPEC) @cache_function(127) @@ -422,4 +424,37 @@ def get_signoff_groups(repos=None, user=None): return signoff_groups + +class PackageJSONEncoder(DjangoJSONEncoder): + pkg_attributes = [ 'pkgname', 'pkgbase', 'repo', 'arch', 'pkgver', + 'pkgrel', 'epoch', 'pkgdesc', 'url', 'filename', 'compressed_size', + 'installed_size', 'build_date', 'last_update', 'flag_date', + 'maintainers', 'packager' ] + pkg_list_attributes = [ 'groups', 'licenses', 'conflicts', + 'provides', 'replaces', 'depends' ] + + def default(self, obj): + if hasattr(obj, '__iter__'): + # mainly for queryset serialization + return list(obj) + if isinstance(obj, Package): + data = dict((attr, getattr(obj, attr)) + for attr in self.pkg_attributes) + for attr in self.pkg_list_attributes: + data[attr] = getattr(obj, attr).all() + return data + if isinstance(obj, PackageFile): + filename = obj.filename or '' + return obj.directory + filename + if isinstance(obj, (Repo, Arch)): + return obj.name.lower() + if isinstance(obj, (PackageGroup, License)): + return obj.name + if isinstance(obj, (Conflict, Provision, Replacement, PackageDepend)): + return unicode(obj) + elif isinstance(obj, User): + return obj.username + return super(PackageJSONEncoder, self).default(obj) + + # vim: set ts=4 sw=4 et: diff --git a/packages/views/__init__.py b/packages/views/__init__.py index abc86d78..2ed266e9 100644 --- a/packages/views/__init__.py +++ b/packages/views/__init__.py @@ -4,7 +4,6 @@ from urllib import urlencode from django.contrib import messages from django.contrib.auth.decorators import permission_required from django.contrib.auth.models import User -from django.core.serializers.json import DjangoJSONEncoder from django.http import HttpResponse, Http404 from django.shortcuts import get_object_or_404, redirect from django.utils import simplejson @@ -12,13 +11,12 @@ from django.views.decorators.http import require_POST from django.views.decorators.vary import vary_on_headers from django.views.generic.simple import direct_to_template -from main.models import Package, PackageFile, PackageDepend, Arch, Repo +from main.models import Package, PackageFile, Arch, Repo from mirrors.models import MirrorUrl from mirrors.utils import get_mirror_url_for_download -from ..models import (PackageRelation, PackageGroup, License, - Conflict, Provision, Replacement) +from ..models import PackageRelation from ..utils import (get_group_info, get_differences_info, - multilib_differences, get_wrong_permissions) + multilib_differences, get_wrong_permissions, PackageJSONEncoder) # make other views available from this same package from .flag import flaghelp, flag, flag_confirmed, unflag, unflag_all @@ -26,37 +24,6 @@ from .search import search from .signoff import signoffs, signoff_package, signoff_options, signoffs_json -class PackageJSONEncoder(DjangoJSONEncoder): - pkg_attributes = [ 'pkgname', 'pkgbase', 'repo', 'arch', 'pkgver', - 'pkgrel', 'epoch', 'pkgdesc', 'url', 'filename', 'compressed_size', - 'installed_size', 'build_date', 'last_update', 'flag_date', - 'maintainers', 'packager' ] - pkg_list_attributes = [ 'groups', 'licenses', 'conflicts', - 'provides', 'replaces', 'depends' ] - - def default(self, obj): - if hasattr(obj, '__iter__'): - # mainly for queryset serialization - return list(obj) - if isinstance(obj, Package): - data = dict((attr, getattr(obj, attr)) - for attr in self.pkg_attributes) - for attr in self.pkg_list_attributes: - data[attr] = getattr(obj, attr).all() - return data - if isinstance(obj, PackageFile): - filename = obj.filename or '' - return obj.directory + filename - if isinstance(obj, (Repo, Arch)): - return obj.name.lower() - if isinstance(obj, (PackageGroup, License)): - return obj.name - if isinstance(obj, (Conflict, Provision, Replacement, PackageDepend)): - return unicode(obj) - elif isinstance(obj, User): - return obj.username - return super(PackageJSONEncoder, self).default(obj) - def opensearch(request): if request.is_secure(): domain = "https://%s" % request.META['HTTP_HOST'] -- cgit v1.2.3-2-g168b From 5d9f87c02bd8ad73fdb27600e0afe71284e3082f Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 7 Apr 2012 14:52:39 -0500 Subject: Add JSON search view This still might change and should not be viewed as a public API yet. This has been a longstanding request in FS#13026. Signed-off-by: Dan McGee --- packages/urls.py | 1 + packages/views/__init__.py | 2 +- packages/views/search.py | 26 ++++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/urls.py b/packages/urls.py index 7e12a239..6eddc5fe 100644 --- a/packages/urls.py +++ b/packages/urls.py @@ -22,6 +22,7 @@ urlpatterns = patterns('packages.views', (r'^update/$', 'update'), (r'^$', 'search', {}, 'packages-search'), + (r'^search/json/$', 'search_json'), (r'^(?P\d+)/$', 'search'), (r'^differences/$', 'arch_differences', {}, 'packages-differences'), diff --git a/packages/views/__init__.py b/packages/views/__init__.py index 2ed266e9..6a9c5275 100644 --- a/packages/views/__init__.py +++ b/packages/views/__init__.py @@ -20,7 +20,7 @@ from ..utils import (get_group_info, get_differences_info, # make other views available from this same package from .flag import flaghelp, flag, flag_confirmed, unflag, unflag_all -from .search import search +from .search import search, search_json from .signoff import signoffs, signoff_package, signoff_options, signoffs_json diff --git a/packages/views/search.py b/packages/views/search.py index a23c6b4a..a09de0a7 100644 --- a/packages/views/search.py +++ b/packages/views/search.py @@ -4,11 +4,14 @@ from django import forms from django.contrib.admin.widgets import AdminDateWidget from django.contrib.auth.models import User from django.db.models import Q +from django.http import HttpResponse from django.views.generic import list_detail +from django.utils import simplejson from main.models import Package, Arch, Repo from main.utils import make_choice from ..models import PackageRelation +from ..utils import PackageJSONEncoder def coerce_limit_value(value): @@ -157,4 +160,27 @@ def search(request, page=None): template_object_name="package", extra_context=page_dict) + +def search_json(request): + limit = 250 + + container = { + 'version': 2, + 'limit': limit, + 'valid': False, + 'results': [], + } + + if request.GET: + form = PackageSearchForm(data=request.GET) + if form.is_valid(): + packages = Package.objects.normal() + packages = parse_form(form, packages)[:limit] + container['results'] = packages + container['valid'] = True + + to_json = simplejson.dumps(container, ensure_ascii=False, + cls=PackageJSONEncoder) + return HttpResponse(to_json, mimetype='application/json') + # vim: set ts=4 sw=4 et: -- cgit v1.2.3-2-g168b