From ecfcdfda941ef0c991300c6eb25fe336c3fd9cbe Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 7 Apr 2011 15:13:37 -0500 Subject: Select related needed objects when pulling package details Signed-off-by: Dan McGee --- packages/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/views.py b/packages/views.py index 263165fd..2f614e34 100644 --- a/packages/views.py +++ b/packages/views.py @@ -84,7 +84,8 @@ def update(request): def details(request, name='', repo='', arch=''): if all([name, repo, arch]): try: - pkg = Package.objects.get(pkgname=name, + pkg = Package.objects.select_related( + 'arch', 'repo', 'packager').get(pkgname=name, repo__name__iexact=repo, arch__name=arch) return direct_to_template(request, 'packages/details.html', {'pkg': pkg, }) -- cgit v1.2.3-2-g168b From 01db07bad844e17e084f650b6732647f77a91c5c Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 7 Apr 2011 15:39:53 -0500 Subject: Use UTC datetime objects everywhere Rather than the twisted mix of local times and UTC times we currently have. Signed-off-by: Dan McGee --- packages/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/views.py b/packages/views.py index 2f614e34..1587563b 100644 --- a/packages/views.py +++ b/packages/views.py @@ -371,7 +371,7 @@ def flag(request, name, repo, arch): # find all packages from (hopefully) the same PKGBUILD pkgs = Package.objects.filter( pkgbase=pkg.pkgbase, repo__testing=pkg.repo.testing) - pkgs.update(flag_date=datetime.now()) + pkgs.update(flag_date=datetime.utcnow()) maints = pkg.maintainers if not maints: -- cgit v1.2.3-2-g168b From 7a7d232c1b37ecedaaf7352cc11f7547f2d0f3e8 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 15 Apr 2011 08:05:26 -0500 Subject: Remove old package search/ URLs Signed-off-by: Dan McGee --- packages/urls.py | 4 ---- 1 file changed, 4 deletions(-) (limited to 'packages') diff --git a/packages/urls.py b/packages/urls.py index 638a370a..bfe9f76c 100644 --- a/packages/urls.py +++ b/packages/urls.py @@ -17,10 +17,6 @@ urlpatterns = patterns('packages.views', 'signoff_package'), (r'^update/$', 'update'), - # Preference is for the non-search url below, but search is kept - # because other projects link to it - (r'^search/$', 'search'), - (r'^search/(?P\d+)/$', 'search'), (r'^$', 'search'), (r'^(?P\d+)/$', 'search'), -- cgit v1.2.3-2-g168b From 9fd0995aa5567bc3b2df939cebb02cc6efeaa3b6 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 16 Apr 2011 09:34:31 -0500 Subject: Only include known values in generated search query Signed-off-by: Dan McGee --- packages/views.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/views.py b/packages/views.py index 1587563b..73692d37 100644 --- a/packages/views.py +++ b/packages/views.py @@ -18,6 +18,7 @@ from django.views.generic.simple import direct_to_template from datetime import datetime import string +from urllib import urlencode from main.models import Package, PackageFile from main.models import Arch, Repo, Signoff @@ -108,8 +109,14 @@ def details(request, name='', repo='', arch=''): return direct_to_template(request, 'packages/packages_list.html', context) else: - return redirect("/packages/?arch=%s&repo=%s&q=%s" % ( - arch.lower(), repo.title(), name)) + pkg_data = [ + ('arch', arch.lower()), + ('repo', repo.lower()), + ('q', name), + ] + # only include non-blank values in the query we generate + pkg_data = [(x, y) for x, y in pkg_data if y] + return redirect("/packages/?%s" % urlencode(pkg_data)) def groups(request, arch=None): arches = [] -- cgit v1.2.3-2-g168b From 43964627a31bbf7e583a3aeb0ab6bc5a5a108396 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 18 Apr 2011 13:48:44 -0500 Subject: Update out of date flag screen and email Now that multiple packages get marked out of date whenever this form is processed, have the page and email itself reflect this fact. Signed-off-by: Dan McGee --- packages/urls.py | 1 + packages/views.py | 37 ++++++++++++++++++++++++++++--------- 2 files changed, 29 insertions(+), 9 deletions(-) (limited to 'packages') diff --git a/packages/urls.py b/packages/urls.py index bfe9f76c..e0362fa2 100644 --- a/packages/urls.py +++ b/packages/urls.py @@ -5,6 +5,7 @@ package_patterns = patterns('packages.views', (r'^files/$', 'files'), (r'^maintainer/$', 'getmaintainer'), (r'^flag/$', 'flag'), + (r'^flag/done/$', 'flag_confirmed', {}, 'package-flag-confirmed'), (r'^unflag/$', 'unflag'), (r'^unflag/all/$', 'unflag_all'), (r'^download/$', 'download'), diff --git a/packages/views.py b/packages/views.py index 73692d37..bcb66413 100644 --- a/packages/views.py +++ b/packages/views.py @@ -367,17 +367,20 @@ class FlagForm(forms.Form): def flag(request, name, repo, arch): pkg = get_object_or_404(Package, pkgname=name, repo__name__iexact=repo, arch__name=arch) - context = {'pkg': pkg} if pkg.flag_date is not None: # already flagged. do nothing. return direct_to_template(request, 'packages/flagged.html', context) + # find all packages from (hopefully) the same PKGBUILD + pkgs = Package.objects.select_related('arch', 'repo').filter( + pkgbase=pkg.pkgbase, flag_date__isnull=True, + repo__testing=pkg.repo.testing).order_by( + 'pkgname', 'repo__name', 'arch__name') if request.POST: form = FlagForm(request.POST) if form.is_valid() and form.cleaned_data['website'] == '': - # find all packages from (hopefully) the same PKGBUILD - pkgs = Package.objects.filter( - pkgbase=pkg.pkgbase, repo__testing=pkg.repo.testing) + # save the package list for later use + flagged_pkgs = list(pkgs) pkgs.update(flag_date=datetime.utcnow()) maints = pkg.maintainers @@ -394,13 +397,13 @@ def flag(request, name, repo, arch): toemail.append(maint.email) if toemail: - # send notification email to the maintainer + # send notification email to the maintainers t = loader.get_template('packages/outofdate.txt') c = Context({ 'email': form.cleaned_data['email'], 'message': form.cleaned_data['usermessage'], 'pkg': pkg, - 'weburl': pkg.get_full_url(), + 'packages': flagged_pkgs, }) send_mail(subject, t.render(c), @@ -408,14 +411,30 @@ def flag(request, name, repo, arch): toemail, fail_silently=True) - context['confirmed'] = True + return redirect('package-flag-confirmed', name=name, repo=repo, + arch=arch) else: form = FlagForm() - context['form'] = form - + context = { + 'package': pkg, + 'packages': pkgs, + 'form': form + } return direct_to_template(request, 'packages/flag.html', context) +def flag_confirmed(request, name, repo, arch): + pkg = get_object_or_404(Package, + pkgname=name, repo__name__iexact=repo, arch__name=arch) + pkgs = Package.objects.select_related('arch', 'repo').filter( + pkgbase=pkg.pkgbase, flag_date=pkg.flag_date, + repo__testing=pkg.repo.testing).order_by( + 'pkgname', 'repo__name', 'arch__name') + + context = {'package': pkg, 'packages': pkgs} + + return direct_to_template(request, 'packages/flag_confirmed.html', context) + def download(request, name, repo, arch): pkg = get_object_or_404(Package, pkgname=name, repo__name__iexact=repo, arch__name=arch) -- cgit v1.2.3-2-g168b From 08ce9c5cd9a5d2dc0c15ee8c88ce7b78748339e5 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 18 Apr 2011 15:19:24 -0500 Subject: packages: pylint suggested cleanups Signed-off-by: Dan McGee --- packages/views.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'packages') diff --git a/packages/views.py b/packages/views.py index bcb66413..59c685bd 100644 --- a/packages/views.py +++ b/packages/views.py @@ -171,7 +171,7 @@ class LimitTypedChoiceField(forms.TypedChoiceField): try: coerce_limit_value(value) return True - except ValueError, TypeError: + except (ValueError, TypeError): return False class PackageSearchForm(forms.Form): @@ -226,7 +226,7 @@ def search(request, page=None): packages = packages.filter(pkgbase__in=inner_q) if form.cleaned_data['flagged'] == 'Flagged': - packages=packages.filter(flag_date__isnull=False) + packages = packages.filter(flag_date__isnull=False) elif form.cleaned_data['flagged'] == 'Not Flagged': packages = packages.filter(flag_date__isnull=True) @@ -369,7 +369,7 @@ def flag(request, name, repo, arch): pkgname=name, repo__name__iexact=repo, arch__name=arch) if pkg.flag_date is not None: # already flagged. do nothing. - return direct_to_template(request, 'packages/flagged.html', context) + return direct_to_template(request, 'packages/flagged.html', {'pkg': pkg}) # find all packages from (hopefully) the same PKGBUILD pkgs = Package.objects.select_related('arch', 'repo').filter( pkgbase=pkg.pkgbase, flag_date__isnull=True, @@ -445,13 +445,13 @@ def download(request, name, repo, arch): if pkg.arch.agnostic: # grab the first non-any arch to fake the download path arch = Arch.objects.exclude(agnostic=True)[0].name - details = { + values = { 'host': mirrorurl.url, 'arch': arch, 'repo': pkg.repo.name.lower(), 'file': pkg.filename, } - url = string.Template('${host}${repo}/os/${arch}/${file}').substitute(details) + url = string.Template('${host}${repo}/os/${arch}/${file}').substitute(values) return redirect(url) def arch_differences(request): -- cgit v1.2.3-2-g168b From f1f01ecf0216441dd66f3bc6afc14fe104de291f Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 18 Apr 2011 23:26:10 -0500 Subject: Reimplement links code as template tags These were starting to get a bit too much inside the model itself, and they don't really belong there as they are view layer concerns anyway. Signed-off-by: Dan McGee --- packages/templatetags/package_extras.py | 37 +++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/templatetags/package_extras.py b/packages/templatetags/package_extras.py index dd5b9347..e089b723 100644 --- a/packages/templatetags/package_extras.py +++ b/packages/templatetags/package_extras.py @@ -1,4 +1,4 @@ -import urllib +from urllib import urlencode, quote as urlquote try: from urlparse import parse_qs except ImportError: @@ -22,7 +22,7 @@ class BuildQueryStringNode(template.Node): qs['sort'] = ['-' + self.sortfield] else: qs['sort'] = [self.sortfield] - return urllib.urlencode(qs, True) + return urlencode(qs, True) @register.tag(name='buildsortqs') def do_buildsortqs(parser, token): @@ -48,4 +48,37 @@ def userpkgs(user): ) return '' + +def svn_link(package, svnpath): + '''Helper function for the two real SVN link methods.''' + parts = (package.repo.svn_root, package.pkgbase, svnpath) + linkbase = "http://projects.archlinux.org/svntogit/%s.git/tree/%s/%s/" + return linkbase % tuple(urlquote(part) for part in parts) + +@register.simple_tag +def svn_arch(package): + repo = package.repo.name.lower() + return svn_link(package, "repos/%s-%s" % (repo, package.arch.name)) + +@register.simple_tag +def svn_trunk(package): + return svn_link(package, "trunk") + +@register.simple_tag +def bugs_list(package): + data = { + 'project': package.repo.bugs_project, + 'string': package.pkgname, + } + return "https://bugs.archlinux.org/?%s" % urlencode(data) + +@register.simple_tag +def bug_report(package): + data = { + 'project': package.repo.bugs_project, + 'product_category': package.repo.bugs_category, + 'item_summary': '[%s]' % package.pkgname, + } + return "https://bugs.archlinux.org/newtask?%s" % urlencode(data) + # vim: set ts=4 sw=4 et: -- cgit v1.2.3-2-g168b From 7cab8ae9f807deff494a9efad1a1747cda2ba0f0 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 3 May 2011 13:45:43 -0500 Subject: Never cache the stale relations page Signed-off-by: Dan McGee --- packages/views.py | 1 + 1 file changed, 1 insertion(+) (limited to 'packages') diff --git a/packages/views.py b/packages/views.py index 59c685bd..23797f71 100644 --- a/packages/views.py +++ b/packages/views.py @@ -467,6 +467,7 @@ 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') -- cgit v1.2.3-2-g168b From ef9faf4414edd013755431fb2e78d9e46d448cb8 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 3 May 2011 14:41:00 -0500 Subject: Add a created date to package relations Signed-off-by: Dan McGee --- ...0007_auto__add_field_packagerelation_created.py | 135 +++++++++++++++++++++ packages/models.py | 13 +- 2 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 packages/migrations/0007_auto__add_field_packagerelation_created.py (limited to 'packages') diff --git a/packages/migrations/0007_auto__add_field_packagerelation_created.py b/packages/migrations/0007_auto__add_field_packagerelation_created.py new file mode 100644 index 00000000..37321fdb --- /dev/null +++ b/packages/migrations/0007_auto__add_field_packagerelation_created.py @@ -0,0 +1,135 @@ +# encoding: 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): + db.add_column('packages_packagerelation', 'created', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.utcnow()), keep_default=False) + + def backwards(self, orm): + db.delete_column('packages_packagerelation', 'created') + + 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',)", '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': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}), + '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': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}), + 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), + 'packager_str': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'pkgname': ('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', [], {'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.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'}), + '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'}) + } + } + + complete_apps = ['packages'] diff --git a/packages/models.py b/packages/models.py index 79e8abca..a950bddb 100644 --- a/packages/models.py +++ b/packages/models.py @@ -1,5 +1,7 @@ +from datetime import datetime + from django.db import models -from django.db.models.signals import post_save +from django.db.models.signals import pre_save, post_save from django.contrib.auth.models import User class PackageRelation(models.Model): @@ -18,6 +20,7 @@ class PackageRelation(models.Model): pkgbase = models.CharField(max_length=255) user = models.ForeignKey(User, related_name="package_relations") type = models.PositiveIntegerField(choices=TYPE_CHOICES, default=MAINTAINER) + created = models.DateTimeField(editable=False) def get_associated_packages(self): # TODO: delayed import to avoid circular reference @@ -109,7 +112,15 @@ def remove_inactive_maintainers(sender, instance, created, **kwargs): type=PackageRelation.MAINTAINER) maint_relations.delete() +def set_created_field(sender, **kwargs): + # We use this same callback for both Isos and Tests + obj = kwargs['instance'] + if not obj.created: + obj.created = datetime.utcnow() + post_save.connect(remove_inactive_maintainers, sender=User, dispatch_uid="packages.models") +pre_save.connect(set_created_field, sender=PackageRelation, + dispatch_uid="packages.models") # vim: set ts=4 sw=4 et: -- cgit v1.2.3-2-g168b