summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--devel/admin.py18
-rw-r--r--devel/fields.py30
-rw-r--r--devel/management/commands/generate_keyring.py3
-rw-r--r--devel/migrations/0002_auto__add_masterkey.py4
-rw-r--r--devel/migrations/0003_auto__add_pgpsignature.py10
-rw-r--r--devel/migrations/0004_masterkey_dates.py6
-rw-r--r--devel/migrations/0005_auto__add_userprofile.py113
-rw-r--r--devel/models.py60
-rw-r--r--devel/tests.py6
-rw-r--r--devel/views.py7
-rw-r--r--main/admin.py14
-rw-r--r--main/fields.py27
-rw-r--r--main/fixtures/groups.json4
-rw-r--r--main/migrations/0030_move_mirror_models.py4
-rw-r--r--main/migrations/0031_move_news_out.py4
-rw-r--r--main/migrations/0034_update_content_type.py26
-rw-r--r--main/migrations/0051_auto__chg_field_userprofile_pgp_key.py4
-rw-r--r--main/migrations/0052_auto__del_signoff.py2
-rw-r--r--main/migrations/0053_auto__add_field_package_pgp_signature.py2
-rw-r--r--main/migrations/0054_auto__add_field_donor_created.py2
-rw-r--r--main/migrations/0055_unique_package_in_repo.py2
-rw-r--r--main/migrations/0056_auto__chg_field_package_pkgdesc.py2
-rw-r--r--main/migrations/0057_auto__add_field_userprofile_latin_name.py2
-rw-r--r--main/migrations/0058_auto__add_on_delete_attributes.py160
-rw-r--r--main/migrations/0059_auto__del_userprofile.py137
-rw-r--r--main/migrations/0060_add_packages_last_update_index.py131
-rw-r--r--main/models.py60
-rw-r--r--mirrors/migrations/0002_rename_model_tables.py21
-rw-r--r--mirrors/migrations/0012_auto__add_on_delete_attribute.py68
-rw-r--r--mirrors/utils.py2
-rw-r--r--news/migrations/0002_move_news_in.py11
-rw-r--r--news/migrations/0010_auto__chg_field_news_author.py65
-rw-r--r--releng/views.py10
-rw-r--r--settings.py2
-rw-r--r--templates/devel/index.html2
-rw-r--r--templates/packages/details.html23
-rw-r--r--templates/releng/iso_overview.html6
-rw-r--r--templates/releng/results.html2
38 files changed, 880 insertions, 172 deletions
diff --git a/devel/admin.py b/devel/admin.py
index 717ba1b2..5a704c0b 100644
--- a/devel/admin.py
+++ b/devel/admin.py
@@ -1,6 +1,18 @@
from django.contrib import admin
+from django.contrib.auth.admin import UserAdmin
+from django.contrib.auth.models import User
-from .models import MasterKey, PGPSignature
+from .models import UserProfile, MasterKey, PGPSignature
+
+
+class UserProfileInline(admin.StackedInline):
+ model = UserProfile
+
+
+class UserProfileAdmin(UserAdmin):
+ inlines = [UserProfileInline]
+ list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff', 'is_active')
+ list_filter = ('is_staff', 'is_superuser', 'is_active')
class MasterKeyAdmin(admin.ModelAdmin):
@@ -8,6 +20,7 @@ class MasterKeyAdmin(admin.ModelAdmin):
search_fields = ('pgp_key', 'owner', 'revoker')
date_hierarchy = 'created'
+
class PGPSignatureAdmin(admin.ModelAdmin):
list_display = ('signer', 'signee', 'created', 'expires', 'valid')
list_filter = ('valid',)
@@ -15,6 +28,9 @@ class PGPSignatureAdmin(admin.ModelAdmin):
date_hierarchy = 'created'
+admin.site.unregister(User)
+admin.site.register(User, UserProfileAdmin)
+
admin.site.register(MasterKey, MasterKeyAdmin)
admin.site.register(PGPSignature, PGPSignatureAdmin)
diff --git a/devel/fields.py b/devel/fields.py
new file mode 100644
index 00000000..606ca63c
--- /dev/null
+++ b/devel/fields.py
@@ -0,0 +1,30 @@
+from django.db import models
+from django.core.validators import RegexValidator
+
+
+class PGPKeyField(models.CharField):
+ _south_introspects = True
+
+ def __init__(self, *args, **kwargs):
+ super(PGPKeyField, self).__init__(*args, **kwargs)
+ self.validators.append(RegexValidator(r'^[0-9A-F]{40}$',
+ "Ensure this value consists of 40 hex characters.", 'hex_char'))
+
+ def to_python(self, value):
+ if value == '' or value is None:
+ return None
+ value = super(PGPKeyField, self).to_python(value)
+ # remove all spaces
+ value = value.replace(' ', '')
+ # prune prefixes, either 0x or 2048R/ type
+ if value.startswith('0x'):
+ value = value[2:]
+ value = value.split('/')[-1]
+ # make all (hex letters) uppercase
+ return value.upper()
+
+ def formfield(self, **kwargs):
+ # override so we don't set max_length form field attribute
+ return models.Field.formfield(self, **kwargs)
+
+# vim: set ts=4 sw=4 et:
diff --git a/devel/management/commands/generate_keyring.py b/devel/management/commands/generate_keyring.py
index 062c738b..b9117c84 100644
--- a/devel/management/commands/generate_keyring.py
+++ b/devel/management/commands/generate_keyring.py
@@ -13,8 +13,7 @@ import logging
import subprocess
import sys
-from devel.models import MasterKey
-from main.models import UserProfile
+from devel.models import MasterKey, UserProfile
logging.basicConfig(
level=logging.INFO,
diff --git a/devel/migrations/0002_auto__add_masterkey.py b/devel/migrations/0002_auto__add_masterkey.py
index ac1f745a..ba9a3e5f 100644
--- a/devel/migrations/0002_auto__add_masterkey.py
+++ b/devel/migrations/0002_auto__add_masterkey.py
@@ -15,7 +15,7 @@ class Migration(SchemaMigration):
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('owner', self.gf('django.db.models.fields.related.ForeignKey')(related_name='masterkey_owner', to=orm['auth.User'])),
('revoker', self.gf('django.db.models.fields.related.ForeignKey')(related_name='masterkey_revoker', to=orm['auth.User'])),
- ('pgp_key', self.gf('main.fields.PGPKeyField')(max_length=40)),
+ ('pgp_key', self.gf('devel.fields.PGPKeyField')(max_length=40)),
('created', self.gf('django.db.models.fields.DateTimeField')()),
('revoked', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
))
@@ -67,7 +67,7 @@ class Migration(SchemaMigration):
'created': ('django.db.models.fields.DateTimeField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'masterkey_owner'", 'to': "orm['auth.User']"}),
- 'pgp_key': ('main.fields.PGPKeyField', [], {'max_length': '40'}),
+ 'pgp_key': ('devel.fields.PGPKeyField', [], {'max_length': '40'}),
'revoked': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'revoker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'masterkey_revoker'", 'to': "orm['auth.User']"})
}
diff --git a/devel/migrations/0003_auto__add_pgpsignature.py b/devel/migrations/0003_auto__add_pgpsignature.py
index f9ac5021..e16de1ca 100644
--- a/devel/migrations/0003_auto__add_pgpsignature.py
+++ b/devel/migrations/0003_auto__add_pgpsignature.py
@@ -8,8 +8,8 @@ class Migration(SchemaMigration):
def forwards(self, orm):
db.create_table('devel_pgpsignature', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
- ('signer', self.gf('main.fields.PGPKeyField')(max_length=40)),
- ('signee', self.gf('main.fields.PGPKeyField')(max_length=40)),
+ ('signer', self.gf('devel.fields.PGPKeyField')(max_length=40)),
+ ('signee', self.gf('devel.fields.PGPKeyField')(max_length=40)),
('created', self.gf('django.db.models.fields.DateField')()),
('expires', self.gf('django.db.models.fields.DateField')(null=True)),
('valid', self.gf('django.db.models.fields.BooleanField')(default=True)),
@@ -63,7 +63,7 @@ class Migration(SchemaMigration):
'created': ('django.db.models.fields.DateTimeField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'masterkey_owner'", 'to': "orm['auth.User']"}),
- 'pgp_key': ('main.fields.PGPKeyField', [], {'max_length': '40'}),
+ 'pgp_key': ('devel.fields.PGPKeyField', [], {'max_length': '40'}),
'revoked': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'revoker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'masterkey_revoker'", 'to': "orm['auth.User']"})
},
@@ -72,8 +72,8 @@ class Migration(SchemaMigration):
'created': ('django.db.models.fields.DateField', [], {}),
'expires': ('django.db.models.fields.DateField', [], {'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
- 'signee': ('main.fields.PGPKeyField', [], {'max_length': '40'}),
- 'signer': ('main.fields.PGPKeyField', [], {'max_length': '40'}),
+ 'signee': ('devel.fields.PGPKeyField', [], {'max_length': '40'}),
+ 'signer': ('devel.fields.PGPKeyField', [], {'max_length': '40'}),
'valid': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
}
}
diff --git a/devel/migrations/0004_masterkey_dates.py b/devel/migrations/0004_masterkey_dates.py
index dc7750dc..f2020dd7 100644
--- a/devel/migrations/0004_masterkey_dates.py
+++ b/devel/migrations/0004_masterkey_dates.py
@@ -56,7 +56,7 @@ class Migration(SchemaMigration):
'created': ('django.db.models.fields.DateField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'masterkey_owner'", 'to': "orm['auth.User']"}),
- 'pgp_key': ('main.fields.PGPKeyField', [], {'max_length': '40'}),
+ 'pgp_key': ('devel.fields.PGPKeyField', [], {'max_length': '40'}),
'revoked': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'revoker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'masterkey_revoker'", 'to': "orm['auth.User']"})
},
@@ -65,8 +65,8 @@ class Migration(SchemaMigration):
'created': ('django.db.models.fields.DateField', [], {}),
'expires': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
- 'signee': ('main.fields.PGPKeyField', [], {'max_length': '40'}),
- 'signer': ('main.fields.PGPKeyField', [], {'max_length': '40'}),
+ 'signee': ('devel.fields.PGPKeyField', [], {'max_length': '40'}),
+ 'signer': ('devel.fields.PGPKeyField', [], {'max_length': '40'}),
'valid': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
}
}
diff --git a/devel/migrations/0005_auto__add_userprofile.py b/devel/migrations/0005_auto__add_userprofile.py
new file mode 100644
index 00000000..ff6f9785
--- /dev/null
+++ b/devel/migrations/0005_auto__add_userprofile.py
@@ -0,0 +1,113 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ depends_on = (
+ ('main', '0059_auto__del_userprofile'),
+ )
+
+ def forwards(self, orm):
+ if not db.dry_run:
+ db.send_create_signal('devel', ['UserProfile'])
+ orm['contenttypes.ContentType'].objects.filter(
+ app_label='main', model='userprofile').update(
+ app_label='devel')
+
+ def backwards(self, orm):
+ pass
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'devel.masterkey': {
+ 'Meta': {'ordering': "('created',)", 'object_name': 'MasterKey'},
+ 'created': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'masterkey_owner'", 'to': "orm['auth.User']"}),
+ 'pgp_key': ('devel.fields.PGPKeyField', [], {'max_length': '40'}),
+ 'revoked': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'revoker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'masterkey_revoker'", 'to': "orm['auth.User']"})
+ },
+ 'devel.pgpsignature': {
+ 'Meta': {'object_name': 'PGPSignature'},
+ 'created': ('django.db.models.fields.DateField', [], {}),
+ 'expires': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'signee': ('devel.fields.PGPKeyField', [], {'max_length': '40'}),
+ 'signer': ('devel.fields.PGPKeyField', [], {'max_length': '40'}),
+ 'valid': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
+ },
+ 'devel.userprofile': {
+ 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"},
+ 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'latin_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'pgp_key': ('devel.fields.PGPKeyField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}),
+ 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'time_zone': ('django.db.models.fields.CharField', [], {'default': "'UTC'", 'max_length': '100'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'userprofile'", 'unique': 'True', 'to': "orm['auth.User']"}),
+ 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'main.repo': {
+ 'Meta': {'ordering': "['name']", 'object_name': 'Repo', 'db_table': "'repos'"},
+ 'bugs_category': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}),
+ 'bugs_project': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'staging': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'svn_root': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ }
+ }
+
+ complete_apps = ['devel']
diff --git a/devel/models.py b/devel/models.py
index 2fc61060..79c56f2a 100644
--- a/devel/models.py
+++ b/devel/models.py
@@ -1,8 +1,66 @@
# -*- coding: utf-8 -*-
+import pytz
+
from django.db import models
from django.contrib.auth.models import User
-from main.fields import PGPKeyField
+from .fields import PGPKeyField
+from main.utils import make_choice
+
+
+class UserProfile(models.Model):
+ notify = models.BooleanField(
+ "Send notifications",
+ default=True,
+ help_text="When enabled, send user 'flag out-of-date' notifications")
+ time_zone = models.CharField(
+ max_length=100,
+ choices=make_choice(pytz.common_timezones),
+ default="UTC",
+ help_text="Used for developer clock page")
+ alias = models.CharField(
+ max_length=50,
+ help_text="Required field")
+ public_email = models.CharField(
+ max_length=50,
+ help_text="Required field")
+ other_contact = models.CharField(max_length=100, null=True, blank=True)
+ pgp_key = PGPKeyField(max_length=40, null=True, blank=True,
+ verbose_name="PGP key fingerprint",
+ help_text="consists of 40 hex digits; use `gpg --fingerprint`")
+ website = models.CharField(max_length=200, null=True, blank=True)
+ yob = models.IntegerField("Year of birth", null=True, blank=True)
+ location = models.CharField(max_length=50, null=True, blank=True)
+ languages = models.CharField(max_length=50, null=True, blank=True)
+ interests = models.CharField(max_length=255, null=True, blank=True)
+ occupation = models.CharField(max_length=50, null=True, blank=True)
+ roles = models.CharField(max_length=255, null=True, blank=True)
+ favorite_distros = models.CharField(max_length=255, null=True, blank=True)
+ picture = models.FileField(upload_to='devs', default='devs/silhouette.png',
+ help_text="Ideally 125px by 125px")
+ user = models.OneToOneField(User, related_name='userprofile')
+ allowed_repos = models.ManyToManyField('main.Repo', blank=True)
+ latin_name = models.CharField(max_length=255, null=True, blank=True,
+ help_text="Latin-form name; used only for non-Latin full names")
+
+ class Meta:
+ db_table = 'user_profiles'
+ verbose_name = 'Additional Profile Data'
+ verbose_name_plural = 'Additional Profile Data'
+
+ def get_absolute_url(self):
+ # TODO: this is disgusting. find a way to consolidate this logic with
+ # public.views.userlist among other places, and make some constants or
+ # something so we aren't using copies of string names everywhere.
+ group_names = self.user.groups.values_list('name', flat=True)
+ if "Developers" in group_names:
+ prefix = "developers"
+ elif "Trusted Users" in group_names:
+ prefix = "trustedusers"
+ else:
+ prefix = "fellows"
+ return '/%s/#%s' % (prefix, self.user.username)
+
class MasterKey(models.Model):
diff --git a/devel/tests.py b/devel/tests.py
index 01eed0fc..5c736a30 100644
--- a/devel/tests.py
+++ b/devel/tests.py
@@ -1,8 +1,8 @@
+from django.contrib.auth.models import User
from django.test import TestCase
-from django.contrib.auth.models import User
-from devel.utils import UserFinder
-from main.models import UserProfile
+from .utils import UserFinder
+from .models import UserProfile
class DevelTest(TestCase):
def test_index(self):
diff --git a/devel/views.py b/devel/views.py
index 2b003bf7..0b9f8f18 100644
--- a/devel/views.py
+++ b/devel/views.py
@@ -22,8 +22,9 @@ from django.views.decorators.cache import never_cache
from django.views.generic.simple import direct_to_template
from django.utils.http import http_date
+from .models import UserProfile
from main.models import Package, PackageDepend, PackageFile, TodolistPkg
-from main.models import Arch, Repo, UserProfile
+from main.models import Arch, Repo
from main.utils import utc_now
from packages.models import PackageRelation
from packages.utils import get_signoff_groups
@@ -160,8 +161,8 @@ def report(request, report_name, username=None):
type=PackageRelation.MAINTAINER).values('user'))
if report_name == 'old':
- title = 'Packages last built more than two years ago'
- cutoff = utc_now() - timedelta(days=365 * 2)
+ title = 'Packages last built more than one year ago'
+ cutoff = utc_now() - timedelta(days=365)
packages = packages.filter(
build_date__lt=cutoff).order_by('build_date')
elif report_name == 'long-out-of-date':
diff --git a/main/admin.py b/main/admin.py
index 783d07e4..741f6665 100644
--- a/main/admin.py
+++ b/main/admin.py
@@ -1,7 +1,5 @@
from django.contrib import admin
-from django.contrib.auth.models import User
-from django.contrib.auth.admin import UserAdmin
-from main.models import Arch, Donor, Package, Repo, Todolist, UserProfile
+from main.models import Arch, Donor, Package, Repo, Todolist
class DonorAdmin(admin.ModelAdmin):
list_display = ('name', 'visible', 'created')
@@ -31,17 +29,7 @@ class TodolistAdmin(admin.ModelAdmin):
list_display = ('name', 'date_added', 'creator', 'description')
search_fields = ('name', 'description')
-admin.site.unregister(User)
-class UserProfileInline(admin.StackedInline):
- model = UserProfile
-class UserProfileAdmin(UserAdmin):
- inlines = [UserProfileInline]
- list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff', 'is_active')
- list_filter = ('is_staff', 'is_superuser', 'is_active')
-
-
-admin.site.register(User, UserProfileAdmin)
admin.site.register(Donor, DonorAdmin)
admin.site.register(Package, PackageAdmin)
diff --git a/main/fields.py b/main/fields.py
index 948cb5d9..2d5703ef 100644
--- a/main/fields.py
+++ b/main/fields.py
@@ -1,5 +1,4 @@
from django.db import models
-from django.core.validators import RegexValidator
class PositiveBigIntegerField(models.BigIntegerField):
@@ -13,30 +12,4 @@ class PositiveBigIntegerField(models.BigIntegerField):
defaults.update(kwargs)
return super(PositiveBigIntegerField, self).formfield(**defaults)
-class PGPKeyField(models.CharField):
- _south_introspects = True
-
- def __init__(self, *args, **kwargs):
- super(PGPKeyField, self).__init__(*args, **kwargs)
- self.validators.append(RegexValidator(r'^[0-9A-F]{40}$',
- "Ensure this value consists of 40 hex characters.", 'hex_char'))
-
- def to_python(self, value):
- if value == '' or value is None:
- return None
- value = super(PGPKeyField, self).to_python(value)
- # remove all spaces
- value = value.replace(' ', '')
- # prune prefixes, either 0x or 2048R/ type
- if value.startswith('0x'):
- value = value[2:]
- value = value.split('/')[-1]
- # make all (hex letters) uppercase
- return value.upper()
-
- def formfield(self, **kwargs):
- # override so we don't set max_length form field attribute
- return models.Field.formfield(self, **kwargs)
-
-
# vim: set ts=4 sw=4 et:
diff --git a/main/fixtures/groups.json b/main/fixtures/groups.json
index 0a3c966c..60db1635 100644
--- a/main/fixtures/groups.json
+++ b/main/fixtures/groups.json
@@ -422,12 +422,12 @@
],
[
"add_userprofile",
- "main",
+ "devel",
"userprofile"
],
[
"change_userprofile",
- "main",
+ "devel",
"userprofile"
]
]
diff --git a/main/migrations/0030_move_mirror_models.py b/main/migrations/0030_move_mirror_models.py
index 998ff6a2..1fe0c7e9 100644
--- a/main/migrations/0030_move_mirror_models.py
+++ b/main/migrations/0030_move_mirror_models.py
@@ -6,10 +6,6 @@ from django.db import models
class Migration(SchemaMigration):
- depends_on = (
- ('mirrors', '0002_rename_model_tables'),
- )
-
def forwards(self, orm):
pass
diff --git a/main/migrations/0031_move_news_out.py b/main/migrations/0031_move_news_out.py
index a730f4f3..28f4b750 100644
--- a/main/migrations/0031_move_news_out.py
+++ b/main/migrations/0031_move_news_out.py
@@ -6,10 +6,6 @@ from django.db import models
class Migration(SchemaMigration):
- depends_on = (
- ('news', '0002_move_news_in'),
- )
-
def forwards(self, orm):
pass
diff --git a/main/migrations/0034_update_content_type.py b/main/migrations/0034_update_content_type.py
index 779021da..59c6f6ad 100644
--- a/main/migrations/0034_update_content_type.py
+++ b/main/migrations/0034_update_content_type.py
@@ -5,31 +5,15 @@ from south.v2 import DataMigration
from django.db import models
class Migration(DataMigration):
-
- depends_on = (
- ('mirrors', '0002_rename_model_tables'),
- ('news', '0002_move_news_in'),
- )
-
- mirror_apps = [ 'mirror', 'mirrorprotocol', 'mirrorurl', 'mirrorrsync' ]
+ '''This is a defunct migration now, things have been moved to their proper
+ places, but removing it would cause all existing setups migrated past this
+ to complain.'''
def forwards(self, orm):
- ct = orm['contenttypes.ContentType'].objects
-
- # somehow these got in there already; remove them in favor of the old
- ct.filter(app_label='news').delete()
- ct.filter(app_label='mirrors').delete()
-
- ct.filter(app_label='main', model='news').update(app_label='news')
- ct.filter(app_label='main', model__in=self.mirror_apps).update(
- app_label='mirrors')
+ pass
def backwards(self, orm):
- ct = orm['contenttypes.ContentType'].objects
-
- ct.filter(app_label='mirrors', model__in=self.mirror_apps).update(
- app_label='main')
- ct.filter(app_label='news', model='news').update(app_label='main')
+ pass
models = {
'auth.group': {
diff --git a/main/migrations/0051_auto__chg_field_userprofile_pgp_key.py b/main/migrations/0051_auto__chg_field_userprofile_pgp_key.py
index 6b8abf6e..4905eb80 100644
--- a/main/migrations/0051_auto__chg_field_userprofile_pgp_key.py
+++ b/main/migrations/0051_auto__chg_field_userprofile_pgp_key.py
@@ -7,7 +7,7 @@ from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
- db.alter_column('user_profiles', 'pgp_key', self.gf('main.models.PGPKeyField')(max_length=40, null=True))
+ db.alter_column('user_profiles', 'pgp_key', self.gf('devel.fields.PGPKeyField')(max_length=40, null=True))
def backwards(self, orm):
@@ -146,7 +146,7 @@ class Migration(SchemaMigration):
'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
- 'pgp_key': ('main.models.PGPKeyField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'pgp_key': ('devel.fields.PGPKeyField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}),
'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
diff --git a/main/migrations/0052_auto__del_signoff.py b/main/migrations/0052_auto__del_signoff.py
index 8da6becc..a9ee633e 100644
--- a/main/migrations/0052_auto__del_signoff.py
+++ b/main/migrations/0052_auto__del_signoff.py
@@ -152,7 +152,7 @@ class Migration(SchemaMigration):
'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
- 'pgp_key': ('main.models.PGPKeyField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'pgp_key': ('devel.fields.PGPKeyField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}),
'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
diff --git a/main/migrations/0053_auto__add_field_package_pgp_signature.py b/main/migrations/0053_auto__add_field_package_pgp_signature.py
index a828d1ef..a3df5266 100644
--- a/main/migrations/0053_auto__add_field_package_pgp_signature.py
+++ b/main/migrations/0053_auto__add_field_package_pgp_signature.py
@@ -138,7 +138,7 @@ class Migration(SchemaMigration):
'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
- 'pgp_key': ('main.models.PGPKeyField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'pgp_key': ('devel.fields.PGPKeyField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}),
'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
diff --git a/main/migrations/0054_auto__add_field_donor_created.py b/main/migrations/0054_auto__add_field_donor_created.py
index c96c0f5d..81946c36 100644
--- a/main/migrations/0054_auto__add_field_donor_created.py
+++ b/main/migrations/0054_auto__add_field_donor_created.py
@@ -146,7 +146,7 @@ class Migration(SchemaMigration):
'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
- 'pgp_key': ('main.models.PGPKeyField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'pgp_key': ('devel.fields.PGPKeyField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}),
'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
diff --git a/main/migrations/0055_unique_package_in_repo.py b/main/migrations/0055_unique_package_in_repo.py
index 63951a08..36cc7193 100644
--- a/main/migrations/0055_unique_package_in_repo.py
+++ b/main/migrations/0055_unique_package_in_repo.py
@@ -141,7 +141,7 @@ class Migration(SchemaMigration):
'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
- 'pgp_key': ('main.models.PGPKeyField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'pgp_key': ('devel.fields.PGPKeyField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}),
'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
diff --git a/main/migrations/0056_auto__chg_field_package_pkgdesc.py b/main/migrations/0056_auto__chg_field_package_pkgdesc.py
index 21dd43af..90856fab 100644
--- a/main/migrations/0056_auto__chg_field_package_pkgdesc.py
+++ b/main/migrations/0056_auto__chg_field_package_pkgdesc.py
@@ -139,7 +139,7 @@ class Migration(SchemaMigration):
'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
- 'pgp_key': ('main.models.PGPKeyField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'pgp_key': ('devel.fields.PGPKeyField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}),
'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
diff --git a/main/migrations/0057_auto__add_field_userprofile_latin_name.py b/main/migrations/0057_auto__add_field_userprofile_latin_name.py
index ffde1885..b9328af0 100644
--- a/main/migrations/0057_auto__add_field_userprofile_latin_name.py
+++ b/main/migrations/0057_auto__add_field_userprofile_latin_name.py
@@ -139,7 +139,7 @@ class Migration(SchemaMigration):
'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
- 'pgp_key': ('main.models.PGPKeyField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'pgp_key': ('devel.fields.PGPKeyField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}),
'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
diff --git a/main/migrations/0058_auto__add_on_delete_attributes.py b/main/migrations/0058_auto__add_on_delete_attributes.py
new file mode 100644
index 00000000..e66e4da2
--- /dev/null
+++ b/main/migrations/0058_auto__add_on_delete_attributes.py
@@ -0,0 +1,160 @@
+# -*- 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.alter_column('todolists', 'creator_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], on_delete=models.PROTECT))
+ db.alter_column('packages', 'repo_id', self.gf('django.db.models.fields.related.ForeignKey')(on_delete=models.PROTECT, to=orm['main.Repo']))
+ db.alter_column('packages', 'packager_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, on_delete=models.SET_NULL))
+ db.alter_column('packages', 'arch_id', self.gf('django.db.models.fields.related.ForeignKey')(on_delete=models.PROTECT, to=orm['main.Arch']))
+
+ def backwards(self, orm):
+ db.alter_column('todolists', 'creator_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User']))
+ db.alter_column('packages', 'repo_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['main.Repo']))
+ db.alter_column('packages', 'packager_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True))
+ db.alter_column('packages', 'arch_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['main.Arch']))
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'main.arch': {
+ 'Meta': {'ordering': "['name']", 'object_name': 'Arch', 'db_table': "'arches'"},
+ 'agnostic': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
+ },
+ 'main.donor': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'Donor', 'db_table': "'donors'"},
+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'visible': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
+ },
+ 'main.package': {
+ 'Meta': {'ordering': "('pkgname',)", 'unique_together': "(('pkgname', 'repo', 'arch'),)", 'object_name': 'Package', 'db_table': "'packages'"},
+ 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'on_delete': 'models.PROTECT', 'to': "orm['main.Arch']"}),
+ 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'compressed_size': ('main.fields.PositiveBigIntegerField', [], {}),
+ 'epoch': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'flag_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'installed_size': ('main.fields.PositiveBigIntegerField', [], {}),
+ 'last_update': ('django.db.models.fields.DateTimeField', [], {}),
+ 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'on_delete': 'models.SET_NULL'}),
+ 'packager_str': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'pgp_signature': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'pkgdesc': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'on_delete': 'models.PROTECT', 'to': "orm['main.Repo']"}),
+ 'url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'})
+ },
+ 'main.packagedepend': {
+ 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"},
+ 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'depvcmp': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'optional': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'depends'", 'to': "orm['main.Package']"})
+ },
+ 'main.packagefile': {
+ 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"},
+ 'directory': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_directory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"})
+ },
+ 'main.repo': {
+ 'Meta': {'ordering': "['name']", 'object_name': 'Repo', 'db_table': "'repos'"},
+ 'bugs_category': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}),
+ 'bugs_project': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'staging': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'svn_root': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'main.todolist': {
+ 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"},
+ 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'on_delete': 'models.PROTECT'}),
+ 'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ },
+ 'main.todolistpkg': {
+ 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"},
+ 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}),
+ 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"})
+ },
+ 'main.userprofile': {
+ 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"},
+ 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'latin_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'pgp_key': ('devel.fields.PGPKeyField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}),
+ 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'time_zone': ('django.db.models.fields.CharField', [], {'default': "'UTC'", 'max_length': '100'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'userprofile'", 'unique': 'True', 'to': "orm['auth.User']"}),
+ 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ }
+ }
+
+ complete_apps = ['main']
diff --git a/main/migrations/0059_auto__del_userprofile.py b/main/migrations/0059_auto__del_userprofile.py
new file mode 100644
index 00000000..2db87eeb
--- /dev/null
+++ b/main/migrations/0059_auto__del_userprofile.py
@@ -0,0 +1,137 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ pass
+
+ def backwards(self, orm):
+ if not db.dry_run:
+ db.send_create_signal('main', ['UserProfile'])
+ orm['contenttypes.ContentType'].objects.filter(
+ app_label='devel', model='userprofile').update(
+ app_label='main')
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'main.arch': {
+ 'Meta': {'ordering': "['name']", 'object_name': 'Arch', 'db_table': "'arches'"},
+ 'agnostic': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
+ },
+ 'main.donor': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'Donor', 'db_table': "'donors'"},
+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'visible': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
+ },
+ 'main.package': {
+ 'Meta': {'ordering': "('pkgname',)", 'unique_together': "(('pkgname', 'repo', 'arch'),)", 'object_name': 'Package', 'db_table': "'packages'"},
+ 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'on_delete': 'models.PROTECT', 'to': "orm['main.Arch']"}),
+ 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'compressed_size': ('main.fields.PositiveBigIntegerField', [], {}),
+ 'epoch': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'flag_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'installed_size': ('main.fields.PositiveBigIntegerField', [], {}),
+ 'last_update': ('django.db.models.fields.DateTimeField', [], {}),
+ 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'on_delete': 'models.SET_NULL'}),
+ 'packager_str': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'pgp_signature': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'pkgdesc': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'on_delete': 'models.PROTECT', 'to': "orm['main.Repo']"}),
+ 'url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'})
+ },
+ 'main.packagedepend': {
+ 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"},
+ 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'depvcmp': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'optional': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'depends'", 'to': "orm['main.Package']"})
+ },
+ 'main.packagefile': {
+ 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"},
+ 'directory': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_directory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"})
+ },
+ 'main.repo': {
+ 'Meta': {'ordering': "['name']", 'object_name': 'Repo', 'db_table': "'repos'"},
+ 'bugs_category': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}),
+ 'bugs_project': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'staging': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'svn_root': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'main.todolist': {
+ 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"},
+ 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'on_delete': 'models.PROTECT'}),
+ 'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ },
+ 'main.todolistpkg': {
+ 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"},
+ 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}),
+ 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"})
+ }
+ }
+
+ complete_apps = ['main']
diff --git a/main/migrations/0060_add_packages_last_update_index.py b/main/migrations/0060_add_packages_last_update_index.py
new file mode 100644
index 00000000..8e3bb892
--- /dev/null
+++ b/main/migrations/0060_add_packages_last_update_index.py
@@ -0,0 +1,131 @@
+# -*- 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.create_index('packages', ['last_update'])
+
+ def backwards(self, orm):
+ db.delete_index('packages', ['last_update'])
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'main.arch': {
+ 'Meta': {'ordering': "['name']", 'object_name': 'Arch', 'db_table': "'arches'"},
+ 'agnostic': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
+ },
+ 'main.donor': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'Donor', 'db_table': "'donors'"},
+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'visible': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
+ },
+ 'main.package': {
+ 'Meta': {'ordering': "('pkgname',)", 'unique_together': "(('pkgname', 'repo', 'arch'),)", 'object_name': 'Package', 'db_table': "'packages'"},
+ 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'on_delete': 'models.PROTECT', 'to': "orm['main.Arch']"}),
+ 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'compressed_size': ('main.fields.PositiveBigIntegerField', [], {}),
+ 'epoch': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'flag_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'installed_size': ('main.fields.PositiveBigIntegerField', [], {}),
+ 'last_update': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
+ 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'on_delete': 'models.SET_NULL'}),
+ 'packager_str': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'pgp_signature': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'pkgdesc': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'on_delete': 'models.PROTECT', 'to': "orm['main.Repo']"}),
+ 'url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'})
+ },
+ 'main.packagedepend': {
+ 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"},
+ 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'depvcmp': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'optional': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'depends'", 'to': "orm['main.Package']"})
+ },
+ 'main.packagefile': {
+ 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"},
+ 'directory': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_directory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"})
+ },
+ 'main.repo': {
+ 'Meta': {'ordering': "['name']", 'object_name': 'Repo', 'db_table': "'repos'"},
+ 'bugs_category': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}),
+ 'bugs_project': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'staging': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'svn_root': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'main.todolist': {
+ 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"},
+ 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'on_delete': 'models.PROTECT'}),
+ 'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ },
+ 'main.todolistpkg': {
+ 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"},
+ 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}),
+ 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"})
+ }
+ }
+
+ complete_apps = ['main']
diff --git a/main/models.py b/main/models.py
index db926dda..c532ed56 100644
--- a/main/models.py
+++ b/main/models.py
@@ -2,68 +2,14 @@ from base64 import b64decode
from datetime import datetime
from itertools import groupby
from pgpdump import BinaryData
-import pytz
from django.db import models
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
-from .fields import PositiveBigIntegerField, PGPKeyField
-from .utils import cache_function, make_choice, set_created_field, utc_now
-
-
-class UserProfile(models.Model):
- notify = models.BooleanField(
- "Send notifications",
- default=True,
- help_text="When enabled, send user 'flag out-of-date' notifications")
- time_zone = models.CharField(
- max_length=100,
- choices=make_choice(pytz.common_timezones),
- default="UTC",
- help_text="Used for developer clock page")
- alias = models.CharField(
- max_length=50,
- help_text="Required field")
- public_email = models.CharField(
- max_length=50,
- help_text="Required field")
- other_contact = models.CharField(max_length=100, null=True, blank=True)
- pgp_key = PGPKeyField(max_length=40, null=True, blank=True,
- verbose_name="PGP key fingerprint",
- help_text="consists of 40 hex digits; use `gpg --fingerprint`")
- website = models.CharField(max_length=200, null=True, blank=True)
- yob = models.IntegerField("Year of birth", null=True, blank=True)
- location = models.CharField(max_length=50, null=True, blank=True)
- languages = models.CharField(max_length=50, null=True, blank=True)
- interests = models.CharField(max_length=255, null=True, blank=True)
- occupation = models.CharField(max_length=50, null=True, blank=True)
- roles = models.CharField(max_length=255, null=True, blank=True)
- favorite_distros = models.CharField(max_length=255, null=True, blank=True)
- picture = models.FileField(upload_to='devs', default='devs/silhouette.png',
- help_text="Ideally 125px by 125px")
- user = models.OneToOneField(User, related_name='userprofile')
- allowed_repos = models.ManyToManyField('Repo', blank=True)
- latin_name = models.CharField(max_length=255, null=True, blank=True,
- help_text="Latin-form name; used only for non-Latin full names")
+from .fields import PositiveBigIntegerField
+from .utils import cache_function, set_created_field, utc_now
- class Meta:
- db_table = 'user_profiles'
- verbose_name = 'Additional Profile Data'
- verbose_name_plural = 'Additional Profile Data'
-
- def get_absolute_url(self):
- # TODO: this is disgusting. find a way to consolidate this logic with
- # public.views.userlist among other places, and make some constants or
- # something so we aren't using copies of string names everywhere.
- group_names = self.user.groups.values_list('name', flat=True)
- if "Developers" in group_names:
- prefix = "developers"
- elif "Trusted Users" in group_names:
- prefix = "trustedusers"
- else:
- prefix = "fellows"
- return '/%s/#%s' % (prefix, self.user.username)
class TodolistManager(models.Manager):
def incomplete(self):
@@ -147,7 +93,7 @@ class Package(models.Model):
compressed_size = PositiveBigIntegerField()
installed_size = PositiveBigIntegerField()
build_date = models.DateTimeField(null=True)
- last_update = models.DateTimeField()
+ last_update = models.DateTimeField(db_index=True)
files_last_update = models.DateTimeField(null=True, blank=True)
packager_str = models.CharField(max_length=255)
packager = models.ForeignKey(User, null=True,
diff --git a/mirrors/migrations/0002_rename_model_tables.py b/mirrors/migrations/0002_rename_model_tables.py
index d510bada..087edd68 100644
--- a/mirrors/migrations/0002_rename_model_tables.py
+++ b/mirrors/migrations/0002_rename_model_tables.py
@@ -7,21 +7,33 @@ from django.db import models
class Migration(SchemaMigration):
depends_on = (
- ('main', '0014_mirror_notes_rsync_optional'),
+ ('main', '0030_move_mirror_models'),
)
+ mirror_apps = [ 'mirror', 'mirrorprotocol', 'mirrorurl', 'mirrorrsync' ]
+
def forwards(self, orm):
db.rename_table('main_mirror', 'mirrors_mirror')
db.rename_table('main_mirrorurl', 'mirrors_mirrorurl')
db.rename_table('main_mirrorrsync', 'mirrors_mirrorrsync')
db.rename_table('main_mirrorprotocol', 'mirrors_mirrorprotocol')
+ if not db.dry_run:
+ ct = orm['contenttypes.ContentType'].objects
+ ct.filter(app_label='main', model__in=self.mirror_apps).update(
+ app_label='mirrors')
+
def backwards(self, orm):
db.rename_table('mirrors_mirror', 'main_mirror')
db.rename_table('mirrors_mirrorurl', 'main_mirrorurl')
db.rename_table('mirrors_mirrorrsync', 'main_mirrorrsync')
db.rename_table('mirrors_mirrorprotocol', 'main_mirrorprotocol')
+ if not db.dry_run:
+ ct = orm['contenttypes.ContentType'].objects
+ ct.filter(app_label='mirrors', model__in=self.mirror_apps).update(
+ app_label='main')
+
models = {
'mirrors.mirror': {
'Meta': {'ordering': "('country', 'name')", 'object_name': 'Mirror'},
@@ -55,6 +67,13 @@ class Migration(SchemaMigration):
'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['mirrors.Mirror']"}),
'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['mirrors.MirrorProtocol']"}),
'url': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
}
}
diff --git a/mirrors/migrations/0012_auto__add_on_delete_attribute.py b/mirrors/migrations/0012_auto__add_on_delete_attribute.py
new file mode 100644
index 00000000..3990d466
--- /dev/null
+++ b/mirrors/migrations/0012_auto__add_on_delete_attribute.py
@@ -0,0 +1,68 @@
+# -*- 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.alter_column('mirrors_mirror', 'upstream_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['mirrors.Mirror'], null=True, on_delete=models.SET_NULL))
+ db.alter_column('mirrors_mirrorurl', 'protocol_id', self.gf('django.db.models.fields.related.ForeignKey')(on_delete=models.PROTECT, to=orm['mirrors.MirrorProtocol']))
+
+ def backwards(self, orm):
+ db.alter_column('mirrors_mirror', 'upstream_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['mirrors.Mirror'], null=True))
+ db.alter_column('mirrors_mirrorurl', 'protocol_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['mirrors.MirrorProtocol']))
+
+ models = {
+ 'mirrors.mirror': {
+ 'Meta': {'ordering': "('country', 'name')", 'object_name': 'Mirror'},
+ 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}),
+ 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ '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': "orm['mirrors.Mirror']", 'null': 'True', 'on_delete': 'models.SET_NULL'})
+ },
+ '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.CharField', [], {'default': "''", 'max_length': '255', 'blank': 'True'}),
+ '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'}),
+ 'url': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'logs'", 'to': "orm['mirrors.MirrorUrl']"})
+ },
+ 'mirrors.mirrorprotocol': {
+ 'Meta': {'ordering': "('protocol',)", 'object_name': 'MirrorProtocol'},
+ 'default': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ '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'})
+ },
+ 'mirrors.mirrorrsync': {
+ 'Meta': {'object_name': 'MirrorRsync'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}),
+ 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['mirrors.Mirror']"})
+ },
+ 'mirrors.mirrorurl': {
+ 'Meta': {'object_name': 'MirrorUrl'},
+ 'country': ('mirrors.models.NullCharField', [], {'db_index': 'True', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'has_ipv4': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'has_ipv6': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['mirrors.Mirror']"}),
+ 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'on_delete': 'models.PROTECT', 'to': "orm['mirrors.MirrorProtocol']"}),
+ 'url': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
+ }
+ }
+
+ complete_apps = ['mirrors']
diff --git a/mirrors/utils.py b/mirrors/utils.py
index 619d5f5c..ddecb095 100644
--- a/mirrors/utils.py
+++ b/mirrors/utils.py
@@ -108,7 +108,7 @@ def get_mirror_url_for_download(cutoff=default_cutoff):
status_data = MirrorLog.objects.filter(
check_time__gte=cutoff_time).aggregate(
Max('check_time'), Max('last_sync'))
- if status_data:
+ if status_data['check_time__max'] is not None:
min_check_time = status_data['check_time__max'] - timedelta(minutes=5)
min_sync_time = status_data['last_sync__max'] - timedelta(minutes=30)
best_logs = MirrorLog.objects.filter(is_success=True,
diff --git a/news/migrations/0002_move_news_in.py b/news/migrations/0002_move_news_in.py
index d6dafad4..43d68df4 100644
--- a/news/migrations/0002_move_news_in.py
+++ b/news/migrations/0002_move_news_in.py
@@ -7,14 +7,19 @@ from django.db import models
class Migration(SchemaMigration):
depends_on = (
- ('main', '0001_initial'),
+ ('main', '0031_move_news_out'),
)
def forwards(self, orm):
- pass
+ db.send_create_signal('news', ['News'])
+ if not db.dry_run:
+ ct = orm['contenttypes.ContentType'].objects
+ ct.filter(app_label='main', model='news').update(app_label='news')
def backwards(self, orm):
- pass
+ if not db.dry_run:
+ ct = orm['contenttypes.ContentType'].objects
+ ct.filter(app_label='news', model='news').update(app_label='main')
models = {
'auth.group': {
diff --git a/news/migrations/0010_auto__chg_field_news_author.py b/news/migrations/0010_auto__chg_field_news_author.py
new file mode 100644
index 00000000..64fdc580
--- /dev/null
+++ b/news/migrations/0010_auto__chg_field_news_author.py
@@ -0,0 +1,65 @@
+# -*- 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.alter_column('news', 'author_id', self.gf('django.db.models.fields.related.ForeignKey')(on_delete=models.PROTECT, to=orm['auth.User']))
+
+ def backwards(self, orm):
+ db.alter_column('news', 'author_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User']))
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'news.news': {
+ 'Meta': {'ordering': "['-postdate']", 'object_name': 'News', 'db_table': "'news'"},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'news_author'", 'on_delete': 'models.PROTECT', 'to': "orm['auth.User']"}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'guid': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_modified': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
+ 'postdate': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ }
+ }
+
+ complete_apps = ['news']
diff --git a/releng/views.py b/releng/views.py
index 007c8c84..33e8fb31 100644
--- a/releng/views.py
+++ b/releng/views.py
@@ -177,12 +177,18 @@ def submit_test_thanks(request):
def iso_overview(request):
isos = Iso.objects.all().order_by('-pk')
- successes = dict(Iso.objects.values_list('pk').filter(test__success=True).annotate(ct=Count('test')))
- failures = dict(Iso.objects.values_list('pk').filter(test__success=False).annotate(ct=Count('test')))
+ successes = dict(Iso.objects.values_list('pk').filter(
+ test__success=True).annotate(ct=Count('test')))
+ failures = dict(Iso.objects.values_list('pk').filter(
+ test__success=False).annotate(ct=Count('test')))
for iso in isos:
iso.successes = successes.get(iso.pk, 0)
iso.failures = failures.get(iso.pk, 0)
+ # only show "useful" rows, currently active ISOs or those with results
+ isos = [iso for iso in isos if
+ iso.active == True or iso.successes > 0 or iso.failures > 0]
+
context = {
'isos': isos
}
diff --git a/settings.py b/settings.py
index 735bf8b8..431c5579 100644
--- a/settings.py
+++ b/settings.py
@@ -43,7 +43,7 @@ LOGIN_URL = '/login/'
LOGIN_REDIRECT_URL = '/'
# Set django's User stuff to use our profile model
-AUTH_PROFILE_MODULE = 'main.UserProfile'
+AUTH_PROFILE_MODULE = 'devel.UserProfile'
# We add a processor to determine if the request is secure or not
TEMPLATE_CONTEXT_PROCESSORS = (
diff --git a/templates/devel/index.html b/templates/devel/index.html
index cda510e4..9f897317 100644
--- a/templates/devel/index.html
+++ b/templates/devel/index.html
@@ -148,7 +148,7 @@
<h3>Developer Reports</h3>
<ul>
<li><a href="reports/old/">Old</a>:
- Packages last built more than two years ago
+ Packages last built more than one year ago
(<a href="reports/old/{{ user.username }}/">yours only</a>)</li>
<li><a href="reports/long-out-of-date/">Long Out-of-date</a>:
Packages marked out-of-date more than 90 days ago
diff --git a/templates/packages/details.html b/templates/packages/details.html
index 00b2c70c..8e4b2bb0 100644
--- a/templates/packages/details.html
+++ b/templates/packages/details.html
@@ -81,7 +81,7 @@
{% with pkg.split_packages as splits %}{% if splits %}
<tr>
<th>Split Packages:</th>
- <td>{% for s in splits %}{% pkg_details_link s %}<br/>{% endfor %}</td>
+ <td class="wrap">{% for s in splits %}{% pkg_details_link s %}{% if not forloop.last %}, {% endif %}{% endfor %}</td>
</tr>
{% endif %}{% endwith %}
{% else %}
@@ -104,22 +104,33 @@
title="Visit the website for {{ pkg.pkgname }}">{{ pkg.url|url_unquote }}</a>{% endif %}</td>
</tr><tr>
<th>License(s):</th>
- <td>{{ pkg.licenses.all|join:", " }}</td>
+ <td class="wrap">{{ pkg.licenses.all|join:", " }}</td>
</tr>
{% with pkg.groups.all as groups %}{% if groups %}
<tr>
<th>Groups:</th>
- <td>{% for g in groups %}
+ <td class="wrap">{% for g in groups %}
<a href="/groups/{{ pkg.arch.name }}/{{ g.name }}/"
- title="Group details for {{ g.name }}">{{ g.name }}</a><br/>
- {% endfor %}
+ title="Group details for {{ g.name }}">{{ g.name }}</a>{% if not forloop.last %}, {% endif %}{% endfor %}
</td>
</tr>
{% endif %}{% endwith %}
{% with pkg.provides.all as provides %}{% if provides %}
<tr>
<th>Provides:</th>
- <td>{% for p in provides %}{{ p.name }}{% if p.version %}={{ p.version }}{% endif %}<br/>{% endfor %}</td>
+ <td class="wrap">{{ provides|join:", " }}</td>
+ </tr>
+ {% endif %}{% endwith %}
+ {% with pkg.conflicts.all as conflicts %}{% if conflicts %}
+ <tr>
+ <th>Conflicts:</th>
+ <td class="wrap">{{ conflicts|join:", " }}</td>
+ </tr>
+ {% endif %}{% endwith %}
+ {% with pkg.replaces.all as replaces %}{% if replaces %}
+ <tr>
+ <th>Replaces:</th>
+ <td class="wrap">{{ replaces|join:", " }}</td>
</tr>
{% endif %}{% endwith %}
<tr>
diff --git a/templates/releng/iso_overview.html b/templates/releng/iso_overview.html
index ca5a8c08..447ba487 100644
--- a/templates/releng/iso_overview.html
+++ b/templates/releng/iso_overview.html
@@ -6,6 +6,12 @@
<div class="box">
<h2>Failures and Successes for Testing ISOs</h2>
+ <p>This is an overview showing all current or tested release engineering
+ produced ISOs. Past but now unavailable ISOs are ommitted if there were
+ never any testing results submitted. To help improve ISO quality, you are
+ encouraged to <a href="{% url 'releng-test-submit' %}">give feedback</a>
+ if you have tested and used any ISOs. Both successful and failed results
+ are encouraged and welcome.</p>
<p><a href="{% url 'releng-test-overview' %}">Go back to testing results</a></p>
<table id="releng-result" class="results">
diff --git a/templates/releng/results.html b/templates/releng/results.html
index fa694cc6..49d81ec4 100644
--- a/templates/releng/results.html
+++ b/templates/releng/results.html
@@ -7,7 +7,7 @@
<div class="box">
<h2>Release Engineering Testbuild Results</h2>
- <p>This is an overview screen showing a test results matrix of release
+ <p>This is an overview showing a test results matrix of release
engineering produced ISOs. Various options and configurations are shown
with last success and last failure results, if known. To help improve ISO
quality, you are encouraged to <a href="{% url 'releng-test-submit' %}">give feedback</a>