From a60801bb7dbc18080e7f6106bcf9c707d2801c9d Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 11 Dec 2011 19:52:27 -0600 Subject: PyLint suggested cleanups Signed-off-by: Dan McGee --- packages/management/commands/populate_signoffs.py | 1 - packages/models.py | 5 ++++- packages/templatetags/package_extras.py | 5 +++-- packages/utils.py | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) (limited to 'packages') diff --git a/packages/management/commands/populate_signoffs.py b/packages/management/commands/populate_signoffs.py index 42496e9d..97ba4146 100644 --- a/packages/management/commands/populate_signoffs.py +++ b/packages/management/commands/populate_signoffs.py @@ -15,7 +15,6 @@ import sys from xml.etree.ElementTree import XML from django.conf import settings -from django.contrib.auth.models import User from django.core.management.base import NoArgsCommand from ...models import SignoffSpecification diff --git a/packages/models.py b/packages/models.py index 77cade68..17843891 100644 --- a/packages/models.py +++ b/packages/models.py @@ -1,7 +1,7 @@ from collections import namedtuple from django.db import models -from django.db.models.signals import pre_save, post_save +from django.db.models.signals import pre_save from django.contrib.auth.models import User from main.models import Arch, Repo @@ -167,6 +167,9 @@ class Signoff(models.Model): class FlagRequest(models.Model): + ''' + A notification the package is out-of-date submitted through the web site. + ''' user = models.ForeignKey(User, blank=True, null=True) user_email = models.EmailField('email address') created = models.DateTimeField(editable=False) diff --git a/packages/templatetags/package_extras.py b/packages/templatetags/package_extras.py index 3eb7578d..47b2fecf 100644 --- a/packages/templatetags/package_extras.py +++ b/packages/templatetags/package_extras.py @@ -27,6 +27,7 @@ def url_unquote(original_url): class BuildQueryStringNode(template.Node): def __init__(self, sortfield): self.sortfield = sortfield + super(BuildQueryStringNode, self).__init__() def render(self, context): qs = parse_qs(context['current_query']) @@ -53,8 +54,8 @@ def do_buildsortqs(parser, token): @register.simple_tag def pkg_details_link(pkg): - template = '%s' - return template % (pkg.get_absolute_url(), pkg.pkgname, pkg.pkgname) + link = '%s' + return link % (pkg.get_absolute_url(), pkg.pkgname, pkg.pkgname) @register.simple_tag def multi_pkg_details(pkgs): diff --git a/packages/utils.py b/packages/utils.py index 5703db3b..d4a9d8f6 100644 --- a/packages/utils.py +++ b/packages/utils.py @@ -377,7 +377,7 @@ SELECT DISTINCT p1.pkgbase, r.name AND r.testing = %s AND p2.repo_id IN ( """ - sql += ','.join(['%s' for r in repos]) + sql += ','.join(['%s' for _ in repos]) sql += ")" params = [False, False] -- cgit v1.2.3-2-g168b From 78f23956e090d8e6967467030407738ca6c1d276 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 12 Dec 2011 07:03:36 -0600 Subject: Add signoff model admin interface Signed-off-by: Dan McGee --- packages/admin.py | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'packages') diff --git a/packages/admin.py b/packages/admin.py index 14fa8960..44aa22f3 100644 --- a/packages/admin.py +++ b/packages/admin.py @@ -1,11 +1,12 @@ from django.contrib import admin -from .models import PackageRelation, FlagRequest +from .models import PackageRelation, FlagRequest, Signoff, SignoffSpecification class PackageRelationAdmin(admin.ModelAdmin): - list_display = ('user', 'pkgbase', 'type', 'created') + list_display = ('pkgbase', 'user', 'type', 'created') list_filter = ('type', 'user') - search_fields = ('user__username', 'pkgbase') + search_fields = ('pkgbase', 'user__username') + ordering = ('pkgbase', 'user') date_hierarchy = 'created' class FlagRequestAdmin(admin.ModelAdmin): @@ -13,9 +14,30 @@ class FlagRequestAdmin(admin.ModelAdmin): 'message') list_filter = ('is_spam', 'is_legitimate') search_fields = ('pkgbase', 'user_email', 'message') + ordering = ('-created',) date_hierarchy = 'created' + +class SignoffAdmin(admin.ModelAdmin): + list_display = ('pkgbase', 'pkgver', 'pkgrel', 'arch', 'repo', + 'user', 'created', 'revoked') + list_filter = ('arch', 'repo', 'user') + search_fields = ('pkgbase', 'user__username') + ordering = ('-created',) + date_hierarchy = 'created' + +class SignoffSpecificationAdmin(admin.ModelAdmin): + list_display = ('pkgbase', 'pkgver', 'pkgrel', 'arch', 'repo', + 'user', 'created', 'comments') + list_filter = ('arch', 'repo', 'user') + search_fields = ('pkgbase', 'user__username') + ordering = ('-created',) + date_hierarchy = 'created' + + admin.site.register(PackageRelation, PackageRelationAdmin) admin.site.register(FlagRequest, FlagRequestAdmin) +admin.site.register(Signoff, SignoffAdmin) +admin.site.register(SignoffSpecification, SignoffSpecificationAdmin) # vim: set ts=4 sw=4 et: -- cgit v1.2.3-2-g168b From 99eada17224b54799e7c2331a2b88dee76420107 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 12 Dec 2011 09:58:46 -0600 Subject: Use full version in signoff admin list view Signed-off-by: Dan McGee --- packages/admin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/admin.py b/packages/admin.py index 44aa22f3..6d85569d 100644 --- a/packages/admin.py +++ b/packages/admin.py @@ -19,7 +19,7 @@ class FlagRequestAdmin(admin.ModelAdmin): class SignoffAdmin(admin.ModelAdmin): - list_display = ('pkgbase', 'pkgver', 'pkgrel', 'arch', 'repo', + list_display = ('pkgbase', 'full_version', 'arch', 'repo', 'user', 'created', 'revoked') list_filter = ('arch', 'repo', 'user') search_fields = ('pkgbase', 'user__username') @@ -27,7 +27,7 @@ class SignoffAdmin(admin.ModelAdmin): date_hierarchy = 'created' class SignoffSpecificationAdmin(admin.ModelAdmin): - list_display = ('pkgbase', 'pkgver', 'pkgrel', 'arch', 'repo', + list_display = ('pkgbase', 'full_version', 'arch', 'repo', 'user', 'created', 'comments') list_filter = ('arch', 'repo', 'user') search_fields = ('pkgbase', 'user__username') -- cgit v1.2.3-2-g168b From 64da32a3f3312331537eb34ab704eec7ebf14221 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 3 Jan 2012 14:17:56 -0600 Subject: Add maintainer and packager data to package JSON view Signed-off-by: Dan McGee --- packages/views/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/views/__init__.py b/packages/views/__init__.py index aa7da262..9f24056a 100644 --- a/packages/views/__init__.py +++ b/packages/views/__init__.py @@ -1,5 +1,6 @@ from django.contrib import messages from django.contrib.auth.decorators import permission_required +from django.contrib.auth.models import User from django.core.serializers.json import DjangoJSONEncoder from django.http import HttpResponse, Http404 from django.shortcuts import get_object_or_404, redirect @@ -27,7 +28,8 @@ from .signoff import signoffs, signoff_package, signoff_options, signoffs_json class PackageJSONEncoder(DjangoJSONEncoder): pkg_attributes = [ 'pkgname', 'pkgbase', 'repo', 'arch', 'pkgver', 'pkgrel', 'epoch', 'pkgdesc', 'url', 'filename', 'compressed_size', - 'installed_size', 'build_date', 'last_update', 'flag_date' ] + 'installed_size', 'build_date', 'last_update', 'flag_date', + 'maintainers', 'packager' ] def default(self, obj): if hasattr(obj, '__iter__'): @@ -43,6 +45,8 @@ class PackageJSONEncoder(DjangoJSONEncoder): return obj.directory + filename if isinstance(obj, (Repo, Arch, PackageGroup)): return obj.name.lower() + elif isinstance(obj, User): + return obj.username return super(PackageJSONEncoder, self).default(obj) def opensearch(request): -- cgit v1.2.3-2-g168b From 6b16b9487a95118a6109a2c5119d430dc1192e80 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 5 Jan 2012 13:03:00 -0600 Subject: Adjust page and content caching lengths and decorators Remove never_cache from many places now that we don't actually need it since we aren't caching by default. Adjust our cache_function decorator times be shorter values, and also randomize them a bit to make cache invalidations not all line up. Signed-off-by: Dan McGee --- packages/utils.py | 4 ++-- packages/views/__init__.py | 2 -- packages/views/signoff.py | 2 -- 3 files changed, 2 insertions(+), 6 deletions(-) (limited to 'packages') diff --git a/packages/utils.py b/packages/utils.py index d4a9d8f6..2a43a08b 100644 --- a/packages/utils.py +++ b/packages/utils.py @@ -11,7 +11,7 @@ from main.utils import cache_function, groupby_preserve_order, PackageStandin from .models import (PackageGroup, PackageRelation, SignoffSpecification, Signoff, DEFAULT_SIGNOFF_SPEC) -@cache_function(300) +@cache_function(127) def get_group_info(include_arches=None): raw_groups = PackageGroup.objects.values_list( 'name', 'pkg__arch__name').order_by('name').annotate( @@ -92,7 +92,7 @@ class Difference(object): return False -@cache_function(300) +@cache_function(127) def get_differences_info(arch_a, arch_b): # This is a monster. Join packages against itself, looking for packages in # our non-'any' architectures only, and not having a corresponding package diff --git a/packages/views/__init__.py b/packages/views/__init__.py index 9f24056a..5be4833e 100644 --- a/packages/views/__init__.py +++ b/packages/views/__init__.py @@ -5,7 +5,6 @@ from django.core.serializers.json import DjangoJSONEncoder from django.http import HttpResponse, Http404 from django.shortcuts import get_object_or_404, redirect from django.utils import simplejson -from django.views.decorators.cache import never_cache from django.views.decorators.http import require_POST from django.views.decorators.vary import vary_on_headers from django.views.generic.simple import direct_to_template @@ -247,7 +246,6 @@ def arch_differences(request): return direct_to_template(request, 'packages/differences.html', context) @permission_required('main.change_package') -@never_cache def stale_relations(request): relations = PackageRelation.objects.select_related('user') pkgbases = Package.objects.all().values('pkgbase') diff --git a/packages/views/signoff.py b/packages/views/signoff.py index e57b4d9a..e3daf0dd 100644 --- a/packages/views/signoff.py +++ b/packages/views/signoff.py @@ -18,7 +18,6 @@ from ..utils import (get_signoff_groups, approved_by_signoffs, PackageSignoffGroup) @permission_required('main.change_package') -@never_cache def signoffs(request): signoff_groups = sorted(get_signoff_groups(), key=attrgetter('pkgbase')) for group in signoff_groups: @@ -178,7 +177,6 @@ class SignoffJSONEncoder(DjangoJSONEncoder): return super(SignoffJSONEncoder, self).default(obj) @permission_required('main.change_package') -@never_cache def signoffs_json(request): signoff_groups = sorted(get_signoff_groups(), key=attrgetter('pkgbase')) data = { -- cgit v1.2.3-2-g168b From b2b5c1a064d5d3c33f4c4fc119bd67cf9ca1b7ba Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 10 Jan 2012 23:31:11 -0600 Subject: Add old version string to saved flag requests This makes it easier to match up a flag request with the package state at the time of flagging, and might also help to determine if flagging actions were legit. We only store it if it is the same across all packages to be marked. Also, move the various database write activities when flagging packages into a single transaction. Signed-off-by: Dan McGee --- packages/admin.py | 4 +- .../0013_auto__add_field_flagrequest_version.py | 180 +++++++++++++++++++++ packages/models.py | 1 + packages/views/flag.py | 41 +++-- 4 files changed, 211 insertions(+), 15 deletions(-) create mode 100644 packages/migrations/0013_auto__add_field_flagrequest_version.py (limited to 'packages') diff --git a/packages/admin.py b/packages/admin.py index 6d85569d..4c170247 100644 --- a/packages/admin.py +++ b/packages/admin.py @@ -10,8 +10,8 @@ class PackageRelationAdmin(admin.ModelAdmin): date_hierarchy = 'created' class FlagRequestAdmin(admin.ModelAdmin): - list_display = ('pkgbase', 'created', 'who', 'is_spam', 'is_legitimate', - 'message') + list_display = ('pkgbase', 'version', 'created', 'who', 'is_spam', + 'is_legitimate', 'message') list_filter = ('is_spam', 'is_legitimate') search_fields = ('pkgbase', 'user_email', 'message') ordering = ('-created',) diff --git a/packages/migrations/0013_auto__add_field_flagrequest_version.py b/packages/migrations/0013_auto__add_field_flagrequest_version.py new file mode 100644 index 00000000..ab33d5b3 --- /dev/null +++ b/packages/migrations/0013_auto__add_field_flagrequest_version.py @@ -0,0 +1,180 @@ +# 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): + db.add_column('packages_flagrequest', 'version', self.gf('django.db.models.fields.CharField')(default='', max_length=255), keep_default=False) + + def backwards(self, orm): + db.delete_column('packages_flagrequest', 'version') + + 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'}), + 'version': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}) + }, + '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 17843891..f63d6db0 100644 --- a/packages/models.py +++ b/packages/models.py @@ -175,6 +175,7 @@ class FlagRequest(models.Model): created = models.DateTimeField(editable=False) ip_address = models.IPAddressField('IP address') pkgbase = models.CharField(max_length=255, db_index=True) + version = models.CharField(max_length=255, default='') repo = models.ForeignKey(Repo) num_packages = models.PositiveIntegerField('number of packages', default=1) message = models.TextField('message to developer', blank=True) diff --git a/packages/views/flag.py b/packages/views/flag.py index 4132f9a7..4ee37f6f 100644 --- a/packages/views/flag.py +++ b/packages/views/flag.py @@ -4,6 +4,7 @@ from django import forms from django.conf import settings from django.contrib.auth.decorators import permission_required from django.core.mail import send_mail +from django.db import transaction from django.shortcuts import get_object_or_404, redirect from django.template import loader, Context from django.views.generic.simple import direct_to_template @@ -46,17 +47,31 @@ def flag(request, name, repo, arch): if form.is_valid() and form.cleaned_data['website'] == '': # save the package list for later use 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() + + # find a common version if there is one available to store + versions = set(pkg.full_version for pkg in flagged_pkgs) + if len(versions) == 1: + version = versions.pop() + else: + version = '' + + email = form.cleaned_data['email'] + message = form.cleaned_data['message'] + ip_addr = request.META.get('REMOTE_ADDR') + + @transaction.commit_on_success + def perform_updates(): + pkgs.update(flag_date=datetime.utcnow()) + # store our flag request + flag_request = FlagRequest(user_email=email, message=message, + ip_address=ip_addr, pkgbase=pkg.pkgbase, + version=version, repo=pkg.repo, + num_packages=len(flagged_pkgs)) + if request.user.is_authenticated(): + flag_request.user = request.user + flag_request.save() + + perform_updates() maints = pkg.maintainers if not maints: @@ -75,8 +90,8 @@ def flag(request, name, repo, arch): # send notification email to the maintainers tmpl = loader.get_template('packages/outofdate.txt') ctx = Context({ - 'email': form.cleaned_data['email'], - 'message': form.cleaned_data['message'], + 'email': email, + 'message': message, 'pkg': pkg, 'packages': flagged_pkgs, }) -- cgit v1.2.3-2-g168b