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 --- templates/packages/details.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'templates') diff --git a/templates/packages/details.html b/templates/packages/details.html index fcbaf083..de6b637f 100644 --- a/templates/packages/details.html +++ b/templates/packages/details.html @@ -112,7 +112,7 @@

Versions Elsewhere

{{ pkg.license }} Groups: - {% with pkg.packagegroup_set.all as groups %} + {% with pkg.groups.all as groups %} {% if groups %} {% for g in groups %} 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 --- devel/management/commands/reporead.py | 11 +- .../0039_auto__del_field_package_license.py | 157 +++++++++++++++++++++ main/models.py | 1 - packages/migrations/0004_auto__add_license.py | 118 ++++++++++++++++ packages/migrations/0005_move_license_data.py | 120 ++++++++++++++++ packages/models.py | 10 ++ templates/packages/details.html | 4 +- 7 files changed, 413 insertions(+), 8 deletions(-) create mode 100644 main/migrations/0039_auto__del_field_package_license.py create mode 100644 packages/migrations/0004_auto__add_license.py create mode 100644 packages/migrations/0005_move_license_data.py (limited to 'templates') diff --git a/devel/management/commands/reporead.py b/devel/management/commands/reporead.py index bdd0882c..9b99e0f7 100644 --- a/devel/management/commands/reporead.py +++ b/devel/management/commands/reporead.py @@ -79,14 +79,13 @@ class Pkg(object): """An interim 'container' object for holding Arch package data.""" bare = ( 'name', 'base', 'arch', 'desc', 'filename', 'md5sum', 'url', 'builddate', 'packager' ) - squash = ( 'license', ) number = ( 'csize', 'isize' ) def __init__(self, repo): self.repo = repo self.ver = None self.rel = None - for k in self.bare + self.squash + self.number: + for k in self.bare + self.number: setattr(self, k, None) def populate(self, values): @@ -94,8 +93,6 @@ def populate(self, values): # ensure we stay under our DB character limit if k in self.bare: setattr(self, k, v[0][:254]) - elif k in self.squash: - setattr(self, k, u', '.join(v)[:254]) elif k in self.number: setattr(self, k, long(v[0])) elif k == 'force': @@ -166,7 +163,6 @@ def populate_pkg(dbpkg, repopkg, force=False, timestamp=None): dbpkg.pkgver = repopkg.ver dbpkg.pkgrel = repopkg.rel dbpkg.pkgdesc = repopkg.desc - dbpkg.license = repopkg.license dbpkg.url = repopkg.url dbpkg.filename = repopkg.filename dbpkg.compressed_size = repopkg.csize @@ -208,6 +204,11 @@ def populate_pkg(dbpkg, repopkg, force=False, timestamp=None): for y in repopkg.groups: dbpkg.groups.create(name=y) + dbpkg.licenses.all().delete() + if 'license' in repopkg.__dict__: + for y in repopkg.license: + dbpkg.licenses.create(name=y) + def populate_files(dbpkg, repopkg, force=False): if not force: diff --git a/main/migrations/0039_auto__del_field_package_license.py b/main/migrations/0039_auto__del_field_package_license.py new file mode 100644 index 00000000..2860bc47 --- /dev/null +++ b/main/migrations/0039_auto__del_field_package_license.py @@ -0,0 +1,157 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + depends_on = ( + ('packages', '0005_move_license_data'), + ) + + def forwards(self, orm): + db.delete_column('packages', 'license') + + def backwards(self, orm): + db.add_column('packages', 'license', self.gf('django.db.models.fields.CharField')(max_length=255, null=True), keep_default=False) + + 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.donor': { + 'Meta': {'ordering': "['name']", 'object_name': 'Donor', 'db_table': "'donors'"}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'visible': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + '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'}), + '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.packagedepend': { + 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, + 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'optional': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) + }, + 'main.packagefile': { + 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) + }, + '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'}) + }, + 'main.signoff': { + 'Meta': {'object_name': 'Signoff'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), + 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + 'main.todolist': { + 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), + 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + 'main.todolistpkg': { + 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, + 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) + }, + 'main.userprofile': { + 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, + 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'symmetrical': 'False', 'blank': 'True'}), + 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), + 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'time_zone': ('django.db.models.fields.CharField', [], {'default': "'UTC'", 'max_length': '100'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'userprofile'", 'unique': 'True', 'to': "orm['auth.User']"}), + 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['main'] diff --git a/main/models.py b/main/models.py index 56e5712d..b1813c3c 100644 --- a/main/models.py +++ b/main/models.py @@ -117,7 +117,6 @@ class Package(models.Model): build_date = models.DateTimeField(null=True) last_update = models.DateTimeField(null=True, blank=True) files_last_update = models.DateTimeField(null=True, blank=True) - license = models.CharField(max_length=255, null=True) packager_str = models.CharField(max_length=255) packager = models.ForeignKey(User, null=True) flag_date = models.DateTimeField(null=True) 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: diff --git a/templates/packages/details.html b/templates/packages/details.html index de6b637f..14b657e3 100644 --- a/templates/packages/details.html +++ b/templates/packages/details.html @@ -108,8 +108,8 @@

Versions Elsewhere

{% if pkg.url %}
{{ pkg.url }}{% endif %} - License: - {{ pkg.license }} + License(s): + {{ pkg.licenses.all|join:", " }} Groups: {% with pkg.groups.all as groups %} -- cgit v1.2.3-54-g00ecf From 7f1c7b08227e49172734f09552ceae8bc1f685ad Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 15 Feb 2011 19:31:56 -0600 Subject: Read in optional deps and show in web interface Signed-off-by: Dan McGee --- devel/management/commands/reporead.py | 36 ++++++++++++++++++++++------------- main/models.py | 6 +++--- media/archweb.css | 4 ++++ templates/packages/details.html | 25 +++++++++++++----------- 4 files changed, 44 insertions(+), 27 deletions(-) (limited to 'templates') diff --git a/devel/management/commands/reporead.py b/devel/management/commands/reporead.py index 9b99e0f7..f3ec50e8 100644 --- a/devel/management/commands/reporead.py +++ b/devel/management/commands/reporead.py @@ -29,7 +29,7 @@ from logging import ERROR, WARNING, INFO, DEBUG -from main.models import Arch, Package, Repo +from main.models import Arch, Package, PackageDepend, Repo logging.basicConfig( level=WARNING, @@ -155,6 +155,20 @@ def user_name(): # lookup more than strictly necessary. find_user.cache = {} +def create_depend(package, dep_str, optional=False): + depend = PackageDepend(pkg=package, optional=optional) + # lop off any description first + parts = dep_str.split(':', 1) + if len(parts) > 1: + depend.description = parts[1].strip() + match = re.match(r"^(.+?)((>=|<=|=|>|<)(.*))?$", parts[0].strip()) + if match: + depend.depname = match.group(1) + if match.group(2): + depend.depvcmp = match.group(2) + depend.save(force_insert=True) + return depend + def populate_pkg(dbpkg, repopkg, force=False, timestamp=None): if repopkg.base: dbpkg.pkgbase = repopkg.base @@ -188,24 +202,20 @@ def populate_pkg(dbpkg, repopkg, force=False, timestamp=None): populate_files(dbpkg, repopkg, force=force) dbpkg.packagedepend_set.all().delete() - if 'depends' in repopkg.__dict__: + if hasattr(repopkg, 'depends'): for y in repopkg.depends: - # make sure we aren't adding self depends.. - # yes *sigh* i have seen them in pkgbuilds - dpname, dpvcmp = re.match(r"([a-z0-9._+-]+)(.*)", y).groups() - if dpname == repopkg.name: - logger.warning('Package %s has a depend on itself', repopkg.name) - continue - dbpkg.packagedepend_set.create(depname=dpname, depvcmp=dpvcmp) - logger.debug('Added %s as dep for pkg %s', dpname, repopkg.name) + dep = create_depend(dbpkg, y) + if hasattr(repopkg, 'optdepends'): + for y in repopkg.optdepends: + dep = create_depend(dbpkg, y, True) dbpkg.groups.all().delete() - if 'groups' in repopkg.__dict__: + if hasattr(repopkg, 'groups'): for y in repopkg.groups: dbpkg.groups.create(name=y) dbpkg.licenses.all().delete() - if 'license' in repopkg.__dict__: + if hasattr(repopkg, 'license'): for y in repopkg.license: dbpkg.licenses.create(name=y) @@ -223,7 +233,7 @@ def populate_files(dbpkg, repopkg, force=False): elif dbpkg.files_last_update > dbpkg.last_update: return # only delete files if we are reading a DB that contains them - if 'files' in repopkg.__dict__: + if hasattr(repopkg, 'files'): dbpkg.packagefile_set.all().delete() logger.info("adding %d files for package %s", len(repopkg.files), dbpkg.pkgname) diff --git a/main/models.py b/main/models.py index b1813c3c..dafbb1eb 100644 --- a/main/models.py +++ b/main/models.py @@ -209,7 +209,7 @@ def get_depends(self): """ deps = [] # TODO: we can use list comprehension and an 'in' query to make this more effective - for dep in self.packagedepend_set.order_by('depname'): + for dep in self.packagedepend_set.order_by('optional', 'depname'): pkgs = Package.objects.select_related('arch', 'repo').filter( pkgname=dep.depname) if not self.arch.agnostic: @@ -320,12 +320,12 @@ class Meta: class PackageDepend(models.Model): pkg = models.ForeignKey(Package) depname = models.CharField(max_length=255, db_index=True) - depvcmp = models.CharField(max_length=255) + depvcmp = models.CharField(max_length=255, default='') optional = models.BooleanField(default=False) description = models.TextField(null=True, blank=True) def __unicode__(self): - return "%s%s" % (depname, depvcmp) + return "%s%s" % (self.depname, self.depvcmp) class Meta: db_table = 'package_depends' diff --git a/media/archweb.css b/media/archweb.css index d45ea10b..47abba7b 100644 --- a/media/archweb.css +++ b/media/archweb.css @@ -216,6 +216,10 @@ form#flag-pkg-form textarea, form#flag-pkg-form input[type=text] { width: 45%; } #pkgdetails #metadata .message { font-style: italic; } #pkgdetails #metadata br { clear: both; } #pkgdetails #pkgdeps { float: left; width: 48%; margin-right: 2%; } +#pkgdetails #metadata .virtual-dep { font-style: italic; } +#pkgdetails #metadata .testing-dep { font-style: italic; } +#pkgdetails #metadata .opt-dep { font-style: italic; } +#pkgdetails #metadata .dep-desc { font-style: italic; } #pkgdetails #pkgreqs { float: left; width: 50%; } #pkgdetails #pkgfiles { clear: left; padding-top: 1em; } diff --git a/templates/packages/details.html b/templates/packages/details.html index 14b657e3..ac997184 100644 --- a/templates/packages/details.html +++ b/templates/packages/details.html @@ -159,16 +159,18 @@

{% if deps %}
    - {% for depend in deps %} - {% ifequal depend.pkg None %} -
  • {{ depend.dep.depname }} (virtual)
  • - {% else %} + {% for depend in deps %} + {% ifequal depend.pkg None %} +
  • {{ depend.dep.depname }} (virtual)
  • + {% else %}
  • {{ depend.dep.depname }} - {{ depend.dep.depvcmp }}{% if depend.pkg.repo.testing %} - (testing){% endif %}
  • - {% endifequal %} - {% endfor %} + title="View package details for {{ depend.dep.depname }}">{{ depend.dep.depname }}{{ depend.dep.depvcmp|default:"" }} + {% if depend.pkg.repo.testing %}(testing){% endif %} + {% if depend.dep.optional %}(optional){% endif %} + {% if depend.dep.description %}{{ depend.dep.description }}{% endif %} + + {% endifequal %} + {% endfor %}
{% endif %} @@ -184,9 +186,10 @@

{% if rqdby %}
    {% for req in rqdby %} -
  • {{ req.pkgname }} - {% if req.repo.testing %} (testing){% endif %}
  • + {% if req.repo.testing %}(testing){% endif %} + {% endfor %}
{% endif %} -- cgit v1.2.3-54-g00ecf From 8d3d05c7cb81611537aa34fa68e98e5e22b74847 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 15 Feb 2011 20:00:33 -0600 Subject: Allow for optional info in required by display We need to make our root object the PackageDepend rather than the Package to get at this, so do a slight refactor on get_requiredby(). Signed-off-by: Dan McGee --- main/models.py | 31 ++++++++++++++++++------------- templates/packages/details.html | 7 ++++--- 2 files changed, 22 insertions(+), 16 deletions(-) (limited to 'templates') diff --git a/main/models.py b/main/models.py index dafbb1eb..73a7620d 100644 --- a/main/models.py +++ b/main/models.py @@ -7,7 +7,6 @@ from itertools import groupby import pytz -from operator import attrgetter class UserProfile(models.Model): notify = models.BooleanField( @@ -173,10 +172,15 @@ def get_requiredby(self): list slim by including the corresponding package in the same testing category as this package if that check makes sense. """ - requiredby = Package.objects.select_related('arch', 'repo').filter( - packagedepend__depname=self.pkgname, - arch__in=self.applicable_arches() - ).distinct().order_by('pkgname') + requiredby = PackageDepend.objects.select_related('pkg', + 'pkg__arch', 'pkg__repo').filter( + pkg__arch__in=self.applicable_arches(), + depname=self.pkgname).order_by( + 'pkg__pkgname', 'pkg__id') + # sort out duplicate packages; this happens if something has a double + # versioned dep such as a kernel module + requiredby = [list(vals)[0] for k, vals in + groupby(requiredby, lambda x: x.pkg.id)] # find another package by this name in the opposite testing setup if not Package.objects.filter(pkgname=self.pkgname, @@ -189,14 +193,15 @@ def get_requiredby(self): # for each unique package name, try to screen our package list down to # those packages in the same testing category (yes or no) iff there is # a package in the same testing category. - for name, pkgs in groupby(requiredby, attrgetter('pkgname')): - pkgs = list(pkgs) - pkg = pkgs[0] - if len(pkgs) > 1: - pkgs = [p for p in pkgs if p.repo.testing == self.repo.testing] - if len(pkgs) > 0: - pkg = pkgs[0] - trimmed.append(pkg) + for name, dep_pkgs in groupby(requiredby, lambda x: x.pkg.pkgname): + dep_pkgs = list(dep_pkgs) + dep = dep_pkgs[0] + if len(dep_pkgs) > 1: + dep_pkgs = [d for d in dep_pkgs + if d.pkg.repo.testing == self.repo.testing] + if len(dep_pkgs) > 0: + dep = dep_pkgs[0] + trimmed.append(dep) return trimmed @cache_function(300) diff --git a/templates/packages/details.html b/templates/packages/details.html index ac997184..09b970cd 100644 --- a/templates/packages/details.html +++ b/templates/packages/details.html @@ -186,9 +186,10 @@

{% if rqdby %}
    {% for req in rqdby %} -
  • {{ req.pkgname }} - {% if req.repo.testing %}(testing){% endif %} +
  • {{ req.pkg.pkgname }} + {% if req.pkg.repo.testing %}(testing){% endif %} + {% if req.optional %}(optional){% endif %}
  • {% endfor %}
-- cgit v1.2.3-54-g00ecf 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 --- devel/management/commands/reporead.py | 10 +- .../0042_auto__del_field_packagefile_path.py | 158 +++++++++++++++++++++ main/models.py | 3 +- packages/views.py | 2 +- templates/packages/files-list.html | 2 +- 5 files changed, 169 insertions(+), 6 deletions(-) create mode 100644 main/migrations/0042_auto__del_field_packagefile_path.py (limited to 'templates') diff --git a/devel/management/commands/reporead.py b/devel/management/commands/reporead.py index f3ec50e8..72595c63 100644 --- a/devel/management/commands/reporead.py +++ b/devel/management/commands/reporead.py @@ -237,8 +237,14 @@ def populate_files(dbpkg, repopkg, force=False): dbpkg.packagefile_set.all().delete() logger.info("adding %d files for package %s", len(repopkg.files), dbpkg.pkgname) - for x in repopkg.files: - dbpkg.packagefile_set.create(path=x) + for f in repopkg.files: + dirname, filename = f.rsplit('/', 1) + if filename == '': + filename = None + dbpkg.packagefile_set.create( + is_directory=(filename is None), + directory=dirname + '/', + filename=filename) dbpkg.files_last_update = datetime.now() dbpkg.save() diff --git a/main/migrations/0042_auto__del_field_packagefile_path.py b/main/migrations/0042_auto__del_field_packagefile_path.py new file mode 100644 index 00000000..837a6a7f --- /dev/null +++ b/main/migrations/0042_auto__del_field_packagefile_path.py @@ -0,0 +1,158 @@ +# 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): + # Deleting field 'PackageFile.path' + db.delete_column('package_files', 'path') + + def backwards(self, orm): + # Adding field 'PackageFile.path' + db.add_column('package_files', 'path', self.gf('django.db.models.fields.CharField')(default='', max_length=255), keep_default=False) + + + 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.donor': { + 'Meta': {'ordering': "['name']", 'object_name': 'Donor', 'db_table': "'donors'"}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'visible': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + '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'}), + '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.packagedepend': { + 'Meta': {'object_name': 'PackageDepend', 'db_table': "'package_depends'"}, + 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'depvcmp': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'optional': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) + }, + 'main.packagefile': { + 'Meta': {'object_name': 'PackageFile', 'db_table': "'package_files'"}, + 'directory': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'filename': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_directory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) + }, + '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'}) + }, + 'main.signoff': { + 'Meta': {'object_name': 'Signoff'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}), + 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + 'main.todolist': { + 'Meta': {'object_name': 'Todolist', 'db_table': "'todolists'"}, + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), + 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + 'main.todolistpkg': { + 'Meta': {'unique_together': "(('list', 'pkg'),)", 'object_name': 'TodolistPkg', 'db_table': "'todolist_pkgs'"}, + 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}), + 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}) + }, + 'main.userprofile': { + 'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"}, + 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'symmetrical': 'False', 'blank': 'True'}), + 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}), + 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'time_zone': ('django.db.models.fields.CharField', [], {'default': "'UTC'", 'max_length': '100'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'userprofile'", 'unique': 'True', 'to': "orm['auth.User']"}), + 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['main'] diff --git a/main/models.py b/main/models.py index ed136759..a7cc2335 100644 --- a/main/models.py +++ b/main/models.py @@ -314,13 +314,12 @@ class Signoff(models.Model): class PackageFile(models.Model): pkg = models.ForeignKey(Package) - path = models.CharField(max_length=255) is_directory = models.BooleanField(default=False) directory = models.CharField(max_length=255) filename = models.CharField(max_length=255, null=True, blank=True) def __unicode__(self): - return self.path + return "%s%s" % (self.directory, self.filename or '') class Meta: db_table = 'package_files' 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' diff --git a/templates/packages/files-list.html b/templates/packages/files-list.html index 1c9ea635..bb89b663 100644 --- a/templates/packages/files-list.html +++ b/templates/packages/files-list.html @@ -5,7 +5,7 @@ {% if files.count %}
    {% for file in files %} -
  • {{ file.path }}
  • +
  • {{ file.directory }}{{ file.filename|default:'' }}
  • {% endfor %}
{% else %} -- cgit v1.2.3-54-g00ecf From dfc4d919f1b0349d5143764c3f8f62c240e50623 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 22 Feb 2011 17:24:09 -0600 Subject: Use hyphen to offset optdep description Signed-off-by: Dan McGee --- templates/packages/details.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'templates') diff --git a/templates/packages/details.html b/templates/packages/details.html index 09b970cd..ea5e528c 100644 --- a/templates/packages/details.html +++ b/templates/packages/details.html @@ -167,7 +167,7 @@

title="View package details for {{ depend.dep.depname }}">{{ depend.dep.depname }}{{ depend.dep.depvcmp|default:"" }} {% if depend.pkg.repo.testing %}(testing){% endif %} {% if depend.dep.optional %}(optional){% endif %} - {% if depend.dep.description %}{{ depend.dep.description }}{% endif %} + {% if depend.dep.description %}- {{ depend.dep.description }}{% endif %} {% endifequal %} {% endfor %} -- cgit v1.2.3-54-g00ecf 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 ++++++- templates/packages/stale_relations.html | 101 ++++++++++++++++++++++++++++++++ 5 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 templates/packages/stale_relations.html (limited to 'templates') 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 @@ (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 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 @@ def get_differences_info(arch_a, arch_b): 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.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.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: diff --git a/templates/packages/stale_relations.html b/templates/packages/stale_relations.html new file mode 100644 index 00000000..975ef1b6 --- /dev/null +++ b/templates/packages/stale_relations.html @@ -0,0 +1,101 @@ +{% extends "base.html" %} +{% block title %}Arch Linux - Stale Package Relations{% endblock %} +{% block navbarclass %}anb-packages{% endblock %} + +{% block content %} +
+

Stale Package Relations

+ +

Inactive User Relations ({{ inactive_user|length }})

+ + + + + + + + + + + + {% for relation in inactive_user %} + + + + + + + {% empty %} + + {% endfor %} + +
Package BasePackagesUserType
{{ relation.pkgbase }}{% for pkg in relation.get_associated_packages %} + {{ pkg.repo|lower }}/{{ pkg.pkgname }} ({{ pkg.arch }}){% if not forloop.last %}, {% endif %} + {% endfor %}{{ relation.user.get_full_name }}{{ relation.get_type_display }}
No inactive user relations.
+ +

Relations with Non-existent pkgbase ({{ missing_pkgbase|length }})

+ + + + + + + + + + + {% for relation in missing_pkgbase %} + + + + + + {% empty %} + + {% endfor %} + +
Package BaseUserType
{{ relation.pkgbase }}{{ relation.user.get_full_name }}{{ relation.get_type_display }}
No non-existent pkgbase relations.
+ +

Maintainers with Wrong Permissions ({{ wrong_permissions|length }})

+ + + + + + + + + + + + + {% for relation in wrong_permissions %} + + + + + + + + {% empty %} + + {% endfor %} + +
Package BasePackagesUserAllowed ReposCurrently in Repos
{{ relation.pkgbase }}{% for pkg in relation.get_associated_packages %} + {{ pkg.repo|lower }}/{{ pkg.pkgname }} ({{ pkg.arch }}){% if not forloop.last %}, {% endif %} + {% endfor %}{{ relation.user.get_full_name }}{{ relation.user.userprofile.allowed_repos.all|join:", " }}{{ relation.repositories|join:", " }}
No relations with wrong permissions.
+ +
+{% load cdn %}{% jquery %} + + + +{% endblock %} -- cgit v1.2.3-54-g00ecf 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 +++++++++++++ templates/packages/stale_relations.html | 23 +++++++++++++++++------ 3 files changed, 31 insertions(+), 6 deletions(-) (limited to 'templates') 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 @@ (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.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: diff --git a/templates/packages/stale_relations.html b/templates/packages/stale_relations.html index 975ef1b6..8e2f8930 100644 --- a/templates/packages/stale_relations.html +++ b/templates/packages/stale_relations.html @@ -6,11 +6,13 @@

Stale Package Relations

+
{% csrf_token %}

Inactive User Relations ({{ inactive_user|length }})

+ @@ -20,6 +22,7 @@

Inactive User Relations ({{ inactive_user|length }})

{% for relation in inactive_user %} + {% empty %} - + {% endfor %}
  Package Base Packages User
{{ relation.pkgbase }} {% for pkg in relation.get_associated_packages %} Inactive User Relations ({{ inactive_user|length }}) {{ relation.get_type_display }}
No inactive user relations.
No inactive user relations.
@@ -39,6 +42,7 @@

Relations with Non-existent pkgbase ({{ missing_pkgbase|length }})< + @@ -47,12 +51,13 @@

Relations with Non-existent pkgbase ({{ missing_pkgbase|length }})<

{% for relation in missing_pkgbase %} + {% empty %} - + {% endfor %}
  Package Base User Type
{{ relation.pkgbase }} {{ relation.user.get_full_name }} {{ relation.get_type_display }}
No non-existent pkgbase relations.
No non-existent pkgbase relations.
@@ -62,6 +67,7 @@

Maintainers with Wrong Permissions ({{ wrong_permissions|length }})

+ @@ -72,6 +78,7 @@

Maintainers with Wrong Permissions ({{ wrong_permissions|length }})

{% for relation in wrong_permissions %} + {% empty %} - + {% endfor %}
  Package Base Packages User
{{ relation.pkgbase }} {% for pkg in relation.get_associated_packages %} Maintainers with Wrong Permissions ({{ wrong_permissions|length }}) {{ relation.repositories|join:", " }}
No relations with wrong permissions.
No relations with wrong permissions.
+

+

+
{% load cdn %}{% jquery %} {% endblock %} -- cgit v1.2.3-54-g00ecf From 710ec0a9de9a2185621cd7f51cdd2a056e12f999 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 3 Mar 2011 14:43:58 -0600 Subject: Remove devel notify view All of this can just be set on the main profile page. Signed-off-by: Dan McGee --- devel/tests.py | 7 ------- devel/urls.py | 1 - devel/views.py | 9 --------- templates/devel/index.html | 9 --------- 4 files changed, 26 deletions(-) (limited to 'templates') diff --git a/devel/tests.py b/devel/tests.py index 682f3d92..da5459d6 100644 --- a/devel/tests.py +++ b/devel/tests.py @@ -10,13 +10,6 @@ def test_index(self): self.assertEqual(response['location'], 'http://testserver/login/?next=/devel/') - def test_notify(self): - response = self.client.get('/devel/notify/') - self.assertEqual(response.status_code, 302) - self.assertEqual(response.has_header('Location'), True) - self.assertEqual(response['location'], - 'http://testserver/login/?next=/devel/notify/') - def test_profile(self): response = self.client.get('/devel/profile/') self.assertEqual(response.status_code, 302) diff --git a/devel/urls.py b/devel/urls.py index 0a050a92..bcf9c071 100644 --- a/devel/urls.py +++ b/devel/urls.py @@ -3,7 +3,6 @@ urlpatterns = patterns('devel.views', (r'^$', 'index'), (r'^clock/$', 'clock'), - (r'^notify/$', 'change_notify'), (r'^profile/$', 'change_profile'), (r'^newuser/$', 'new_user_form'), ) diff --git a/devel/views.py b/devel/views.py index b26c7af0..f89d6870 100644 --- a/devel/views.py +++ b/devel/views.py @@ -65,15 +65,6 @@ def clock(request): return direct_to_template(request, 'devel/clock.html', page_dict) -@login_required -def change_notify(request): - maint = User.objects.get(username=request.user.username) - notify = request.POST.get('notify', 'no') - prof = maint.get_profile() - prof.notify = (notify == 'yes') - prof.save() - return HttpResponseRedirect('/devel/') - class ProfileForm(forms.Form): email = forms.EmailField(label='Private email (not shown publicly):', help_text="Used for out-of-date notifications, etc.") diff --git a/templates/devel/index.html b/templates/devel/index.html index cb9b92ae..08ca249a 100644 --- a/templates/devel/index.html +++ b/templates/devel/index.html @@ -89,15 +89,6 @@

Package Todo Lists

-
{% csrf_token %} -
-

- -

-
-
-
-- cgit v1.2.3-54-g00ecf From 8b77efbfabfb3d65b0400e123025c02346454214 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 3 Mar 2011 14:59:04 -0600 Subject: Template fine-grained permissioning Rather than use user.is_authenticated, rely on certain permissions being set for the user. This allows us to open up the developer side and not assume everyone is a package maintainer. Allow all logged-in users to still view todo lists, but don't show the complete/incomplete links (only the text) unless they are allowed to mess with todo lists. Signed-off-by: Dan McGee --- templates/packages/details.html | 4 ++-- templates/packages/search.html | 6 +++--- templates/todolists/view.html | 4 ++++ 3 files changed, 9 insertions(+), 5 deletions(-) (limited to 'templates') diff --git a/templates/packages/details.html b/templates/packages/details.html index ea5e528c..f73e9d7c 100644 --- a/templates/packages/details.html +++ b/templates/packages/details.html @@ -26,7 +26,7 @@

Package Actions

title="Testing package details for {{ tp.pkgname }}">{{ tp.pkgver }}-{{ tp.pkgrel }} in testing {% endif %}{% endwith %} - {% if user.is_authenticated %} + {% if perms.main.change_package %}
  • Click here to unflag
  • Click here to unflag all split packages
  • {% endif %} @@ -40,7 +40,7 @@

    Package Actions

  • Download From Mirror
  • - {% if user.is_authenticated %} + {% if perms.main.change_package %}
    {% csrf_token %}

    {% if user in pkg.maintainers %} diff --git a/templates/packages/search.html b/templates/packages/search.html index 4a779aa0..dad05ffa 100644 --- a/templates/packages/search.html +++ b/templates/packages/search.html @@ -71,7 +71,7 @@

    Package Search

    - {% if user.is_authenticated %} + {% if perms.main.change_package %} {% endif %} {% for pkg in package_list %} - {% if user.is_authenticated %} + {% if perms.main.change_package %} {% endif %} @@ -134,7 +134,7 @@

    Package Search

    {% endif %} - {% if user.is_authenticated %} + {% if perms.main.change_package %}

    Todo List: {{ list.name }}

    {% endfor %} -- cgit v1.2.3-54-g00ecf From c722d8bf9e2f647d5cd8fa3a85a17d0cb3b5b101 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 4 Mar 2011 09:36:18 -0600 Subject: Remove multiple account login/logout URLs And slightly spruce up the logout template with a header. Signed-off-by: Dan McGee --- templates/base.html | 2 +- templates/registration/logout.html | 4 +++- urls.py | 4 ---- 3 files changed, 4 insertions(+), 6 deletions(-) (limited to 'templates') diff --git a/templates/base.html b/templates/base.html index 03795dd9..88bb3414 100644 --- a/templates/base.html +++ b/templates/base.html @@ -44,7 +44,7 @@ title="arch-dev mailing list archives">Archives
  • Mirrors
  • Profile
  • -
  • Logout
  • +
  • Logout
  • {% endif %} diff --git a/templates/registration/logout.html b/templates/registration/logout.html index f8e07621..e890ce99 100644 --- a/templates/registration/logout.html +++ b/templates/registration/logout.html @@ -3,7 +3,9 @@ {% block content %}
    -

    Logout successful.

    +

    Developer Logout

    + +

    Logout was successful.

    {% endblock %} diff --git a/urls.py b/urls.py index 3608da67..33319263 100644 --- a/urls.py +++ b/urls.py @@ -42,12 +42,8 @@ urlpatterns += patterns('django.contrib.auth.views', (r'^login/$', 'login', { 'template_name': 'registration/login.html'}), - (r'^accounts/login/$', 'login', { - 'template_name': 'registration/login.html'}), (r'^logout/$', 'logout', { 'template_name': 'registration/logout.html'}), - (r'^accounts/logout/$', 'logout', { - 'template_name': 'registration/logout.html'}), ) # Public pages -- cgit v1.2.3-54-g00ecf From b5c67fad51b05b105487ff73c2d803ad9951f894 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 4 Mar 2011 11:10:33 -0600 Subject: Get general form up to snuff Signed-off-by: Dan McGee --- templates/general_form.html | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'templates') diff --git a/templates/general_form.html b/templates/general_form.html index 12b35463..1fa33513 100644 --- a/templates/general_form.html +++ b/templates/general_form.html @@ -6,14 +6,18 @@

    {{title}}

    - {% if description %}{{description}}{% endif %} + {{description}} + {{form.non_field_errors}} {% csrf_token %}
    {% for field in form %} -


    - {{field.help_text}} {% else %}: {% endif %} - {{field}} {% if field.required %}*{% endif%}

    + {{field.errors}} +

    + {% if field.help_text %}
    {{field.help_text}}{% endif %} + {{field}} + {% if field.field.required %}*{% endif %} +

    {% endfor %}

    -- cgit v1.2.3-54-g00ecf 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 --- devel/views.py | 30 ++++++++++++++++++++---------- packages/views.py | 2 +- templates/devel/new_account.txt | 5 +++++ 3 files changed, 26 insertions(+), 11 deletions(-) create mode 100644 templates/devel/new_account.txt (limited to 'templates') diff --git a/devel/views.py b/devel/views.py index f89d6870..311922ca 100644 --- a/devel/views.py +++ b/devel/views.py @@ -4,6 +4,7 @@ from django.contrib.auth.models import User from django.contrib.sites.models import Site from django.core.mail import send_mail +from django.template import loader, Context from django.views.decorators.cache import never_cache from django.views.generic.simple import direct_to_template @@ -23,8 +24,8 @@ def index(request): '''the Developer dashboard''' inner_q = PackageRelation.objects.filter(user=request.user).values('pkgbase') - flagged = Package.objects.select_related('arch', 'repo').filter(flag_date__isnull=False) - flagged = flagged.filter(pkgbase__in=inner_q).order_by('pkgname') + flagged = Package.objects.select_related('arch', 'repo').filter( + flag_date__isnull=False, pkgbase__in=inner_q).order_by('pkgname') todopkgs = TodolistPkg.objects.select_related( 'pkg', 'pkg__arch', 'pkg__repo').filter(complete=False) @@ -111,25 +112,34 @@ class Meta: first_name = forms.CharField(required=False) last_name = forms.CharField(required=False) + def clean_username(self): + username = self.cleaned_data['username'] + if User.objects.filter(username=username).exists(): + raise forms.ValidationError( + "A user with that username already exists.") + return username + def save(self): profile = forms.ModelForm.save(self, False) pwletters = ascii_letters + digits - pw = ''.join([random.choice(pwletters) for i in xrange(8)]) + password = ''.join([random.choice(pwletters) for i in xrange(8)]) user = User.objects.create_user(username=self.cleaned_data['username'], - email=self.cleaned_data['email'], password=pw) + email=self.cleaned_data['email'], password=password) user.first_name = self.cleaned_data['first_name'] user.last_name = self.cleaned_data['last_name'] user.save() profile.user = user profile.save() - domain = Site.objects.get_current().domain + + t = loader.get_template('devel/new_account.txt') + c = Context({ + 'site': Site.objects.get_current(), + 'user': user, + 'password': password, + }) send_mail("Your new archweb account", - """You can now log into: -https://%s/login/ -with these login details: -Username: %s -Password: %s""" % (domain, user.username, pw), + t.render(c), 'Arch Website Notification ', [user.email], fail_silently=False) 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.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 diff --git a/templates/devel/new_account.txt b/templates/devel/new_account.txt new file mode 100644 index 00000000..1159992a --- /dev/null +++ b/templates/devel/new_account.txt @@ -0,0 +1,5 @@ +You can now log into https://{{ site.domain }}/login/ with these login details: +Username: {{ user.username }} +Password: {{ password }} + +Please update your profile once logged in and change your password. -- cgit v1.2.3-54-g00ecf From 65e965c8f76677904f5d98965e13bf89726247d4 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 4 Mar 2011 12:39:53 -0600 Subject: Send only one email per todolist Customize each email on a per-maintainer basis and list all the relevant packages inside, rather than spamming people. Signed-off-by: Dan McGee --- templates/packages/outofdate.txt | 4 +-- templates/todolists/email_notification.txt | 13 +++---- todolists/views.py | 54 ++++++++++++++++-------------- 3 files changed, 33 insertions(+), 38 deletions(-) (limited to 'templates') diff --git a/templates/packages/outofdate.txt b/templates/packages/outofdate.txt index d8b74005..93abea03 100644 --- a/templates/packages/outofdate.txt +++ b/templates/packages/outofdate.txt @@ -1,6 +1,4 @@ -{% autoescape off %}* Note: this is an automated message - -{{ email }} wants to notify you that the following package may be out-of-date: +{% autoescape off %}{{ email }} wants to notify you that the following package may be out-of-date: Package Name: {{ pkg.pkgname }} Architecture: {{ pkg.arch.name }} diff --git a/templates/todolists/email_notification.txt b/templates/todolists/email_notification.txt index abe1dbf3..1825912c 100644 --- a/templates/todolists/email_notification.txt +++ b/templates/todolists/email_notification.txt @@ -1,14 +1,9 @@ -{% autoescape off %}* Note: this is an automated message +{% autoescape off %}The todo list {{ todolist.name }} has had the following packages added to it for which you are a maintainer: -The following package: - - Package Name: {{ pkg.pkgname }} - Architecture: {{ pkg.arch.name }} - Repository: {{ pkg.repo.name }} - ({{ weburl }}) - -has been added to this todo list: +{% for tpkg in todo_packages %} +{{ tpkg.pkg.repo.name|lower }}/{{ tpkg.pkg.pkgname }} ({{ tpkg.pkg.arch.name }}) - {{ tpkg.pkg.get_full_url }}{% endfor %} +Todo list information: Creator: {{todolist.creator.get_full_name}} Name: {{todolist.name}} Description: diff --git a/todolists/views.py b/todolists/views.py index 337fd0d6..6bd456ae 100644 --- a/todolists/views.py +++ b/todolists/views.py @@ -75,9 +75,7 @@ def add(request): form = TodoListForm(request.POST) if form.is_valid(): new_packages = create_todolist_packages(form, creator=request.user) - for new_package in new_packages: - send_newlist_email(new_package) - + send_todolist_emails(form.instance, new_packages) return redirect(form.instance) else: form = TodoListForm() @@ -98,10 +96,7 @@ def edit(request, list_id): form = TodoListForm(request.POST, instance=todo_list) if form.is_valid(): new_packages = create_todolist_packages(form) - - for new_package in new_packages: - send_todolist_email(new_package) - + send_todolist_emails(todo_list, new_packages) return redirect(todo_list) else: form = TodoListForm(instance=todo_list, @@ -152,25 +147,32 @@ def create_todolist_packages(form, creator=None): return todo_pkgs -def send_todolist_email(todo): - '''Sends an e-mail to the maintainer of a package notifying them that the - package has been added to a todo list''' - maints = todo.pkg.maintainers.values_list('email', flat=True) - if not maints: - return - - page_dict = { - 'pkg': todo.pkg, - 'todolist': todo.list, - 'weburl': todo.pkg.get_full_url() - } - t = loader.get_template('todolists/email_notification.txt') - c = Context(page_dict) - send_mail('arch: Package [%s] added to Todolist' % todo.pkg.pkgname, - t.render(c), - 'Arch Website Notification ', - maints, - fail_silently=True) +def send_todolist_emails(todo_list, new_packages): + '''Sends emails to package maintainers notifying them that packages have + been added to a todo list.''' + # start by flipping the incoming list on its head: we want a list of + # involved maintainers and the packages they need to be notified about. + orphan_packages = [] + maint_packages = {} + for todo_package in new_packages: + maints = todo_package.pkg.maintainers.values_list('email', flat=True) + if not maints: + orphan_packages.append(todo_package) + else: + for maint in maints: + maint_packages.setdefault(maint, []).append(todo_package) + + for maint, packages in maint_packages.iteritems(): + c = Context({ + 'todo_packages': sorted(packages), + 'todolist': todo_list, + }) + t = loader.get_template('todolists/email_notification.txt') + send_mail('Packages added to todo list \'%s\'' % todo_list.name, + t.render(c), + 'Arch Website Notification ', + [maint], + fail_silently=True) def public_list(request): todo_lists = Todolist.objects.incomplete() -- cgit v1.2.3-54-g00ecf
     Package Search
    {{ pkg.arch.name }} {{ pkg.pkg.repo.name|capfirst }} {{ pkg.pkg.maintainers|join:', ' }} + {% if perms.main.change_todolistpkg %} {% if pkg.complete %} Complete @@ -45,6 +46,9 @@

    Todo List: {{ list.name }}

    Incomplete {% endif %} + {% else %} + {% if pkg.complete %}Complete{% else %}Incomplete{% endif %} + {% endif %}