diff options
author | Luke Shumaker <LukeShu@sbcglobal.net> | 2012-11-14 22:02:39 -0500 |
---|---|---|
committer | Luke Shumaker <LukeShu@sbcglobal.net> | 2012-11-14 22:02:39 -0500 |
commit | a2db6164a890d91307cbfed6794776f4f17c4955 (patch) | |
tree | 610deaae4780da796aa6b466c4b20868306926b8 | |
parent | 4c22dbf07b12b172d9662c8d809fe0fb7b616a2f (diff) | |
parent | d198137d718a5dfcaacedc3e2e3adf86c3192cd7 (diff) |
Merge commit 'd198137' (update)
-rw-r--r-- | devel/views.py | 42 | ||||
-rw-r--r-- | main/models.py | 2 | ||||
-rw-r--r-- | packages/admin.py | 11 | ||||
-rw-r--r-- | packages/management/commands/populate_signoffs.py | 16 | ||||
-rw-r--r-- | packages/migrations/0012_auto__add_flagrequest.py | 201 | ||||
-rw-r--r-- | packages/models.py | 45 | ||||
-rw-r--r-- | packages/views/flag.py | 20 | ||||
-rw-r--r-- | public/utils.py | 7 | ||||
-rw-r--r-- | sitestatic/archweb.css | 8 | ||||
-rw-r--r-- | templates/public/index.html | 2 |
10 files changed, 307 insertions, 47 deletions
diff --git a/devel/views.py b/devel/views.py index c888871d..f7ed3539 100644 --- a/devel/views.py +++ b/devel/views.py @@ -6,7 +6,7 @@ from django.contrib.auth.models import User, Group from django.contrib.sites.models import Site from django.core.mail import send_mail from django.db import transaction -from django.db.models import F, Q +from django.db.models import F from django.http import Http404 from django.shortcuts import get_object_or_404 from django.template import loader, Context @@ -150,6 +150,15 @@ def report(request, report, username=None): packages = Package.objects.normal() names = attrs = user = None + if username: + user = get_object_or_404(User, username=username, is_active=True) + maintained = PackageRelation.objects.filter(user=user, + type=PackageRelation.MAINTAINER).values('pkgbase') + packages = packages.filter(pkgbase__in=maintained) + + maints = User.objects.filter(id__in=PackageRelation.objects.filter( + type=PackageRelation.MAINTAINER).values('user')) + if report == 'old': title = 'Packages last built more than two years ago' cutoff = datetime.utcnow() - timedelta(days=365 * 2) @@ -192,20 +201,24 @@ def report(request, report, username=None): package.compress_type = package.filename.split('.')[-1] elif report == 'uncompressed-man': title = 'Packages with uncompressed manpages' - # magic going on here! Checking for all '.1'...'.9' extensions - invalid_endings = [Q(filename__endswith='.%d' % n) for n in range(1,10)] - invalid_endings.append(Q(filename__endswith='.n')) - bad_files = PackageFile.objects.filter(Q(directory__contains='man') & ( - reduce(operator.or_, invalid_endings)) - ).values_list('pkg_id', flat=True).distinct() + # checking for all '.0'...'.9' + '.n' extensions + bad_files = PackageFile.objects.filter(directory__contains='/man/', + filename__regex=r'\.[0-9n]').exclude(filename__endswith='.gz') + if username: + pkg_ids = set(packages.values_list('id', flat=True)) + bad_files = bad_files.filter(pkg__in=pkg_ids) + bad_files = bad_files.values_list('pkg_id', flat=True).distinct() packages = packages.filter(id__in=set(bad_files)) elif report == 'uncompressed-info': title = 'Packages with uncompressed infopages' - # we don't worry abut looking for '*.info-1', etc., given that an + # we don't worry about looking for '*.info-1', etc., given that an # uncompressed root page probably exists in the package anyway bad_files = PackageFile.objects.filter(directory__endswith='/info/', - filename__endswith='.info').values_list( - 'pkg_id', flat=True).distinct() + filename__endswith='.info') + if username: + pkg_ids = set(packages.values_list('id', flat=True)) + bad_files = bad_files.filter(pkg__in=pkg_ids) + bad_files = bad_files.values_list('pkg_id', flat=True).distinct() packages = packages.filter(id__in=set(bad_files)) elif report == 'unneeded-orphans': title = 'Orphan packages required by no other packages' @@ -217,15 +230,6 @@ def report(request, report, username=None): else: raise Http404 - if username: - user = get_object_or_404(User, username=username, is_active=True) - maintained = PackageRelation.objects.filter(user=user, - type=PackageRelation.MAINTAINER).values('pkgbase') - packages = packages.filter(pkgbase__in=maintained) - - maints = User.objects.filter(id__in=PackageRelation.objects.filter( - type=PackageRelation.MAINTAINER).values('user')) - context = { 'all_maintainers': maints, 'title': title, diff --git a/main/models.py b/main/models.py index 9156fb51..cefebf76 100644 --- a/main/models.py +++ b/main/models.py @@ -6,7 +6,6 @@ from django.forms import ValidationError from .fields import PositiveBigIntegerField, PGPKeyField from .utils import cache_function, make_choice, set_created_field -from packages.models import PackageRelation from datetime import datetime from itertools import groupby @@ -193,6 +192,7 @@ class Package(models.Model): @property def maintainers(self): + from packages.models import PackageRelation if self._maintainers is None: self._maintainers = User.objects.filter( package_relations__pkgbase=self.pkgbase, diff --git a/packages/admin.py b/packages/admin.py index 01b6ed6c..14fa8960 100644 --- a/packages/admin.py +++ b/packages/admin.py @@ -1,12 +1,21 @@ from django.contrib import admin -from .models import PackageRelation +from .models import PackageRelation, FlagRequest class PackageRelationAdmin(admin.ModelAdmin): list_display = ('user', 'pkgbase', 'type', 'created') list_filter = ('type', 'user') search_fields = ('user__username', 'pkgbase') + date_hierarchy = 'created' + +class FlagRequestAdmin(admin.ModelAdmin): + list_display = ('pkgbase', 'created', 'who', 'is_spam', 'is_legitimate', + 'message') + list_filter = ('is_spam', 'is_legitimate') + search_fields = ('pkgbase', 'user_email', 'message') + date_hierarchy = 'created' admin.site.register(PackageRelation, PackageRelationAdmin) +admin.site.register(FlagRequest, FlagRequestAdmin) # vim: set ts=4 sw=4 et: diff --git a/packages/management/commands/populate_signoffs.py b/packages/management/commands/populate_signoffs.py index ce5ec734..42496e9d 100644 --- a/packages/management/commands/populate_signoffs.py +++ b/packages/management/commands/populate_signoffs.py @@ -44,6 +44,9 @@ class Command(NoArgsCommand): return add_signoff_comments() def svn_log(pkgbase, repo): + '''Retrieve the most recent SVN log entry for the given pkgbase and + repository. The configured setting SVN_BASE_URL is used along with the + svn_root for each repository to form the correct URL.''' path = '%s%s/%s/trunk/' % (settings.SVN_BASE_URL, repo.svn_root, pkgbase) cmd = ['svn', 'log', '--limit=1', '--xml', path] log_data = subprocess.check_output(cmd) @@ -59,6 +62,17 @@ def svn_log(pkgbase, repo): 'message': xml.findtext('logentry/msg'), } +def cached_svn_log(pkgbase, repo): + '''Retrieve the cached version of the SVN log if possible, else delegate to + svn_log() to do the work and cache the result.''' + key = (pkgbase, repo) + if key in cached_svn_log.cache: + return cached_svn_log.cache[key] + log = svn_log(pkgbase, repo) + cached_svn_log.cache[key] = log + return log +cached_svn_log.cache = {} + def create_specification(package, log, finder): trimmed_message = log['message'].strip() spec = SignoffSpecification(pkgbase=package.pkgbase, @@ -80,7 +94,7 @@ def add_signoff_comments(): continue logger.debug("getting SVN log for %s (%s)", group.pkgbase, group.repo) - log = svn_log(group.pkgbase, group.repo) + log = cached_svn_log(group.pkgbase, group.repo) logger.info("creating spec with SVN message for %s", group.pkgbase) spec = create_specification(group.packages[0], log, finder) spec.save() diff --git a/packages/migrations/0012_auto__add_flagrequest.py b/packages/migrations/0012_auto__add_flagrequest.py new file mode 100644 index 00000000..a501daff --- /dev/null +++ b/packages/migrations/0012_auto__add_flagrequest.py @@ -0,0 +1,201 @@ +# encoding: utf-8 +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'FlagRequest' + db.create_table('packages_flagrequest', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)), + ('user_email', self.gf('django.db.models.fields.EmailField')(max_length=75)), + ('created', self.gf('django.db.models.fields.DateTimeField')()), + ('ip_address', self.gf('django.db.models.fields.IPAddressField')(max_length=15)), + ('pkgbase', self.gf('django.db.models.fields.CharField')(max_length=255, db_index=True)), + ('repo', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['main.Repo'])), + ('num_packages', self.gf('django.db.models.fields.PositiveIntegerField')(default=1)), + ('message', self.gf('django.db.models.fields.TextField')(blank=True)), + ('is_spam', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('is_legitimate', self.gf('django.db.models.fields.BooleanField')(default=True)), + )) + db.send_create_signal('packages', ['FlagRequest']) + + if db.backend_name == 'mysql': + # stupid f#$%ing storage of IP address as a 15 character type + db.execute("ALTER TABLE packages_flagrequest " + "MODIFY ip_address char(39) NOT NULL") + + + def backwards(self, orm): + # Deleting model 'FlagRequest' + db.delete_table('packages_flagrequest') + + + 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.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'", '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'}), + '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'", 'to': "orm['main.Repo']"}), + 'url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}) + }, + 'main.repo': { + 'Meta': {'ordering': "['name']", 'object_name': 'Repo', 'db_table': "'repos'"}, + 'bugs_category': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + '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'}) + }, + 'packages.conflict': { + 'Meta': {'ordering': "['name']", 'object_name': 'Conflict'}, + 'comparison': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'conflicts'", 'to': "orm['main.Package']"}), + 'version': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}) + }, + 'packages.flagrequest': { + 'Meta': {'object_name': 'FlagRequest'}, + 'created': ('django.db.models.fields.DateTimeField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}), + 'is_legitimate': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_spam': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'message': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'num_packages': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'repo': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Repo']"}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}) + }, + 'packages.license': { + 'Meta': {'ordering': "['name']", 'object_name': 'License'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'licenses'", 'to': "orm['main.Package']"}) + }, + 'packages.packagegroup': { + 'Meta': {'object_name': 'PackageGroup'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'groups'", 'to': "orm['main.Package']"}) + }, + 'packages.packagerelation': { + 'Meta': {'unique_together': "(('pkgbase', 'user', 'type'),)", 'object_name': 'PackageRelation'}, + 'created': ('django.db.models.fields.DateTimeField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'type': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'package_relations'", 'to': "orm['auth.User']"}) + }, + 'packages.provision': { + 'Meta': {'ordering': "['name']", 'object_name': 'Provision'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'provides'", 'to': "orm['main.Package']"}), + 'version': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}) + }, + 'packages.replacement': { + 'Meta': {'ordering': "['name']", 'object_name': 'Replacement'}, + 'comparison': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'replaces'", 'to': "orm['main.Package']"}), + 'version': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}) + }, + 'packages.signoff': { + 'Meta': {'object_name': 'Signoff'}, + 'arch': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Arch']"}), + 'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {}), + 'epoch': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + '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', [], {'to': "orm['main.Repo']"}), + 'revoked': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'package_signoffs'", 'to': "orm['auth.User']"}) + }, + 'packages.signoffspecification': { + 'Meta': {'object_name': 'SignoffSpecification'}, + 'arch': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Arch']"}), + 'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {}), + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'epoch': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'known_bad': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + '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', [], {'to': "orm['main.Repo']"}), + 'required': ('django.db.models.fields.PositiveIntegerField', [], {'default': '2'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}) + } + } + + complete_apps = ['packages'] diff --git a/packages/models.py b/packages/models.py index 0d02ab31..77cade68 100644 --- a/packages/models.py +++ b/packages/models.py @@ -4,6 +4,7 @@ from django.db import models from django.db.models.signals import pre_save, post_save from django.contrib.auth.models import User +from main.models import Arch, Repo from main.utils import set_created_field class PackageRelation(models.Model): @@ -71,8 +72,8 @@ class SignoffSpecification(models.Model): pkgver = models.CharField(max_length=255) pkgrel = models.CharField(max_length=255) epoch = models.PositiveIntegerField(default=0) - arch = models.ForeignKey('main.Arch') - repo = models.ForeignKey('main.Repo') + arch = models.ForeignKey(Arch) + repo = models.ForeignKey(Repo) user = models.ForeignKey(User, null=True) created = models.DateTimeField(editable=False) required = models.PositiveIntegerField(default=2, @@ -134,8 +135,8 @@ class Signoff(models.Model): pkgver = models.CharField(max_length=255) pkgrel = models.CharField(max_length=255) epoch = models.PositiveIntegerField(default=0) - arch = models.ForeignKey('main.Arch') - repo = models.ForeignKey('main.Repo') + arch = models.ForeignKey(Arch) + repo = models.ForeignKey(Repo) user = models.ForeignKey(User, related_name="package_signoffs") created = models.DateTimeField(editable=False) revoked = models.DateTimeField(null=True) @@ -164,6 +165,29 @@ class Signoff(models.Model): return u'%s-%s: %s%s' % ( self.pkgbase, self.full_version, self.user, revoked) + +class FlagRequest(models.Model): + user = models.ForeignKey(User, blank=True, null=True) + user_email = models.EmailField('email address') + created = models.DateTimeField(editable=False) + ip_address = models.IPAddressField('IP address') + pkgbase = models.CharField(max_length=255, db_index=True) + repo = models.ForeignKey(Repo) + num_packages = models.PositiveIntegerField('number of packages', default=1) + message = models.TextField('message to developer', blank=True) + is_spam = models.BooleanField(default=False, + help_text="Is this comment from a real person?") + is_legitimate = models.BooleanField(default=True, + help_text="Is this actually an out-of-date flag request?") + + def who(self): + if self.user: + return self.user.get_full_name() + return self.user_email + + def __unicode__(self): + return u'%s from %s on %s' % (self.pkgbase, self.who(), self.created) + class PackageGroup(models.Model): ''' Represents a group a package is in. There is no actual group entity, @@ -229,17 +253,8 @@ class Replacement(models.Model): ordering = ['name'] -def remove_inactive_maintainers(sender, instance, created, **kwargs): - # instance is an auth.models.User; we want to remove any existing - # maintainer relations if the user is no longer active - if not instance.is_active: - maint_relations = PackageRelation.objects.filter(user=instance, - type=PackageRelation.MAINTAINER) - maint_relations.delete() - -post_save.connect(remove_inactive_maintainers, sender=User, - dispatch_uid="packages.models") -for sender in (PackageRelation, SignoffSpecification, Signoff): +# hook up some signals +for sender in (PackageRelation, SignoffSpecification, Signoff, FlagRequest): pre_save.connect(set_created_field, sender=sender, dispatch_uid="packages.models") diff --git a/packages/views/flag.py b/packages/views/flag.py index 5db2ea69..2f5c9933 100644 --- a/packages/views/flag.py +++ b/packages/views/flag.py @@ -9,6 +9,7 @@ from django.template import loader, Context from django.views.generic.simple import direct_to_template from django.views.decorators.cache import never_cache +from ..models import FlagRequest from main.models import Package @@ -17,7 +18,7 @@ def flaghelp(request): class FlagForm(forms.Form): email = forms.EmailField(label='* E-mail Address') - usermessage = forms.CharField(label='Message To Dev', + message = forms.CharField(label='Message To Dev', widget=forms.Textarea, required=False) # The field below is used to filter out bots that blindly fill out all # input elements @@ -47,6 +48,16 @@ def flag(request, name, repo, arch): flagged_pkgs = list(pkgs) pkgs.update(flag_date=datetime.utcnow()) + # store our flag request + flag_request = FlagRequest(user_email=form.cleaned_data['email'], + ip_address=request.META.get('REMOTE_ADDR', '127.0.0.1'), + pkgbase=pkg.pkgbase, repo=pkg.repo, + num_packages=len(flagged_pkgs), + message=form.cleaned_data['message']) + if request.user.is_authenticated(): + flag_request.user = request.user + flag_request.save() + maints = pkg.maintainers if not maints: toemail = settings.NOTIFICATIONS @@ -65,7 +76,7 @@ def flag(request, name, repo, arch): tmpl = loader.get_template('packages/outofdate.txt') ctx = Context({ 'email': form.cleaned_data['email'], - 'message': form.cleaned_data['usermessage'], + 'message': form.cleaned_data['message'], 'pkg': pkg, 'packages': flagged_pkgs, }) @@ -78,7 +89,10 @@ def flag(request, name, repo, arch): return redirect('package-flag-confirmed', name=name, repo=repo, arch=arch) else: - form = FlagForm() + initial = {} + if request.user.is_authenticated(): + initial['email'] = request.user.email + form = FlagForm(initial=initial) context = { 'package': pkg, diff --git a/public/utils.py b/public/utils.py index 30c76ac1..6566b8c4 100644 --- a/public/utils.py +++ b/public/utils.py @@ -11,6 +11,13 @@ class RecentUpdate(object): self.pkgbase = first.pkgbase self.repo = first.repo self.version = '' + self.classes = set() + + self.classes.add(self.repo.name.lower()) + if self.repo.testing: + self.classes.add('testing') + if self.repo.staging: + self.classes.add('staging') packages = sorted(packages, key=attrgetter('arch', 'pkgname')) # split the packages into two lists. we need to prefer packages diff --git a/sitestatic/archweb.css b/sitestatic/archweb.css index 7a306770..a3ed2cf1 100644 --- a/sitestatic/archweb.css +++ b/sitestatic/archweb.css @@ -481,15 +481,11 @@ h3 span.arrow { text-align: right; } - #pkg-updates span.testing, - #pkg-updates span.community-testing, - span.multilib-testing { + #pkg-updates span.testing { font-style: italic; } - #pkg-updates span.staging, - #pkg-updates span.community-staging, - span.multilib-staging { + #pkg-updates span.staging { font-style: italic; color: #ff8040; } diff --git a/templates/public/index.html b/templates/public/index.html index 2cfec9e2..dbc7c854 100644 --- a/templates/public/index.html +++ b/templates/public/index.html @@ -97,7 +97,7 @@ <table> {% for update in pkg_updates %} <tr> - <td class="pkg-name"><span class="{{ update.repo|lower }}">{{ update.pkgbase }} {{ update.version }}</span></td> + <td class="pkg-name"><span class="{{ update.classes|join:' ' }}">{{ update.pkgbase }} {{ update.version }}</span></td> <td class="pkg-arch"> {% for pkg in update.package_links %}<a href="{{ pkg.get_absolute_url }}" title="Details for {{ pkg.pkgname }} [{{ pkg.repo|lower }}]">{{ pkg.arch }}</a>{% if not forloop.last %}/{% endif %}{% endfor %} |