diff options
-rw-r--r-- | devel/management/commands/reporead_inotify.py | 7 | ||||
-rw-r--r-- | mirrors/admin.py | 1 | ||||
-rw-r--r-- | mirrors/fixtures/mirrorprotocols.json | 9 | ||||
-rw-r--r-- | mirrors/management/commands/mirrorcheck.py | 2 | ||||
-rw-r--r-- | mirrors/management/commands/mirrorresolv.py | 2 | ||||
-rw-r--r-- | mirrors/migrations/0026_auto__add_field_mirrorurl_active.py | 83 | ||||
-rw-r--r-- | mirrors/models.py | 3 | ||||
-rw-r--r-- | mirrors/urls_mirrorlist.py | 4 | ||||
-rw-r--r-- | mirrors/utils.py | 10 | ||||
-rw-r--r-- | mirrors/views.py | 44 | ||||
-rw-r--r-- | requirements.txt | 4 | ||||
-rw-r--r-- | requirements_prod.txt | 6 | ||||
-rw-r--r-- | templates/mirrors/error_table.html | 23 | ||||
-rw-r--r-- | templates/mirrors/mirror_details.html | 11 | ||||
-rw-r--r-- | templates/mirrors/mirrorlist_generate.html | 2 | ||||
-rw-r--r-- | templates/mirrors/status.html | 32 | ||||
-rw-r--r-- | templates/mirrors/status_table.html | 3 | ||||
-rw-r--r-- | templates/todolists/view.html | 2 | ||||
-rw-r--r-- | todolists/models.py | 3 | ||||
-rw-r--r-- | todolists/views.py | 5 |
20 files changed, 167 insertions, 89 deletions
diff --git a/devel/management/commands/reporead_inotify.py b/devel/management/commands/reporead_inotify.py index 8c1e47bf..6aa4e0e0 100644 --- a/devel/management/commands/reporead_inotify.py +++ b/devel/management/commands/reporead_inotify.py @@ -192,10 +192,11 @@ class EventHandler(pyinotify.ProcessEvent): def process_default(self, event): '''Primary event processing function which kicks off reporead timer threads if a files database was updated.''' - if not event.name: + name = event.name + if not name: return - # screen to only the files we care about - if event.name.endswith('.files.tar.gz'): + # screen to only the files we care about, skipping temp files + if name.endswith('.files.tar.gz') and not name.startswith('.'): path = event.pathname stat = os.stat(path) database = self.databases.get(path, None) diff --git a/mirrors/admin.py b/mirrors/admin.py index 9c88207d..d0f2f475 100644 --- a/mirrors/admin.py +++ b/mirrors/admin.py @@ -10,6 +10,7 @@ from .models import (Mirror, MirrorProtocol, MirrorUrl, MirrorRsync, class MirrorUrlForm(forms.ModelForm): class Meta: model = MirrorUrl + def clean_url(self): # is this a valid-looking URL? url_parts = urlparse(self.cleaned_data["url"]) diff --git a/mirrors/fixtures/mirrorprotocols.json b/mirrors/fixtures/mirrorprotocols.json index 8822ef8e..1a07510b 100644 --- a/mirrors/fixtures/mirrorprotocols.json +++ b/mirrors/fixtures/mirrorprotocols.json @@ -9,15 +9,6 @@ } }, { - "pk": 2, - "model": "mirrors.mirrorprotocol", - "fields": { - "is_download": true, - "default": false, - "protocol": "ftp" - } - }, - { "pk": 3, "model": "mirrors.mirrorprotocol", "fields": { diff --git a/mirrors/management/commands/mirrorcheck.py b/mirrors/management/commands/mirrorcheck.py index e7dd7b49..6faf294a 100644 --- a/mirrors/management/commands/mirrorcheck.py +++ b/mirrors/management/commands/mirrorcheck.py @@ -63,7 +63,7 @@ class Command(NoArgsCommand): timeout = options.get('timeout') urls = MirrorUrl.objects.select_related('protocol').filter( - mirror__active=True, mirror__public=True) + active=True, mirror__active=True, mirror__public=True) location = options.get('location', None) if location: diff --git a/mirrors/management/commands/mirrorresolv.py b/mirrors/management/commands/mirrorresolv.py index a6c2523e..85a3c654 100644 --- a/mirrors/management/commands/mirrorresolv.py +++ b/mirrors/management/commands/mirrorresolv.py @@ -39,7 +39,7 @@ class Command(NoArgsCommand): def resolve_mirrors(): logger.debug("requesting list of mirror URLs") - for mirrorurl in MirrorUrl.objects.filter(mirror__active=True): + for mirrorurl in MirrorUrl.objects.filter(active=True, mirror__active=True): try: # save old values, we can skip no-op updates this way oldvals = (mirrorurl.has_ipv4, mirrorurl.has_ipv6) diff --git a/mirrors/migrations/0026_auto__add_field_mirrorurl_active.py b/mirrors/migrations/0026_auto__add_field_mirrorurl_active.py new file mode 100644 index 00000000..f989435f --- /dev/null +++ b/mirrors/migrations/0026_auto__add_field_mirrorurl_active.py @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + db.add_column(u'mirrors_mirrorurl', 'active', + self.gf('django.db.models.fields.BooleanField')(default=True), + keep_default=True) + + def backwards(self, orm): + db.delete_column(u'mirrors_mirrorurl', 'active') + + + models = { + u'mirrors.checklocation': { + 'Meta': {'ordering': "('hostname', 'source_ip')", 'object_name': 'CheckLocation'}, + 'country': ('django_countries.fields.CountryField', [], {'max_length': '2'}), + 'created': ('django.db.models.fields.DateTimeField', [], {}), + 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'source_ip': ('django.db.models.fields.GenericIPAddressField', [], {'unique': 'True', 'max_length': '39'}) + }, + u'mirrors.mirror': { + 'Meta': {'ordering': "('name',)", 'object_name': 'Mirror'}, + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), + 'alternate_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'rsync_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), + 'rsync_user': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}), + 'tier': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}), + 'upstream': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['mirrors.Mirror']", 'null': 'True', 'on_delete': 'models.SET_NULL'}) + }, + u'mirrors.mirrorlog': { + 'Meta': {'object_name': 'MirrorLog'}, + 'check_time': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'error': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_success': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'last_sync': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'location': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'logs'", 'null': 'True', 'to': u"orm['mirrors.CheckLocation']"}), + 'url': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'logs'", 'to': u"orm['mirrors.MirrorUrl']"}) + }, + u'mirrors.mirrorprotocol': { + 'Meta': {'ordering': "('protocol',)", 'object_name': 'MirrorProtocol'}, + 'created': ('django.db.models.fields.DateTimeField', [], {}), + 'default': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_download': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}) + }, + u'mirrors.mirrorrsync': { + 'Meta': {'object_name': 'MirrorRsync'}, + 'created': ('django.db.models.fields.DateTimeField', [], {}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip': ('mirrors.fields.IPNetworkField', [], {'max_length': '44'}), + 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': u"orm['mirrors.Mirror']"}) + }, + u'mirrors.mirrorurl': { + 'Meta': {'object_name': 'MirrorUrl'}, + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'country': ('django_countries.fields.CountryField', [], {'db_index': 'True', 'max_length': '2', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {}), + 'has_ipv4': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'has_ipv6': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': u"orm['mirrors.Mirror']"}), + 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'on_delete': 'models.PROTECT', 'to': u"orm['mirrors.MirrorProtocol']"}), + 'url': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) + } + } + + complete_apps = ['mirrors'] diff --git a/mirrors/models.py b/mirrors/models.py index d8ac7952..975ead39 100644 --- a/mirrors/models.py +++ b/mirrors/models.py @@ -47,7 +47,7 @@ class Mirror(models.Model): class MirrorProtocol(models.Model): protocol = models.CharField(max_length=10, unique=True) is_download = models.BooleanField(default=True, - help_text="Is protocol useful for end-users, e.g. FTP/HTTP") + help_text="Is protocol useful for end-users, e.g. HTTP") default = models.BooleanField(default=True, help_text="Included by default when building mirror list?") created = models.DateTimeField(editable=False) @@ -70,6 +70,7 @@ class MirrorUrl(models.Model): has_ipv6 = models.BooleanField("IPv6 capable", default=False, editable=False) created = models.DateTimeField(editable=False) + active = models.BooleanField(default=True) def address_families(self): hostname = urlparse(self.url).hostname diff --git a/mirrors/urls_mirrorlist.py b/mirrors/urls_mirrorlist.py index 1444eca9..bba54ec9 100644 --- a/mirrors/urls_mirrorlist.py +++ b/mirrors/urls_mirrorlist.py @@ -1,9 +1,11 @@ from django.conf.urls import patterns + urlpatterns = patterns('mirrors.views', (r'^$', 'generate_mirrorlist', {}, 'mirrorlist'), (r'^all/$', 'find_mirrors', {'countries': ['all']}), - (r'^all/(?P<protocol>[A-z]+)/$', 'find_mirrors_simple') + (r'^all/(?P<protocol>[A-z]+)/$', 'find_mirrors_simple', + {}, 'mirrorlist_simple') ) # vim: set ts=4 sw=4 et: diff --git a/mirrors/utils.py b/mirrors/utils.py index ba45da5f..e98b5c9f 100644 --- a/mirrors/utils.py +++ b/mirrors/utils.py @@ -116,7 +116,10 @@ def annotate_url(url, url_data): def get_mirror_statuses(cutoff=DEFAULT_CUTOFF, mirror_id=None): cutoff_time = now() - cutoff - valid_urls = MirrorUrl.objects.filter( + # TODO: this prevents grabbing data points from any mirror that was active, + # receiving checks, and then marked private. we can probably be smarter and + # filter the data later? + valid_urls = MirrorUrl.objects.filter(active=True, mirror__active=True, mirror__public=True, logs__check_time__gte=cutoff_time).distinct() @@ -159,7 +162,7 @@ def get_mirror_statuses(cutoff=DEFAULT_CUTOFF, mirror_id=None): def get_mirror_errors(cutoff=DEFAULT_CUTOFF, mirror_id=None): cutoff_time = now() - cutoff errors = MirrorLog.objects.filter( - is_success=False, check_time__gte=cutoff_time, + is_success=False, check_time__gte=cutoff_time, url__active=True, url__mirror__active=True, url__mirror__public=True).values( 'url__url', 'url__country', 'url__protocol__protocol', 'url__mirror__tier', 'error').annotate( @@ -189,13 +192,14 @@ def get_mirror_url_for_download(cutoff=DEFAULT_CUTOFF): min_sync_time = status_data['last_sync__max'] - timedelta(minutes=20) best_logs = MirrorLog.objects.filter(is_success=True, check_time__gte=min_check_time, last_sync__gte=min_sync_time, + url__active=True, url__mirror__public=True, url__mirror__active=True, url__protocol__default=True).order_by( 'duration')[:1] if best_logs: return MirrorUrl.objects.get(id=best_logs[0].url_id) - mirror_urls = MirrorUrl.objects.filter( + mirror_urls = MirrorUrl.objects.filter(active=True, mirror__public=True, mirror__active=True, protocol__default=True) # look first for a country-agnostic URL, then fall back to any HTTP URL filtered_urls = mirror_urls.filter(country='')[:1] diff --git a/mirrors/views.py b/mirrors/views.py index 73d40297..6f4ad838 100644 --- a/mirrors/views.py +++ b/mirrors/views.py @@ -8,7 +8,7 @@ from django.forms.widgets import CheckboxSelectMultiple from django.core.serializers.json import DjangoJSONEncoder from django.db.models import Q from django.http import Http404, HttpResponse -from django.shortcuts import get_object_or_404, render +from django.shortcuts import get_object_or_404, redirect, render from django.utils.timezone import now from django.views.decorators.csrf import csrf_exempt from django_countries.countries import COUNTRIES @@ -43,7 +43,7 @@ class MirrorlistForm(forms.Form): def get_countries(self): country_codes = set() - country_codes.update(MirrorUrl.objects.filter( + country_codes.update(MirrorUrl.objects.filter(active=True, mirror__active=True).exclude(country='').values_list( 'country', flat=True).order_by().distinct()) countries = [(code, self.countries[code]) for code in country_codes] @@ -78,18 +78,6 @@ def generate_mirrorlist(request): {'mirrorlist_form': form}) -def default_protocol_filter(original_urls): - key_func = attrgetter('country') - sorted_urls = sorted(original_urls, key=key_func) - urls = [] - for _, group in groupby(sorted_urls, key=key_func): - cntry_urls = list(group) - if any(url.protocol.default for url in cntry_urls): - cntry_urls = [url for url in cntry_urls if url.protocol.default] - urls.extend(cntry_urls) - return urls - - def status_filter(original_urls): status_info = get_mirror_statuses() scores = {u.id: u.score for u in status_info['urls']} @@ -105,7 +93,7 @@ def status_filter(original_urls): def find_mirrors(request, countries=None, protocols=None, use_status=False, - ipv4_supported=True, ipv6_supported=True, smart_protocol=False): + ipv4_supported=True, ipv6_supported=True): if not protocols: protocols = MirrorProtocol.objects.filter(is_download=True) elif hasattr(protocols, 'model') and protocols.model == MirrorProtocol: @@ -114,7 +102,7 @@ def find_mirrors(request, countries=None, protocols=None, use_status=False, else: protocols = MirrorProtocol.objects.filter(protocol__in=protocols) qset = MirrorUrl.objects.select_related().filter( - protocol__in=protocols, + protocol__in=protocols, active=True, mirror__public=True, mirror__active=True) if countries and 'all' not in countries: qset = qset.filter(country__in=countries) @@ -126,17 +114,12 @@ def find_mirrors(request, countries=None, protocols=None, use_status=False, ip_version |= Q(has_ipv6=True) qset = qset.filter(ip_version) - if smart_protocol: - urls = default_protocol_filter(qset) - else: - urls = qset - if not use_status: sort_key = attrgetter('country.name', 'mirror.name', 'url') - urls = sorted(urls, key=sort_key) + urls = sorted(qset, key=sort_key) template = 'mirrors/mirrorlist.txt' else: - urls = status_filter(urls) + urls = status_filter(qset) template = 'mirrors/mirrorlist_status.txt' context = { @@ -147,9 +130,7 @@ def find_mirrors(request, countries=None, protocols=None, use_status=False, def find_mirrors_simple(request, protocol): if protocol == 'smart': - # generate a 'smart' mirrorlist, one that only includes FTP mirrors if - # no HTTP mirror is available in that country. - return find_mirrors(request, smart_protocol=True) + return redirect('mirrorlist_simple', 'http', permanent=True) proto = get_object_or_404(MirrorProtocol, protocol=protocol) return find_mirrors(request, protocols=[proto]) @@ -175,6 +156,7 @@ def mirror_details(request, name): if not request.user.is_authenticated() and \ (not mirror.public or not mirror.active): raise Http404 + error_cutoff = timedelta(days=7) status_info = get_mirror_statuses(mirror_id=mirror.id) checked_urls = {url for url in status_info['urls'] \ @@ -188,9 +170,15 @@ def mirror_details(request, name): setattr(url, attr, None) all_urls = sorted(checked_urls.union(other_urls), key=attrgetter('url')) - return render(request, 'mirrors/mirror_details.html', - {'mirror': mirror, 'urls': all_urls}) + error_logs = get_mirror_errors(mirror_id=mirror.id, cutoff=error_cutoff) + context = { + 'mirror': mirror, + 'urls': all_urls, + 'cutoff': error_cutoff, + 'error_logs': error_logs, + } + return render(request, 'mirrors/mirror_details.html', context) def mirror_details_json(request, name): mirror = get_object_or_404(Mirror, name=name) diff --git a/requirements.txt b/requirements.txt index 84450c76..1909da1b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,9 +2,9 @@ Django==1.5.1 IPy==0.81 Markdown==2.3.1 -South==0.7.6 +South==0.8.1 bencode==1.0 django-countries==1.5 -jsmin==2.0.2-1 +jsmin==2.0.3 pgpdump==1.4 pytz>=2013b diff --git a/requirements_prod.txt b/requirements_prod.txt index cde5f513..1c331cf9 100644 --- a/requirements_prod.txt +++ b/requirements_prod.txt @@ -2,12 +2,12 @@ Django==1.5.1 IPy==0.81 Markdown==2.3.1 -South==0.7.6 +South==0.8.1 bencode==1.0 django-countries==1.5 -jsmin==2.0.2-1 +jsmin==2.0.3 pgpdump==1.4 psycopg2==2.5 pyinotify==0.9.4 -python-memcached==1.48 +python-memcached==1.51 pytz>=2013b diff --git a/templates/mirrors/error_table.html b/templates/mirrors/error_table.html new file mode 100644 index 00000000..6054814f --- /dev/null +++ b/templates/mirrors/error_table.html @@ -0,0 +1,23 @@ +{% load flags mirror_status %} +<table id="errorlog_mirrors" class="results"> + <thead> + <tr> + <th>Mirror URL</th> + <th>Protocol</th> + <th>Country</th> + <th>Error Message</th> + <th>Last Occurred</th> + <th>Occurrences (last {{ cutoff|hours }})</th> + </tr> + </thead> + <tbody> + {% for log in error_logs %}<tr class="{% cycle 'odd' 'even' %}"> + <td>{{ log.url__url }}</td> + <td>{{ log.url__protocol__protocol }}</td> + <td class="country">{% country_flag log.country %}{{ log.country.name }}</td> + <td class="wrap">{{ log.error|linebreaksbr }}</td> + <td>{{ log.last_occurred|date:'Y-m-d H:i' }}</td> + <td>{{ log.error_count }}</td> + </tr>{% endfor %} + </tbody> +</table> diff --git a/templates/mirrors/mirror_details.html b/templates/mirrors/mirror_details.html index 98755ad2..f2202e38 100644 --- a/templates/mirrors/mirror_details.html +++ b/templates/mirrors/mirror_details.html @@ -2,6 +2,7 @@ {% load static from staticfiles %} {% load mirror_status %} {% load flags %} +{% load admin_urls %} {% block title %}{{ BRANDING_DISTRONAME }} - {{ mirror.name }} - Mirror Details{% endblock %} @@ -9,9 +10,14 @@ {% block content %} <div class="box"> - <h2>Mirror Details: {{ mirror.name }}</h2> + {% if perms.mirrors.change_mirror %} + <ul class="admin-actions"> + <li><a href="{% url 'admin:mirrors_mirror_change' mirror.pk %}" title="Edit mirror">Edit Mirror</a></li> + </ul> + {% endif %} + <table class="compact"> <tr> <th>Name:</th> @@ -106,6 +112,9 @@ {% endfor %} </tbody> </table> + + <h3>Error Log</h3> + {% include "mirrors/error_table.html" %} </div> <div class="box"> diff --git a/templates/mirrors/mirrorlist_generate.html b/templates/mirrors/mirrorlist_generate.html index e141ae3d..c2a79fa8 100644 --- a/templates/mirrors/mirrorlist_generate.html +++ b/templates/mirrors/mirrorlist_generate.html @@ -22,10 +22,8 @@ <ul> <li><a href="all/">All mirrors</a></li> - <li><a href="all/ftp/">All mirrors, FTP only</a></li> <li><a href="all/http/">All mirrors, HTTP only</a></li> <li><a href="all/https/">All mirrors, HTTPS only</a></li> - <li><a href="all/smart/">All mirrors, Smart protocols</a>: this link only includes FTP mirrors if an HTTP mirror is not available in a given country.</li> </ul> <h3>Customized by country mirrorlist</h3> diff --git a/templates/mirrors/status.html b/templates/mirrors/status.html index de2c3d5c..5a275e33 100644 --- a/templates/mirrors/status.html +++ b/templates/mirrors/status.html @@ -59,45 +59,19 @@ <a name="outofsync" id="outofsync"></a> <h3>Out of Sync Mirrors</h3> - {% with bad_urls as urls %} - {% with 'outofsync_mirrors' as table_id %} + {% with urls=bad_urls table_id='outofsync_mirrors' %} {% include "mirrors/status_table.html" %} {% endwith %} - {% endwith %} <a name="successful" id="successful"></a> <h3>Successfully Syncing Mirrors</h3> - {% with good_urls as urls %} - {% with 'successful_mirrors' as table_id %} + {% with urls=good_urls table_id='successful_mirrors' %} {% include "mirrors/status_table.html" %} {% endwith %} - {% endwith %} <a name="errorlog" id="errorlog"></a> <h3>Mirror Syncing Error Log</h3> - <table id="errorlog_mirrors" class="results"> - <thead> - <tr> - <th>Mirror URL</th> - <th>Protocol</th> - <th>Country</th> - <th>Error Message</th> - <th>Last Occurred</th> - <th>Occurrences (last {{ cutoff|hours }})</th> - </tr> - </thead> - <tbody> - {% for log in error_logs %}<tr class="{% cycle 'odd' 'even' %}"> - <td>{{ log.url__url }}</td> - <td>{{ log.url__protocol__protocol }}</td> - <td class="country">{% country_flag log.country %}{{ log.country.name }}</td> - <td class="wrap">{{ log.error|linebreaksbr }}</td> - <td>{{ log.last_occurred|date:'Y-m-d H:i' }}</td> - <td>{{ log.error_count }}</td> - </tr>{% endfor %} - </tbody> - </table> - + {% include "mirrors/error_table.html" %} </div> {% endblock %} diff --git a/templates/mirrors/status_table.html b/templates/mirrors/status_table.html index e848a9c9..28175420 100644 --- a/templates/mirrors/status_table.html +++ b/templates/mirrors/status_table.html @@ -1,5 +1,4 @@ -{% load mirror_status %} -{% load flags %} +{% load flags mirror_status %} <table id="{{ table_id }}" class="results"> <thead> <tr> diff --git a/templates/todolists/view.html b/templates/todolists/view.html index e0cd4007..28ce8580 100644 --- a/templates/todolists/view.html +++ b/templates/todolists/view.html @@ -68,6 +68,7 @@ <th>Staging Version</th> <th>Maintainers</th> <th>Status</th> + <th>Last Touched By</th> </tr> </thead> <tbody> @@ -95,6 +96,7 @@ <span class="{{ pkg.status_css_class }}">{{ pkg.get_status_display }}</span> {% endif %} </td> + <td>{{ pkg.user|default:"" }}</td> </tr> {% endfor %} </tbody> diff --git a/todolists/models.py b/todolists/models.py index 3ea80f37..59b14616 100644 --- a/todolists/models.py +++ b/todolists/models.py @@ -47,7 +47,8 @@ class Todolist(models.Model): if not hasattr(self, '_packages'): self._packages = self.todolistpackage_set.filter( removed__isnull=True).select_related( - 'pkg', 'repo', 'arch').order_by('pkgname', 'arch') + 'pkg', 'repo', 'arch', 'user__username').order_by( + 'pkgname', 'arch') return self._packages diff --git a/todolists/views.py b/todolists/views.py index b6d3c25f..6c117473 100644 --- a/todolists/views.py +++ b/todolists/views.py @@ -72,12 +72,13 @@ def view(request, slug): attach_staging(todolist.packages(), todolist.pk) arches = {tp.arch for tp in todolist.packages()} repos = {tp.repo for tp in todolist.packages()} - return render(request, 'todolists/view.html', { + context = { 'list': todolist, 'svn_roots': svn_roots, 'arches': sorted(arches), 'repos': sorted(repos), - }) + } + return render(request, 'todolists/view.html', context) def list_pkgbases(request, slug, svn_root): |