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 @@ 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 @@ def __unicode__(self): 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 @@ def get_target_repo_map(repos): 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-54-g00ecf 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-54-g00ecf 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-54-g00ecf 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 @@ 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 @@ def default(self, obj): 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-54-g00ecf 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 --- devel/views.py | 14 ++++++++++---- main/models.py | 8 ++++---- mirrors/utils.py | 4 ++-- packages/utils.py | 4 ++-- packages/views/__init__.py | 2 -- packages/views/signoff.py | 2 -- public/utils.py | 2 +- todolists/views.py | 2 -- 8 files changed, 19 insertions(+), 19 deletions(-) (limited to 'packages') diff --git a/devel/views.py b/devel/views.py index 2e62200e..35918d66 100644 --- a/devel/views.py +++ b/devel/views.py @@ -13,6 +13,7 @@ from django.template.defaultfilters import filesizeformat 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 main.models import Package, PackageDepend, PackageFile, TodolistPkg from main.models import Arch, Repo @@ -27,9 +28,9 @@ import pytz import random from string import ascii_letters, digits +import time @login_required -@never_cache def index(request): '''the developer dashboard''' if(request.user.is_authenticated()): @@ -80,7 +81,6 @@ def index(request): return direct_to_template(request, 'devel/index.html', page_dict) @login_required -@never_cache def clock(request): devs = User.objects.filter(is_active=True).order_by( 'first_name', 'last_name').select_related('userprofile') @@ -98,7 +98,14 @@ def clock(request): 'utc_now': utc_now, } - return direct_to_template(request, 'devel/clock.html', page_dict) + response = direct_to_template(request, 'devel/clock.html', page_dict) + if not response.has_header('Expires'): + # why this works only with the non-UTC date I have no idea... + expire_time = now.replace(minute=utc_now.minute + 1, + second=0, microsecond=0) + expire_time = time.mktime(expire_time.timetuple()) + response['Expires'] = http_date(expire_time) + return response class ProfileForm(forms.Form): email = forms.EmailField(label='Private email (not shown publicly):', @@ -342,7 +349,6 @@ def inner_save(): return direct_to_template(request, 'general_form.html', context) @user_passes_test(lambda u: u.is_superuser) -@never_cache def admin_log(request, username=None): user = None if username: diff --git a/main/models.py b/main/models.py index c54e2972..d72f2c05 100644 --- a/main/models.py +++ b/main/models.py @@ -201,14 +201,14 @@ def maintainers(self): def maintainers(self, maintainers): self._maintainers = maintainers - @cache_function(300) + @cache_function(1800) def applicable_arches(self): '''The list of (this arch) + (available agnostic arches).''' arches = set(Arch.objects.filter(agnostic=True)) arches.add(self.arch) return list(arches) - @cache_function(300) + @cache_function(119) def get_requiredby(self): """ Returns a list of package objects. An attempt will be made to keep this @@ -254,7 +254,7 @@ def get_requiredby(self): trimmed.append(dep) return trimmed - @cache_function(300) + @cache_function(121) def get_depends(self): """ Returns a list of dicts. Each dict contains ('dep', 'pkg', and @@ -279,7 +279,7 @@ def get_depends(self): deps.append({'dep': dep, 'pkg': pkg, 'providers': providers}) return deps - @cache_function(300) + @cache_function(125) def base_package(self): """ Locate the base package for this package. It may be this very package, diff --git a/mirrors/utils.py b/mirrors/utils.py index 686ec581..f05ffc77 100644 --- a/mirrors/utils.py +++ b/mirrors/utils.py @@ -26,7 +26,7 @@ def annotate_url(url, delays): url.delay = None url.score = None -@cache_function(300) +@cache_function(123) def get_mirror_statuses(cutoff=default_cutoff): cutoff_time = datetime.datetime.utcnow() - cutoff protocols = list(MirrorProtocol.objects.filter(is_download=True)) @@ -80,7 +80,7 @@ def get_mirror_statuses(cutoff=default_cutoff): 'urls': urls, } -@cache_function(300) +@cache_function(117) def get_mirror_errors(cutoff=default_cutoff): cutoff_time = datetime.datetime.utcnow() - cutoff errors = MirrorLog.objects.filter( 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 .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 @@ def __cmp__(self, other): 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.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 @@ 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 @@ def default(self, obj): 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 = { diff --git a/public/utils.py b/public/utils.py index 6566b8c4..a40c9b53 100644 --- a/public/utils.py +++ b/public/utils.py @@ -49,7 +49,7 @@ def package_links(self): if package.arch not in arches and not arches.add(package.arch): yield PackageStandin(package) -@cache_function(300) +@cache_function(62) def get_recent_updates(number=15): # This is a bit of magic. We are going to show 15 on the front page, but we # want to try and eliminate cross-architecture wasted space. Pull enough diff --git a/todolists/views.py b/todolists/views.py index d413ca47..e5cc0823 100644 --- a/todolists/views.py +++ b/todolists/views.py @@ -47,7 +47,6 @@ def flag(request, list_id, pkg_id): return redirect(todolist) @login_required -@never_cache def view(request, list_id): todolist = get_object_or_404(Todolist, id=list_id) svn_roots = Repo.objects.order_by().values_list( @@ -71,7 +70,6 @@ def list_pkgbases(request, list_id, svn_root): mimetype='text/plain') @login_required -@never_cache def todolist_list(request): lists = get_annotated_todolists() return direct_to_template(request, 'todolists/list.html', {'lists': lists}) -- cgit v1.2.3-54-g00ecf 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.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-54-g00ecf