From 76c37ce3acc7a4af0271c7535d4a33042f7749b5 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 24 Jul 2012 09:35:55 -0500 Subject: Replace deprecated direct_to_template() with render() shortcut Now that Django actually provides a concise way to use a RequestContext object without instantiating it, we can use that rather than the old function-based generic view that worked well to do the same. Additionally, these function-based generic views will be gone in Django 1.5, so might as well make the move now. Signed-off-by: Dan McGee --- public/views.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'public/views.py') diff --git a/public/views.py b/public/views.py index 3ea8f841..3f68545c 100644 --- a/public/views.py +++ b/public/views.py @@ -5,8 +5,8 @@ from django.conf import settings from django.contrib.auth.models import User from django.db.models import Count, Q from django.http import Http404 +from django.shortcuts import render from django.views.decorators.cache import cache_control -from django.views.generic.simple import direct_to_template from devel.models import MasterKey, PGPSignature from main.models import Arch, Repo, Donor @@ -21,7 +21,7 @@ def index(request): 'news_updates': News.objects.order_by('-postdate', '-id')[:15], 'pkg_updates': pkgs, } - return direct_to_template(request, 'public/index.html', context) + return render(request, 'public/index.html', context) USER_LISTS = { 'devs': { @@ -55,14 +55,14 @@ def userlist(request, user_type='devs'): users = users.distinct() context = USER_LISTS[user_type].copy() context['users'] = users - return direct_to_template(request, 'public/userlist.html', context) + return render(request, 'public/userlist.html', context) @cache_control(max_age=300) def donate(request): context = { 'donors': Donor.objects.filter(visible=True).order_by('name'), } - return direct_to_template(request, 'public/donate.html', context) + return render(request, 'public/donate.html', context) @cache_control(max_age=300) def download(request): @@ -76,7 +76,7 @@ def download(request): 'releng_pxeboot_url': settings.PXEBOOT_URL, 'mirror_urls': mirror_urls, } - return direct_to_template(request, 'public/download.html', context) + return render(request, 'public/download.html', context) @cache_control(max_age=300) def feeds(request): @@ -84,7 +84,7 @@ def feeds(request): 'arches': Arch.objects.all(), 'repos': Repo.objects.all(), } - return direct_to_template(request, 'public/feeds.html', context) + return render(request, 'public/feeds.html', context) @cache_control(max_age=300) def keys(request): @@ -113,6 +113,6 @@ def keys(request): 'active_users': users, 'signatures': signatures, } - return direct_to_template(request, 'public/keys.html', context) + return render(request, 'public/keys.html', context) # vim: set ts=4 sw=4 et: -- cgit v1.2.3 From 0cc369e985dd6376f0367e4b57e980ce14231796 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 31 Jul 2012 00:09:28 -0500 Subject: Update several bits and pieces for staging packages This will prevent [staging] packages from cluttering normal user's view on the website, but allow us to still import everything from this repository for developer use. Signed-off-by: Dan McGee --- public/views.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'public/views.py') diff --git a/public/views.py b/public/views.py index 3f68545c..c8854b72 100644 --- a/public/views.py +++ b/public/views.py @@ -16,7 +16,10 @@ from .utils import get_recent_updates @cache_control(max_age=300) def index(request): - pkgs = get_recent_updates() + if request.user.is_authenticated(): + pkgs = get_recent_updates(testing=True, staging=True) + else: + pkgs = get_recent_updates() context = { 'news_updates': News.objects.order_by('-postdate', '-id')[:15], 'pkg_updates': pkgs, -- cgit v1.2.3 From 3f0c024754047d92e8ce4aa4ecf93a06865f8448 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 31 Jul 2012 18:37:30 -0500 Subject: PGP key handling updates * Import signatures for all known keys, not just active developers * Ensure we are only showing and accounting for active developers on the master keys page * Add a new table showing signatures between developers Signed-off-by: Dan McGee --- public/views.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'public/views.py') diff --git a/public/views.py b/public/views.py index c8854b72..312cb3b2 100644 --- a/public/views.py +++ b/public/views.py @@ -91,30 +91,38 @@ def feeds(request): @cache_control(max_age=300) def keys(request): + users = User.objects.filter(is_active=True).select_related( + 'userprofile__pgp_key').order_by('first_name', 'last_name') + user_key_ids = frozenset(user.userprofile.pgp_key[-16:] for user in users + if user.userprofile.pgp_key) + not_expired = Q(expires__gt=datetime.utcnow) | Q(expires__isnull=True) master_keys = MasterKey.objects.select_related('owner', 'revoker', 'owner__userprofile', 'revoker__userprofile').filter( revoked__isnull=True) + master_key_ids = frozenset(key.pgp_key[-16:] for key in master_keys) - sig_counts = PGPSignature.objects.filter( - not_expired, valid=True).values_list('signer').annotate( + sig_counts = PGPSignature.objects.filter(not_expired, valid=True, + signee__in=user_key_ids).values_list('signer').annotate( Count('signer')) sig_counts = dict((key_id[-16:], ct) for key_id, ct in sig_counts) for key in master_keys: key.signature_count = sig_counts.get(key.pgp_key[-16:], 0) - users = User.objects.filter(is_active=True).select_related( - 'userprofile__pgp_key').order_by('first_name', 'last_name') - # frozenset because we are going to do lots of __contains__ lookups signatures = frozenset(PGPSignature.objects.filter( not_expired, valid=True).values_list('signer', 'signee')) + restrict = Q(signer__in=user_key_ids) & Q(signee__in=user_key_ids) + cross_signatures = PGPSignature.objects.filter(restrict, + not_expired, valid=True).order_by('created') + context = { 'keys': master_keys, 'active_users': users, 'signatures': signatures, + 'cross_signatures': cross_signatures, } return render(request, 'public/keys.html', context) -- cgit v1.2.3 From 3eed426027ed6bc87b58f82d48da06bea55b265f Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 25 Sep 2012 00:30:05 -0500 Subject: Add structured data to developer listing pages Signed-off-by: Dan McGee --- public/views.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'public/views.py') diff --git a/public/views.py b/public/views.py index 312cb3b2..35315e0e 100644 --- a/public/views.py +++ b/public/views.py @@ -29,14 +29,17 @@ def index(request): USER_LISTS = { 'devs': { 'user_type': 'Developers', + 'user_title': 'Developer', 'description': "This is a list of the current Arch Linux Developers. They maintain the [core] and [extra] package repositories in addition to doing any other developer duties.", }, 'tus': { 'user_type': 'Trusted Users', + 'user_title': 'Trusted User', 'description': "Here are all your friendly Arch Linux Trusted Users who are in charge of the [community] repository.", }, 'fellows': { 'user_type': 'Fellows', + 'user_title': 'Fellow', 'description': "Below you can find a list of ex-developers (aka project fellows). These folks helped make Arch what it is today. Thanks!", }, } -- cgit v1.2.3 From 67fef06fe8d07e8b832e447a6b2064fb051a5ef9 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 25 Sep 2012 00:49:54 -0500 Subject: Only show staging feeds to logged-in users This doesn't prevent unauthenticated users from accessing the feeds, but it should reduce clutter and confusion on the feeds index page for users unlikely to need these feeds. Signed-off-by: Dan McGee --- public/views.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'public/views.py') diff --git a/public/views.py b/public/views.py index 35315e0e..42f2f345 100644 --- a/public/views.py +++ b/public/views.py @@ -86,9 +86,12 @@ def download(request): @cache_control(max_age=300) def feeds(request): + repos = Repo.objects.all() + if not request.user.is_authenticated(): + repos = repos.filter(staging=False) context = { 'arches': Arch.objects.all(), - 'repos': Repo.objects.all(), + 'repos': repos, } return render(request, 'public/feeds.html', context) -- cgit v1.2.3 From 45d81a9578e846062550335495dbceb82f16a1a0 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 13 Nov 2012 10:03:55 -0600 Subject: Move JSON keys view to public/ app This seems like a more appropriate place, and now the visualization is done here anyway so we should move the data backing it. Signed-off-by: Dan McGee --- public/views.py | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) (limited to 'public/views.py') diff --git a/public/views.py b/public/views.py index 42f2f345..96120761 100644 --- a/public/views.py +++ b/public/views.py @@ -1,12 +1,13 @@ from datetime import datetime +import json from operator import attrgetter from django.conf import settings from django.contrib.auth.models import User from django.db.models import Count, Q -from django.http import Http404 +from django.http import Http404, HttpResponse from django.shortcuts import render -from django.views.decorators.cache import cache_control +from django.views.decorators.cache import cache_control, cache_page from devel.models import MasterKey, PGPSignature from main.models import Arch, Repo, Donor @@ -14,6 +15,7 @@ from mirrors.models import MirrorUrl from news.models import News from .utils import get_recent_updates + @cache_control(max_age=300) def index(request): if request.user.is_authenticated(): @@ -44,6 +46,7 @@ USER_LISTS = { }, } + @cache_control(max_age=300) def userlist(request, user_type='devs'): users = User.objects.order_by( @@ -63,6 +66,7 @@ def userlist(request, user_type='devs'): context['users'] = users return render(request, 'public/userlist.html', context) + @cache_control(max_age=300) def donate(request): context = { @@ -70,6 +74,7 @@ def donate(request): } return render(request, 'public/donate.html', context) + @cache_control(max_age=300) def download(request): mirror_urls = MirrorUrl.objects.select_related('mirror').filter( @@ -84,6 +89,7 @@ def download(request): } return render(request, 'public/download.html', context) + @cache_control(max_age=300) def feeds(request): repos = Repo.objects.all() @@ -95,6 +101,7 @@ def feeds(request): } return render(request, 'public/feeds.html', context) + @cache_control(max_age=300) def keys(request): users = User.objects.filter(is_active=True).select_related( @@ -132,4 +139,46 @@ def keys(request): } return render(request, 'public/keys.html', context) + +@cache_page(1800) +def keys_json(request): + node_list = [] + + users = User.objects.filter(is_active=True).select_related('userprofile') + node_list.extend({ + 'name': dev.get_full_name(), + 'key': dev.userprofile.pgp_key, + 'group': 'dev' + } for dev in users.filter(groups__name='Developers')) + node_list.extend({ + 'name': tu.get_full_name(), + 'key': tu.userprofile.pgp_key, + 'group': 'tu' + } for tu in users.filter(groups__name='Trusted Users').exclude( + groups__name='Developers')) + + master_keys = MasterKey.objects.select_related('owner').filter( + revoked__isnull=True) + node_list.extend({ + 'name': 'Master Key (%s)' % key.owner.get_full_name(), + 'key': key.pgp_key, + 'group': 'master' + } for key in master_keys) + + node_list.append({ + 'name': 'CA Cert Signing Authority', + 'key': 'A31D4F81EF4EBD07B456FA04D2BB0D0165D0FD58', + 'group': 'cacert', + }) + + not_expired = Q(expires__gt=datetime.utcnow) | Q(expires__isnull=True) + signatures = PGPSignature.objects.filter(not_expired, valid=True) + edge_list = [{ 'signee': sig.signee, 'signer': sig.signer } + for sig in signatures] + + data = { 'nodes': node_list, 'edges': edge_list } + + to_json = json.dumps(data, ensure_ascii=False) + return HttpResponse(to_json, mimetype='application/json') + # vim: set ts=4 sw=4 et: -- cgit v1.2.3 From 6dd4d54bb0adbbb0f8c2b1beaa92b7a58971cf88 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 16 Nov 2012 16:20:11 -0600 Subject: Use Python 2.7 dictionary comprehension syntax Rather than the old idiom of dict((k, v) for <> in <>). Signed-off-by: Dan McGee --- public/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'public/views.py') diff --git a/public/views.py b/public/views.py index 96120761..3e15f9df 100644 --- a/public/views.py +++ b/public/views.py @@ -118,7 +118,7 @@ def keys(request): sig_counts = PGPSignature.objects.filter(not_expired, valid=True, signee__in=user_key_ids).values_list('signer').annotate( Count('signer')) - sig_counts = dict((key_id[-16:], ct) for key_id, ct in sig_counts) + sig_counts = {key_id[-16:]: ct for key_id, ct in sig_counts} for key in master_keys: key.signature_count = sig_counts.get(key.pgp_key[-16:], 0) -- cgit v1.2.3 From f7331a0eca351300685ebee494e810d8c82c35b1 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 20 Nov 2012 19:16:25 -0600 Subject: Add Release model to releng This should prevent the need for monthly template updates from Pierre and Thomas; best to just let them enter the data themselves and have it show up on the website. Signed-off-by: Dan McGee --- public/views.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'public/views.py') diff --git a/public/views.py b/public/views.py index 3e15f9df..fefe032e 100644 --- a/public/views.py +++ b/public/views.py @@ -13,6 +13,7 @@ from devel.models import MasterKey, PGPSignature from main.models import Arch, Repo, Donor from mirrors.models import MirrorUrl from news.models import News +from releng.models import Release from .utils import get_recent_updates @@ -77,12 +78,17 @@ def donate(request): @cache_control(max_age=300) def download(request): + try: + release = Release.objects.filter(available=True).latest() + except Release.DoesNotExist: + release = None mirror_urls = MirrorUrl.objects.select_related('mirror').filter( protocol__default=True, mirror__public=True, mirror__active=True, mirror__isos=True) sort_by = attrgetter('real_country.name', 'mirror.name') mirror_urls = sorted(mirror_urls, key=sort_by) context = { + 'release': release, 'releng_iso_url': settings.ISO_LIST_URL, 'releng_pxeboot_url': settings.PXEBOOT_URL, 'mirror_urls': mirror_urls, -- cgit v1.2.3 From e7c331d361e0b6b5c9fb498793953119afcbf741 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 27 Dec 2012 22:51:20 -0600 Subject: Fix master key signing total counts Commit 4c69911982 had an inadvertent side effect here; we need to explicitly disable ordering for the annotate() to work correctly. Signed-off-by: Dan McGee --- public/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'public/views.py') diff --git a/public/views.py b/public/views.py index fefe032e..44ceb45d 100644 --- a/public/views.py +++ b/public/views.py @@ -122,7 +122,7 @@ def keys(request): master_key_ids = frozenset(key.pgp_key[-16:] for key in master_keys) sig_counts = PGPSignature.objects.filter(not_expired, valid=True, - signee__in=user_key_ids).values_list('signer').annotate( + signee__in=user_key_ids).order_by().values_list('signer').annotate( Count('signer')) sig_counts = {key_id[-16:]: ct for key_id, ct in sig_counts} -- cgit v1.2.3 From 66850026ca934e5a09238e9033c541cdc5085a42 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 13 Jan 2013 22:34:33 -0600 Subject: Use content_type and not mimetype on HttpResponse() Bug #16519 in Django deprecates mimetype, so update our code accordingly. Signed-off-by: Dan McGee --- public/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'public/views.py') diff --git a/public/views.py b/public/views.py index 44ceb45d..65b0c31f 100644 --- a/public/views.py +++ b/public/views.py @@ -185,6 +185,6 @@ def keys_json(request): data = { 'nodes': node_list, 'edges': edge_list } to_json = json.dumps(data, ensure_ascii=False) - return HttpResponse(to_json, mimetype='application/json') + return HttpResponse(to_json, content_type='application/json') # vim: set ts=4 sw=4 et: -- cgit v1.2.3 From 6f0ae6746baea657ee6d7c21ac0813a04f825443 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 14 Jan 2013 01:00:11 -0600 Subject: Drop country column from mirror table We now always look for this information at the URL level, not the mirror level. This simplifies quite a bit of code in and around the mirror views. Signed-off-by: Dan McGee --- public/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'public/views.py') diff --git a/public/views.py b/public/views.py index 65b0c31f..e15f5b89 100644 --- a/public/views.py +++ b/public/views.py @@ -85,7 +85,7 @@ def download(request): mirror_urls = MirrorUrl.objects.select_related('mirror').filter( protocol__default=True, mirror__public=True, mirror__active=True, mirror__isos=True) - sort_by = attrgetter('real_country.name', 'mirror.name') + sort_by = attrgetter('country.name', 'mirror.name') mirror_urls = sorted(mirror_urls, key=sort_by) context = { 'release': release, -- cgit v1.2.3 From cba22a378b48f1a4f185a56a21f39483595cf8a6 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 18 Jan 2013 20:01:22 -0600 Subject: Don't pull and sort mirror URLs unless we have to On the download page, the explicit sorted() call was forcing evaluation of the Django queryset, even if we never actually needed the results because the template fragment was cached. Wrap it all in a callable function which looks the same to the template, but saves us the cost of evaluation every single page view. Signed-off-by: Dan McGee --- public/views.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'public/views.py') diff --git a/public/views.py b/public/views.py index e15f5b89..3c823c9d 100644 --- a/public/views.py +++ b/public/views.py @@ -82,11 +82,16 @@ def download(request): release = Release.objects.filter(available=True).latest() except Release.DoesNotExist: release = None - mirror_urls = MirrorUrl.objects.select_related('mirror').filter( - protocol__default=True, - mirror__public=True, mirror__active=True, mirror__isos=True) - sort_by = attrgetter('country.name', 'mirror.name') - mirror_urls = sorted(mirror_urls, key=sort_by) + + def mirror_urls(): + '''In order to ensure this is lazily evaluated since we can't do + sorting at the database level, make it a callable.''' + urls = MirrorUrl.objects.select_related('mirror').filter( + protocol__default=True, + mirror__public=True, mirror__active=True, mirror__isos=True) + sort_by = attrgetter('country.name', 'mirror.name') + return sorted(urls, key=sort_by) + context = { 'release': release, 'releng_iso_url': settings.ISO_LIST_URL, -- cgit v1.2.3 From 23ef118ac129e17d251634d2ef3c88c6d74279e3 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 19 Jan 2013 10:37:14 -0600 Subject: Don't redefine mirror_url function every call If we pull this out and define it at the top level once, we save the interpreter a fair amount of work. Signed-off-by: Dan McGee --- public/views.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'public/views.py') diff --git a/public/views.py b/public/views.py index 3c823c9d..22cb8759 100644 --- a/public/views.py +++ b/public/views.py @@ -76,6 +76,16 @@ def donate(request): return render(request, 'public/donate.html', context) +def _mirror_urls(): + '''In order to ensure this is lazily evaluated since we can't do + sorting at the database level, make it a callable.''' + urls = MirrorUrl.objects.select_related('mirror').filter( + protocol__default=True, + mirror__public=True, mirror__active=True, mirror__isos=True) + sort_by = attrgetter('country.name', 'mirror.name') + return sorted(urls, key=sort_by) + + @cache_control(max_age=300) def download(request): try: @@ -83,20 +93,11 @@ def download(request): except Release.DoesNotExist: release = None - def mirror_urls(): - '''In order to ensure this is lazily evaluated since we can't do - sorting at the database level, make it a callable.''' - urls = MirrorUrl.objects.select_related('mirror').filter( - protocol__default=True, - mirror__public=True, mirror__active=True, mirror__isos=True) - sort_by = attrgetter('country.name', 'mirror.name') - return sorted(urls, key=sort_by) - context = { 'release': release, 'releng_iso_url': settings.ISO_LIST_URL, 'releng_pxeboot_url': settings.PXEBOOT_URL, - 'mirror_urls': mirror_urls, + 'mirror_urls': _mirror_urls, } return render(request, 'public/download.html', context) -- cgit v1.2.3