diff options
author | Dan McGee <dan@archlinux.org> | 2013-12-15 13:22:41 -0600 |
---|---|---|
committer | Dan McGee <dan@archlinux.org> | 2013-12-15 13:28:13 -0600 |
commit | 79aef280ddf0c704fd40d0077822a8ff7548437e (patch) | |
tree | 706e88b3e072402feeb1baee7e6cbaa658226aeb | |
parent | 3c7b02753a4f742eeb66b8deea2fc3f179b87b8e (diff) |
Add mirror URL details page
This will allow those that care about mirrors to zoom into URL-level
details for each mirror and examine the individual check results.
Signed-off-by: Dan McGee <dan@archlinux.org>
-rw-r--r-- | mirrors/models.py | 2 | ||||
-rw-r--r-- | mirrors/urls.py | 1 | ||||
-rw-r--r-- | mirrors/views.py | 19 | ||||
-rw-r--r-- | templates/mirrors/mirror_details.html | 8 | ||||
-rw-r--r-- | templates/mirrors/url_details.html | 89 |
5 files changed, 118 insertions, 1 deletions
diff --git a/mirrors/models.py b/mirrors/models.py index d2c64c51..57664562 100644 --- a/mirrors/models.py +++ b/mirrors/models.py @@ -161,6 +161,8 @@ class MirrorLog(models.Model): error = models.TextField(blank=True, default='') def delay(self): + if self.last_sync is None: + return None # sanity check, this shouldn't happen if self.check_time < self.last_sync: return timedelta() diff --git a/mirrors/urls.py b/mirrors/urls.py index 7cf76aa1..b1054380 100644 --- a/mirrors/urls.py +++ b/mirrors/urls.py @@ -9,6 +9,7 @@ urlpatterns = patterns('mirrors.views', (r'^locations/json/$', 'locations_json', {}, 'mirror-locations-json'), (r'^(?P<name>[\.\-\w]+)/$', 'mirror_details'), (r'^(?P<name>[\.\-\w]+)/json/$', 'mirror_details_json'), + (r'^(?P<name>[\.\-\w]+)/(?P<url_id>\d+)/$', 'url_details'), ) # vim: set ts=4 sw=4 et: diff --git a/mirrors/views.py b/mirrors/views.py index 9e05e5fc..b2e75b25 100644 --- a/mirrors/views.py +++ b/mirrors/views.py @@ -186,6 +186,7 @@ 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) @@ -199,6 +200,24 @@ def mirror_details_json(request, name): return response +def url_details(request, name, url_id): + url = get_object_or_404(MirrorUrl, id=url_id, mirror__name=name) + mirror = url.mirror + authorized = request.user.is_authenticated() + if not authorized and \ + (not mirror.public or not mirror.active or not url.active): + raise Http404 + error_cutoff = timedelta(days=7) + cutoff_time = now() - error_cutoff + logs = MirrorLog.objects.filter(url=url, check_time__gte=cutoff_time).order_by('-check_time') + + context = { + 'url': url, + 'logs': logs, + } + return render(request, 'mirrors/url_details.html', context) + + def status(request, tier=None): if tier is not None: tier = int(tier) diff --git a/templates/mirrors/mirror_details.html b/templates/mirrors/mirror_details.html index aa0a9648..665ad805 100644 --- a/templates/mirrors/mirror_details.html +++ b/templates/mirrors/mirror_details.html @@ -42,6 +42,10 @@ <td>{{ mirror.active|yesno|capfirst }}</td> </tr> <tr> + <th>Created:</th> + <td>{{ mirror.created }}</td> + </tr> + <tr> <th>Rsync IPs:</th> <td class="wrap">{{mirror.rsync_ips.all|join:', '}}</td> </tr> @@ -99,7 +103,8 @@ <th>μ Delay (hh:mm)</th> <th>μ Duration (secs)</th> <th>σ Duration (secs)</th> - <th>Mirror Score</th> + <th>Score</th> + <th>Details</th> </tr> </thead> <tbody> @@ -116,6 +121,7 @@ <td>{{ m_url.duration_avg|floatvalue:2 }}</td> <td>{{ m_url.duration_stddev|floatvalue:2 }}</td> <td>{{ m_url.score|floatvalue:1|default:'∞' }}</td> + <td><a href="{{ m_url.id }}/">Details</a></td> </tr> {% endfor %} </tbody> diff --git a/templates/mirrors/url_details.html b/templates/mirrors/url_details.html new file mode 100644 index 00000000..0b9d2916 --- /dev/null +++ b/templates/mirrors/url_details.html @@ -0,0 +1,89 @@ +{% extends "base.html" %} +{% load cycle from future %} +{% load static from staticfiles %} +{% load mirror_status %} +{% load flags %} + +{% block title %}Arch Linux - {{ url.url }} - URL Details{% endblock %} + +{% block head %}<link rel="stylesheet" type="text/css" href="{% static "flags/fam.css" %}" media="screen, projection" />{% endblock %} + +{% block content %} +<div class="box"> + <h2>URL Details: {{ url.url }}</h2> + + <table class="compact"> + <tr> + <th>URL:</th> + <td>{{ url.url }}</td> + </tr> + <tr> + <th>Protocol:</th> + <td>{{ url.protocol }}</td> + </tr> + <tr> + <th>Country:</th> + <td class="country">{% country_flag url.country %}{{ url.country.name }}</td> + </tr> + <tr> + <th>IPv4:</th> + <td>{{ url.has_ipv4|yesno|capfirst }}</td> + </tr> + <tr> + <th>IPv6:</th> + <td>{{ url.has_ipv6|yesno|capfirst }}</td> + </tr> + {% if user.is_authenticated %} + <tr> + <th>Active:</th> + <td>{{ url.active|yesno|capfirst }}</td> + </tr> + <tr> + <th>Created:</th> + <td>{{ url.created }}</td> + </tr> + {% endif %} + </table> + + <h3>Check Logs</h3> + + <table id="check_logs" class="results"> + <thead> + <tr> + <th>Check Time</th> + <th>Check Location</th> + <th>Check IP</th> + <th>Last Sync</th> + <th>Delay (hh:mm)</th> + <th>Duration (secs)</th> + <th>Success?</th> + <th>Error Message</th> + </tr> + </thead> + <tbody> + {% for log in logs %}<tr class="{% cycle 'odd' 'even' %}"> + <td>{{ log.check_time|date:'Y-m-d H:i' }}</td> + <td class="country">{% country_flag log.location.country %}{{ log.location.country.name }}</td> + <td>{{ log.location.source_ip }}</td> + <td>{{ log.last_sync|date:'Y-m-d H:i' }}</td> + <td>{{ log.delay|duration }}</td> + <td>{{ log.duration|floatvalue }}</td> + <td>{{ log.is_success|yesno|capfirst }}</td> + <td class="wrap">{{ log.error|linebreaksbr }}</td> + </tr>{% endfor %} + </tbody> + </table> +</div> +{% endblock %} + +{% block script_block %} +{% load cdn %}{% jquery %}{% jquery_tablesorter %} +<script type="text/javascript" src="{% static "archweb.js" %}"></script> +<script type="text/javascript"> +$(document).ready(function() { + $("#check_logs:has(tbody tr)").tablesorter( + {widgets: ['zebra'], sortList: [[0,1]], + headers: { 5: { sorter: 'mostlydigit' } } }); +}); +</script> +{% endblock %} |