From e739d440e91ff58e2efa59f8b142a7f71fa1e77f Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 26 Feb 2015 19:53:44 -0600 Subject: Break out mirror JSON API views Signed-off-by: Dan McGee --- mirrors/urls.py | 9 ++-- mirrors/views/__init__.py | 102 +------------------------------------------- mirrors/views/api.py | 106 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 103 deletions(-) create mode 100644 mirrors/views/api.py diff --git a/mirrors/urls.py b/mirrors/urls.py index b1054380..a41bfdc3 100644 --- a/mirrors/urls.py +++ b/mirrors/urls.py @@ -3,13 +3,16 @@ from django.conf.urls import patterns urlpatterns = patterns('mirrors.views', (r'^$', 'mirrors', {}, 'mirror-list'), (r'^status/$', 'status', {}, 'mirror-status'), - (r'^status/json/$', 'status_json', {}, 'mirror-status-json'), (r'^status/tier/(?P\d+)/$', 'status', {}, 'mirror-status-tier'), + (r'^(?P[\.\-\w]+)/$', 'mirror_details'), + (r'^(?P[\.\-\w]+)/(?P\d+)/$', 'url_details'), +) + +urlpatterns += patterns('mirrors.views.api', + (r'^status/json/$', 'status_json', {}, 'mirror-status-json'), (r'^status/tier/(?P\d+)/json/$', 'status_json', {}, 'mirror-status-tier-json'), (r'^locations/json/$', 'locations_json', {}, 'mirror-locations-json'), - (r'^(?P[\.\-\w]+)/$', 'mirror_details'), (r'^(?P[\.\-\w]+)/json/$', 'mirror_details_json'), - (r'^(?P[\.\-\w]+)/(?P\d+)/$', 'url_details'), ) # vim: set ts=4 sw=4 et: diff --git a/mirrors/views/__init__.py b/mirrors/views/__init__.py index d84b0b10..01e8519d 100644 --- a/mirrors/views/__init__.py +++ b/mirrors/views/__init__.py @@ -1,20 +1,17 @@ from datetime import timedelta from itertools import groupby -import json from operator import attrgetter, itemgetter -from django.core.serializers.json import DjangoJSONEncoder from django.db import connection -from django.http import Http404, HttpResponse +from django.http import Http404 from django.shortcuts import get_object_or_404, render from django.utils.timezone import now -from django.views.decorators.cache import cache_page from django.views.decorators.http import condition from django_countries.fields import Country from ..models import (Mirror, MirrorUrl, MirrorProtocol, MirrorLog, CheckLocation) -from ..utils import get_mirror_statuses, get_mirror_errors, DEFAULT_CUTOFF +from ..utils import get_mirror_statuses, get_mirror_errors def mirrors(request): @@ -84,21 +81,6 @@ def mirror_details(request, name): return render(request, 'mirrors/mirror_details.html', context) -def mirror_details_json(request, name): - authorized = request.user.is_authenticated() - mirror = get_object_or_404(Mirror, name=name) - if not authorized and (not mirror.public or not mirror.active): - raise Http404 - status_info = get_mirror_statuses(mirror_id=mirror.id, - show_all=authorized) - data = status_info.copy() - data['version'] = 3 - to_json = json.dumps(data, ensure_ascii=False, - cls=ExtendedMirrorStatusJSONEncoder) - response = HttpResponse(to_json, content_type='application/json') - return response - - def url_details(request, name, url_id): url = get_object_or_404(MirrorUrl.objects.select_related(), id=url_id, mirror__name=name) @@ -164,84 +146,4 @@ def status(request, tier=None): }) return render(request, 'mirrors/status.html', context) - -class MirrorStatusJSONEncoder(DjangoJSONEncoder): - '''Base JSONEncoder extended to handle datetime.timedelta and MirrorUrl - serialization. The base class takes care of datetime.datetime types.''' - url_attributes = ('url', 'protocol', 'last_sync', 'completion_pct', - 'delay', 'duration_avg', 'duration_stddev', 'score') - - def default(self, obj): - if isinstance(obj, timedelta): - # always returned as integer seconds - return obj.days * 24 * 3600 + obj.seconds - if isinstance(obj, MirrorUrl): - data = {attr: getattr(obj, attr) for attr in self.url_attributes} - country = obj.country - data['country'] = unicode(country.name) - data['country_code'] = country.code - return data - if isinstance(obj, MirrorProtocol): - return unicode(obj) - return super(MirrorStatusJSONEncoder, self).default(obj) - - -class ExtendedMirrorStatusJSONEncoder(MirrorStatusJSONEncoder): - '''Adds URL check history information.''' - log_attributes = ('check_time', 'last_sync', 'duration', 'is_success', - 'location_id') - - def default(self, obj): - if isinstance(obj, MirrorUrl): - data = super(ExtendedMirrorStatusJSONEncoder, self).default(obj) - cutoff = now() - DEFAULT_CUTOFF - data['logs'] = list(obj.logs.filter( - check_time__gte=cutoff).order_by('check_time')) - return data - if isinstance(obj, MirrorLog): - return {attr: getattr(obj, attr) for attr in self.log_attributes} - return super(ExtendedMirrorStatusJSONEncoder, self).default(obj) - - -@cache_page(67) -@condition(last_modified_func=status_last_modified) -def status_json(request, tier=None): - if tier is not None: - tier = int(tier) - if tier not in [t[0] for t in Mirror.TIER_CHOICES]: - raise Http404 - status_info = get_mirror_statuses() - data = status_info.copy() - if tier is not None: - data['urls'] = [url for url in data['urls'] if url.mirror.tier == tier] - data['version'] = 3 - to_json = json.dumps(data, ensure_ascii=False, cls=MirrorStatusJSONEncoder) - response = HttpResponse(to_json, content_type='application/json') - return response - - -class LocationJSONEncoder(DjangoJSONEncoder): - '''Base JSONEncoder extended to handle CheckLocation objects.''' - - def default(self, obj): - if isinstance(obj, CheckLocation): - return { - 'id': obj.pk, - 'hostname': obj.hostname, - 'source_ip': obj.source_ip, - 'country': unicode(obj.country.name), - 'country_code': obj.country.code, - 'ip_version': obj.ip_version, - } - return super(LocationJSONEncoder, self).default(obj) - - -def locations_json(request): - data = {} - data['version'] = 1 - data['locations'] = list(CheckLocation.objects.all().order_by('pk')) - to_json = json.dumps(data, ensure_ascii=False, cls=LocationJSONEncoder) - response = HttpResponse(to_json, content_type='application/json') - return response - # vim: set ts=4 sw=4 et: diff --git a/mirrors/views/api.py b/mirrors/views/api.py new file mode 100644 index 00000000..06574082 --- /dev/null +++ b/mirrors/views/api.py @@ -0,0 +1,106 @@ +from datetime import timedelta +import json + +from django.core.serializers.json import DjangoJSONEncoder +from django.http import Http404, HttpResponse +from django.shortcuts import get_object_or_404 +from django.utils.timezone import now + +from ..models import (Mirror, MirrorUrl, MirrorProtocol, MirrorLog, + CheckLocation) +from ..utils import get_mirror_statuses, DEFAULT_CUTOFF + + +class MirrorStatusJSONEncoder(DjangoJSONEncoder): + '''Base JSONEncoder extended to handle datetime.timedelta and MirrorUrl + serialization. The base class takes care of datetime.datetime types.''' + url_attributes = ('url', 'protocol', 'last_sync', 'completion_pct', + 'delay', 'duration_avg', 'duration_stddev', 'score') + + def default(self, obj): + if isinstance(obj, timedelta): + # always returned as integer seconds + return obj.days * 24 * 3600 + obj.seconds + if isinstance(obj, MirrorUrl): + data = {attr: getattr(obj, attr) for attr in self.url_attributes} + country = obj.country + data['country'] = unicode(country.name) + data['country_code'] = country.code + return data + if isinstance(obj, MirrorProtocol): + return unicode(obj) + return super(MirrorStatusJSONEncoder, self).default(obj) + + +class ExtendedMirrorStatusJSONEncoder(MirrorStatusJSONEncoder): + '''Adds URL check history information.''' + log_attributes = ('check_time', 'last_sync', 'duration', 'is_success', + 'location_id') + + def default(self, obj): + if isinstance(obj, MirrorUrl): + data = super(ExtendedMirrorStatusJSONEncoder, self).default(obj) + cutoff = now() - DEFAULT_CUTOFF + data['logs'] = list(obj.logs.filter( + check_time__gte=cutoff).order_by('check_time')) + return data + if isinstance(obj, MirrorLog): + return {attr: getattr(obj, attr) for attr in self.log_attributes} + return super(ExtendedMirrorStatusJSONEncoder, self).default(obj) + + +class LocationJSONEncoder(DjangoJSONEncoder): + '''Base JSONEncoder extended to handle CheckLocation objects.''' + + def default(self, obj): + if isinstance(obj, CheckLocation): + return { + 'id': obj.pk, + 'hostname': obj.hostname, + 'source_ip': obj.source_ip, + 'country': unicode(obj.country.name), + 'country_code': obj.country.code, + 'ip_version': obj.ip_version, + } + return super(LocationJSONEncoder, self).default(obj) + + +def status_json(request, tier=None): + if tier is not None: + tier = int(tier) + if tier not in [t[0] for t in Mirror.TIER_CHOICES]: + raise Http404 + status_info = get_mirror_statuses() + data = status_info.copy() + if tier is not None: + data['urls'] = [url for url in data['urls'] if url.mirror.tier == tier] + data['version'] = 3 + to_json = json.dumps(data, ensure_ascii=False, cls=MirrorStatusJSONEncoder) + response = HttpResponse(to_json, content_type='application/json') + return response + + +def mirror_details_json(request, name): + authorized = request.user.is_authenticated() + mirror = get_object_or_404(Mirror, name=name) + if not authorized and (not mirror.public or not mirror.active): + raise Http404 + status_info = get_mirror_statuses(mirror_id=mirror.id, + show_all=authorized) + data = status_info.copy() + data['version'] = 3 + to_json = json.dumps(data, ensure_ascii=False, + cls=ExtendedMirrorStatusJSONEncoder) + response = HttpResponse(to_json, content_type='application/json') + return response + + +def locations_json(request): + data = {} + data['version'] = 1 + data['locations'] = list(CheckLocation.objects.all().order_by('pk')) + to_json = json.dumps(data, ensure_ascii=False, cls=LocationJSONEncoder) + response = HttpResponse(to_json, content_type='application/json') + return response + +# vim: set ts=4 sw=4 et: -- cgit v1.2.3