From 376ce4a69e016d13eff28589a5caa627bf7c451b Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 7 Feb 2011 12:48:12 -0600 Subject: Clean up Package related objects code Main change is just to move groups from the default packagegroup_set location to a related_name of groups. Also refer to the Package class directly rather than by text string if we have it available. Signed-off-by: Dan McGee --- packages/models.py | 5 ++++- packages/views.py | 3 +-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'packages') diff --git a/packages/models.py b/packages/models.py index 70ac4fe5..c217a692 100644 --- a/packages/models.py +++ b/packages/models.py @@ -25,7 +25,10 @@ class PackageGroup(models.Model): Represents a group a package is in. There is no actual group entity, only names that link to given packages. ''' - pkg = models.ForeignKey('main.Package') + pkg = models.ForeignKey('main.Package', related_name='groups') name = models.CharField(max_length=255) + def __unicode__(self): + return self.name + # vim: set ts=4 sw=4 et: diff --git a/packages/views.py b/packages/views.py index 4f7c3b93..9c34db0c 100644 --- a/packages/views.py +++ b/packages/views.py @@ -104,8 +104,7 @@ def group_details(request, arch, name): arch = get_object_or_404(Arch, name=arch) arches = [ arch ] arches.extend(Arch.objects.filter(agnostic=True)) - pkgs = Package.objects.filter(packagegroup__name=name, - arch__in=arches) + pkgs = Package.objects.filter(groups__name=name, arch__in=arches) pkgs = pkgs.order_by('pkgname') if len(pkgs) == 0: raise Http404 -- cgit v1.2.3-2-g168b From 4444f25d5cd9a9e1cb310a2d9c0b6b1ec1f55789 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 7 Feb 2011 13:45:05 -0600 Subject: Move license to a related model This allows us to store multiple licenses per package in a more elegant fashion, and will later allow us to search and filter on this information. Signed-off-by: Dan McGee --- packages/migrations/0004_auto__add_license.py | 118 +++++++++++++++++++++++++ packages/migrations/0005_move_license_data.py | 120 ++++++++++++++++++++++++++ packages/models.py | 10 +++ 3 files changed, 248 insertions(+) create mode 100644 packages/migrations/0004_auto__add_license.py create mode 100644 packages/migrations/0005_move_license_data.py (limited to 'packages') diff --git a/packages/migrations/0004_auto__add_license.py b/packages/migrations/0004_auto__add_license.py new file mode 100644 index 00000000..001440fe --- /dev/null +++ b/packages/migrations/0004_auto__add_license.py @@ -0,0 +1,118 @@ +# 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): + # Adding model 'License' + db.create_table('packages_license', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('pkg', self.gf('django.db.models.fields.related.ForeignKey')(related_name='licenses', to=orm['main.Package'])), + ('name', self.gf('django.db.models.fields.CharField')(max_length=255)), + )) + db.send_create_signal('packages', ['License']) + + + def backwards(self, orm): + # Deleting model 'License' + db.delete_table('packages_license') + + + 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'}), + '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'}), + 'license': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': '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_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'}), + 'svn_root': ('django.db.models.fields.CharField', [], {'max_length': '64'}), + 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + }, + 'packages.license': { + 'Meta': {'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'}, + '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']"}) + } + } + + complete_apps = ['packages'] diff --git a/packages/migrations/0005_move_license_data.py b/packages/migrations/0005_move_license_data.py new file mode 100644 index 00000000..1c1e689a --- /dev/null +++ b/packages/migrations/0005_move_license_data.py @@ -0,0 +1,120 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models + +class Migration(DataMigration): + + depends_on = ( + # the last structural change to the package model + ('main', '0026_auto__add_field_package_packager_str__add_field_package_packager'), + ) + + def forwards(self, orm): + "Migrate the flat license text to a seperate relation." + for pkg in orm['main.Package'].objects.all(): + licenses = pkg.license.split(u', ') + for license in licenses: + pkg.licenses.create(name=license) + + def backwards(self, orm): + for pkg in orm['main.Package'].objects.all(): + pkg.license = u', '.join([l.name for l in pkg.licenses.all()]) + pkg.save() + + 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'}), + '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'}), + 'license': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': '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_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'}), + 'svn_root': ('django.db.models.fields.CharField', [], {'max_length': '64'}), + 'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + }, + 'packages.license': { + 'Meta': {'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'}, + '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']"}) + } + } + + complete_apps = ['packages'] diff --git a/packages/models.py b/packages/models.py index c217a692..5aa213d1 100644 --- a/packages/models.py +++ b/packages/models.py @@ -31,4 +31,14 @@ class PackageGroup(models.Model): def __unicode__(self): return self.name +class License(models.Model): + pkg = models.ForeignKey('main.Package', related_name='licenses') + name = models.CharField(max_length=255) + + def __unicode__(self): + return self.name + + class Meta: + ordering = ['name'] + # vim: set ts=4 sw=4 et: -- cgit v1.2.3-2-g168b From ed4eca37fc7680a7f88d213af68b740f046aad17 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 18 Feb 2011 16:25:53 -0600 Subject: Add unicode methods for packages models Signed-off-by: Dan McGee --- packages/models.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'packages') diff --git a/packages/models.py b/packages/models.py index 5aa213d1..bc36f787 100644 --- a/packages/models.py +++ b/packages/models.py @@ -17,6 +17,11 @@ 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) + + def __unicode__(self): + return "%s: %s (%s)" % ( + self.pkgbase, self.user, self.get_type_display()) + class Meta: unique_together = (('pkgbase', 'user', 'type'),) @@ -29,7 +34,7 @@ class PackageGroup(models.Model): name = models.CharField(max_length=255) def __unicode__(self): - return self.name + return "%s: %s" % (name, pkg) class License(models.Model): pkg = models.ForeignKey('main.Package', related_name='licenses') -- cgit v1.2.3-2-g168b From eb97b0400b7323540896b98ac0eddbd7b4373241 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 18 Feb 2011 16:26:27 -0600 Subject: Add a PackageRelation admin Signed-off-by: Dan McGee --- packages/admin.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 packages/admin.py (limited to 'packages') diff --git a/packages/admin.py b/packages/admin.py new file mode 100644 index 00000000..3ecfdbb1 --- /dev/null +++ b/packages/admin.py @@ -0,0 +1,11 @@ +from django.contrib import admin + +from .models import PackageRelation + +class PackageRelationAdmin(admin.ModelAdmin): + list_display = ('user', 'pkgbase', 'type') + list_filter = ('type', 'user') + +admin.site.register(PackageRelation, PackageRelationAdmin) + +# vim: set ts=4 sw=4 et: -- cgit v1.2.3-2-g168b From 3fb20c942da5afece6f8717a9c3bf878e18b508a Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 18 Feb 2011 16:35:54 -0600 Subject: Remove maintainer relations if user marked inactive These users are being marked inactive because they are no longer developers; thus they should have all of their maintainer relations removed from the database. This is one of two causes of "orphan" package relation objects, the other being pkgbase values that go out of existence. Signed-off-by: Dan McGee --- packages/models.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'packages') diff --git a/packages/models.py b/packages/models.py index bc36f787..0afdee00 100644 --- a/packages/models.py +++ b/packages/models.py @@ -1,4 +1,5 @@ from django.db import models +from django.db.models.signals import post_save from django.contrib.auth.models import User class PackageRelation(models.Model): @@ -46,4 +47,15 @@ class License(models.Model): class Meta: 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") + # vim: set ts=4 sw=4 et: -- cgit v1.2.3-2-g168b From b9fdcd06222c674d5fabcf5a4ab6bc55f268c757 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 22 Feb 2011 15:29:08 -0600 Subject: Modularize URLs Make some additional URL config files that can be included so we aren't trying to do so much in the top level config. This also allows us to branch a bit more rather than go linear down the rather lengthy list. Signed-off-by: Dan McGee --- packages/urls_groups.py | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 packages/urls_groups.py (limited to 'packages') diff --git a/packages/urls_groups.py b/packages/urls_groups.py new file mode 100644 index 00000000..c561e50d --- /dev/null +++ b/packages/urls_groups.py @@ -0,0 +1,9 @@ +from django.conf.urls.defaults import patterns + +urlpatterns = patterns('packages.views', + (r'^$', 'groups', {}, 'groups-list'), + (r'^(?P[A-z0-9]+)/$', 'groups'), + (r'^(?P[A-z0-9]+)/(?P[A-z0-9\-+.]+)/$', 'group_details'), +) + +# vim: set ts=4 sw=4 et: -- cgit v1.2.3-2-g168b From 4b12255d1cf52fcc1a98c230d940d0c1d3809ad2 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 21 Dec 2010 21:34:40 -0600 Subject: Use new split package file fields everywhere 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 9c34db0c..e792175b 100644 --- a/packages/views.py +++ b/packages/views.py @@ -234,7 +234,7 @@ def search(request, page=None): def files(request, name, repo, arch): pkg = get_object_or_404(Package, pkgname=name, repo__name__iexact=repo, arch__name=arch) - fileslist = PackageFile.objects.filter(pkg=pkg).order_by('path') + fileslist = PackageFile.objects.filter(pkg=pkg).order_by('directory', 'filename') template = 'packages/files.html' if request.is_ajax(): template = 'packages/files-list.html' -- cgit v1.2.3-2-g168b From 3181e970ce9dcc4fd996499ee536e4c2454e89dd Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Wed, 23 Feb 2011 12:09:29 -0600 Subject: Add stale package relations status screen For now it is read only. Display a few tables of various ways of detecting stale package relations. These include inactive users, pkgbase values that no longer exist, and users that are listed as maintainers that don't have the proper permissions for that package anymore. Signed-off-by: Dan McGee --- packages/models.py | 10 ++++++++++ packages/urls.py | 1 + packages/utils.py | 24 +++++++++++++++++++++++- packages/views.py | 21 +++++++++++++++++++-- 4 files changed, 53 insertions(+), 3 deletions(-) (limited to 'packages') diff --git a/packages/models.py b/packages/models.py index 0afdee00..5dbdea45 100644 --- a/packages/models.py +++ b/packages/models.py @@ -19,6 +19,16 @@ class PackageRelation(models.Model): user = models.ForeignKey(User, related_name="package_relations") type = models.PositiveIntegerField(choices=TYPE_CHOICES, default=MAINTAINER) + def get_associated_packages(self): + # TODO: delayed import to avoid circular reference + from main.models import Package + return Package.objects.filter(pkgbase=self.pkgbase).select_related( + 'arch', 'repo') + + def repositories(self): + packages = self.get_associated_packages() + return sorted(set([p.repo for p in packages])) + def __unicode__(self): return "%s: %s (%s)" % ( self.pkgbase, self.user, self.get_type_display()) diff --git a/packages/urls.py b/packages/urls.py index b7ce5c74..37ce23c0 100644 --- a/packages/urls.py +++ b/packages/urls.py @@ -25,6 +25,7 @@ urlpatterns = patterns('packages.views', (r'^(?P\d+)/$', 'search'), (r'^differences/$', 'arch_differences'), + (r'^stale_relations/$', 'stale_relations'), (r'^(?P[A-z0-9\-+.]+)/$', 'details'), diff --git a/packages/utils.py b/packages/utils.py index aaec0ec4..8d9f13ab 100644 --- a/packages/utils.py +++ b/packages/utils.py @@ -5,7 +5,7 @@ from operator import itemgetter from main.models import Package from main.utils import cache_function -from .models import PackageGroup +from .models import PackageGroup, PackageRelation @cache_function(300) def get_group_info(include_arches=None): @@ -128,4 +128,26 @@ SELECT p.id, q.id differences.sort(key=lambda a: (a.repo.name, a.pkgname)) return differences +def get_wrong_permissions(): + sql = """ +SELECT DISTINCT id + FROM ( + SELECT pr.id, p.repo_id, pr.user_id + FROM packages p + JOIN packages_packagerelation pr ON p.pkgbase = pr.pkgbase + WHERE pr.type = %s + ) pkgs + WHERE pkgs.repo_id NOT IN ( + SELECT repo_id FROM user_profiles_allowed_repos ar + INNER JOIN user_profiles up ON ar.userprofile_id = up.id + WHERE up.user_id = pkgs.user_id + ) +""" + cursor = connection.cursor() + cursor.execute(sql, [PackageRelation.MAINTAINER]) + to_fetch = [row[0] for row in cursor.fetchall()] + relations = PackageRelation.objects.select_related('user').filter( + id__in=to_fetch) + return relations + # vim: set ts=4 sw=4 et: diff --git a/packages/views.py b/packages/views.py index e792175b..9a2094aa 100644 --- a/packages/views.py +++ b/packages/views.py @@ -2,7 +2,7 @@ from django import forms from django.contrib import messages from django.contrib.admin.widgets import AdminDateWidget from django.contrib.auth.models import User -from django.contrib.auth.decorators import permission_required +from django.contrib.auth.decorators import login_required, permission_required from django.conf import settings from django.core.mail import send_mail from django.db.models import Q @@ -23,7 +23,7 @@ from main.models import Arch, Repo, Signoff from main.utils import make_choice from mirrors.models import MirrorUrl from .models import PackageRelation -from .utils import get_group_info, get_differences_info +from .utils import get_group_info, get_differences_info, get_wrong_permissions def opensearch(request): if request.is_secure(): @@ -401,4 +401,21 @@ def arch_differences(request): } return direct_to_template(request, 'packages/differences.html', context) +@login_required +def stale_relations(request): + relations = PackageRelation.objects.select_related('user') + pkgbases = Package.objects.all().values('pkgbase') + + inactive_user = relations.filter(user__is_active=False) + missing_pkgbase = relations.exclude( + pkgbase__in=pkgbases).order_by('pkgbase') + wrong_permissions = get_wrong_permissions() + + context = { + 'inactive_user': inactive_user, + 'missing_pkgbase': missing_pkgbase, + 'wrong_permissions': wrong_permissions, + } + return direct_to_template(request, 'packages/stale_relations.html', context) + # vim: set ts=4 sw=4 et: -- cgit v1.2.3-2-g168b From 93bca8b0ed79afc30f6237e13dacaf32ed8cd4b3 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Wed, 23 Feb 2011 12:36:49 -0600 Subject: Allow deleting of stale package relations via status page Add a column of checkboxes to each table, enclose the whole thing in a form, and add a super-simple delete view that takes a list of IDs and removes them from the database. The delete_packagerelation permission is required to be able to delete relations. Signed-off-by: Dan McGee --- packages/urls.py | 1 + packages/views.py | 13 +++++++++++++ 2 files changed, 14 insertions(+) (limited to 'packages') diff --git a/packages/urls.py b/packages/urls.py index 37ce23c0..638a370a 100644 --- a/packages/urls.py +++ b/packages/urls.py @@ -26,6 +26,7 @@ urlpatterns = patterns('packages.views', (r'^differences/$', 'arch_differences'), (r'^stale_relations/$', 'stale_relations'), + (r'^stale_relations/update/$','stale_relations_update'), (r'^(?P[A-z0-9\-+.]+)/$', 'details'), diff --git a/packages/views.py b/packages/views.py index 9a2094aa..1ab04258 100644 --- a/packages/views.py +++ b/packages/views.py @@ -11,6 +11,7 @@ from django.shortcuts import get_object_or_404, redirect from django.template import loader, Context, RequestContext 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 import list_detail from django.views.generic.simple import direct_to_template @@ -36,6 +37,7 @@ def opensearch(request): mimetype='application/opensearchdescription+xml') @permission_required('main.change_package') +@require_POST def update(request): ids = request.POST.getlist('pkgid') count = 0 @@ -418,4 +420,15 @@ def stale_relations(request): } return direct_to_template(request, 'packages/stale_relations.html', context) +@permission_required('packages.delete_packagerelation') +@require_POST +def stale_relations_update(request): + ids = set(request.POST.getlist('relation_id')) + + if ids: + PackageRelation.objects.filter(id__in=ids).delete() + + messages.info(request, "%d package relations deleted." % len(ids)) + return redirect('/packages/stale_relations/') + # vim: set ts=4 sw=4 et: -- cgit v1.2.3-2-g168b From 3a85ead4475b8acfa236a5b1825b844d0431bbaf Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 3 Mar 2011 12:31:58 -0600 Subject: Make Arch and Repo a MultipleChoice on package search Signed-off-by: Dan McGee --- packages/views.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'packages') diff --git a/packages/views.py b/packages/views.py index 1ab04258..7c57d88a 100644 --- a/packages/views.py +++ b/packages/views.py @@ -127,8 +127,8 @@ def getmaintainer(request, name, repo, arch): return HttpResponse(str('\n'.join(names)), mimetype='text/plain') class PackageSearchForm(forms.Form): - repo = forms.ChoiceField(required=False) - arch = forms.ChoiceField(required=False) + repo = forms.MultipleChoiceField(required=False) + arch = forms.MultipleChoiceField(required=False) q = forms.CharField(required=False) maintainer = forms.ChoiceField(required=False) last_update = forms.DateField(required=False, widget=AdminDateWidget(), @@ -157,9 +157,9 @@ class PackageSearchForm(forms.Form): def __init__(self, *args, **kwargs): super(PackageSearchForm, self).__init__(*args, **kwargs) - self.fields['repo'].choices = [('', 'All')] + make_choice( + self.fields['repo'].choices = make_choice( [repo.name for repo in Repo.objects.all()]) - self.fields['arch'].choices = [('', 'All')] + make_choice( + self.fields['arch'].choices = make_choice( [arch.name for arch in Arch.objects.all()]) self.fields['q'].widget.attrs.update({"size": "30"}) maints = User.objects.filter(is_active=True).order_by('username') @@ -178,11 +178,11 @@ def search(request, page=None): if form.is_valid(): if form.cleaned_data['repo']: packages = packages.filter( - repo__name=form.cleaned_data['repo']) + repo__name__in=form.cleaned_data['repo']) if form.cleaned_data['arch']: packages = packages.filter( - arch__name=form.cleaned_data['arch']) + arch__name__in=form.cleaned_data['arch']) if form.cleaned_data['maintainer'] == 'orphan': inner_q = PackageRelation.objects.all().values('pkgbase') -- cgit v1.2.3-2-g168b From 0c368ce4661c91f77aa79f189c4be11de5d94d27 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 3 Mar 2011 14:40:32 -0600 Subject: Correct some permission decorators Signed-off-by: Dan McGee --- packages/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages') diff --git a/packages/views.py b/packages/views.py index 7c57d88a..2291c4f4 100644 --- a/packages/views.py +++ b/packages/views.py @@ -2,7 +2,7 @@ from django import forms from django.contrib import messages from django.contrib.admin.widgets import AdminDateWidget from django.contrib.auth.models import User -from django.contrib.auth.decorators import login_required, permission_required +from django.contrib.auth.decorators import permission_required from django.conf import settings from django.core.mail import send_mail from django.db.models import Q @@ -403,7 +403,7 @@ def arch_differences(request): } return direct_to_template(request, 'packages/differences.html', context) -@login_required +@permission_required('main.change_package') def stale_relations(request): relations = PackageRelation.objects.select_related('user') pkgbases = Package.objects.all().values('pkgbase') -- cgit v1.2.3-2-g168b From 9d12c0fac5c0580b30c6bf8f578a358dc22afdff Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 4 Mar 2011 12:13:29 -0600 Subject: Move new user email contents to template 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 2291c4f4..59779fe4 100644 --- a/packages/views.py +++ b/packages/views.py @@ -8,7 +8,7 @@ from django.core.mail import send_mail from django.db.models import Q from django.http import HttpResponse, Http404 from django.shortcuts import get_object_or_404, redirect -from django.template import loader, Context, RequestContext +from django.template import loader, Context from django.utils import simplejson from django.views.decorators.cache import never_cache from django.views.decorators.http import require_POST -- cgit v1.2.3-2-g168b