summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan McGee <dan@archlinux.org>2013-12-15 13:22:41 -0600
committerDan McGee <dan@archlinux.org>2013-12-15 13:28:13 -0600
commit79aef280ddf0c704fd40d0077822a8ff7548437e (patch)
tree706e88b3e072402feeb1baee7e6cbaa658226aeb
parent3c7b02753a4f742eeb66b8deea2fc3f179b87b8e (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.py2
-rw-r--r--mirrors/urls.py1
-rw-r--r--mirrors/views.py19
-rw-r--r--templates/mirrors/mirror_details.html8
-rw-r--r--templates/mirrors/url_details.html89
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 %}