From 7bbb30eca1c0b8679b9797d302538213d2d5da16 Mon Sep 17 00:00:00 2001 From: Victor Rajewski Date: Tue, 18 Jun 2013 08:30:11 +1000 Subject: [PATCH 1/3] replaced erroneous strftime('%s') with isoformat() for OBI assertion --- badger/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/badger/models.py b/badger/models.py index cf40323..153a79f 100644 --- a/badger/models.py +++ b/badger/models.py @@ -795,8 +795,8 @@ def as_obi_assertion(self, request=None): "salt": hash_salt, "evidence": urljoin(base_url, self.get_absolute_url()), # TODO: implement award expiration - # "expires": self.expires.strftime('%s'), - "issued_on": self.created.strftime('%s'), + # "expires": self.expires.isoformat(), + "issued_on": self.created.isoformat(), "badge": badge_data } return assertion From d9d1d2863d74bda5f039643229ff8f46f3fc55c4 Mon Sep 17 00:00:00 2001 From: Victor Rajewski Date: Tue, 18 Jun 2013 08:42:16 +1000 Subject: [PATCH 2/3] Added field badge_prerequisites_number to Badger model, to allow auto-awarding of a badge when a set number of prerequisites met e.g. Badge Foo is awarded when 3 out of the 5 prerequisites have been obtained. --- ...o__add_field_badge_prerequisites_number.py | 128 ++++++++++++++++++ badger/models.py | 20 ++- 2 files changed, 142 insertions(+), 6 deletions(-) create mode 100644 badger/migrations/0008_auto__add_field_badge_prerequisites_number.py diff --git a/badger/migrations/0008_auto__add_field_badge_prerequisites_number.py b/badger/migrations/0008_auto__add_field_badge_prerequisites_number.py new file mode 100644 index 0000000..5ec5bf7 --- /dev/null +++ b/badger/migrations/0008_auto__add_field_badge_prerequisites_number.py @@ -0,0 +1,128 @@ +# -*- coding: 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 field 'Badge.prerequisites_number' + db.add_column('badger_badge', 'prerequisites_number', + self.gf('django.db.models.fields.PositiveIntegerField')(null=True, blank=True), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'Badge.prerequisites_number' + db.delete_column('badger_badge', 'prerequisites_number') + + + 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'}) + }, + 'badger.award': { + 'Meta': {'ordering': "['-modified', '-created']", 'object_name': 'Award'}, + 'badge': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['badger.Badge']"}), + 'claim_code': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '32', 'db_index': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'award_creator'", 'null': 'True', 'to': "orm['auth.User']"}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'hidden': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"}) + }, + 'badger.badge': { + 'Meta': {'ordering': "['-modified', '-created']", 'unique_together': "(('title', 'slug'),)", 'object_name': 'Badge'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'nominations_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'nominations_autoapproved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'prerequisites': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['badger.Badge']", 'null': 'True', 'blank': 'True'}), + 'prerequisites_number': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'}), + 'title': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'unique': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'badger.deferredaward': { + 'Meta': {'ordering': "['-modified', '-created']", 'object_name': 'DeferredAward'}, + 'badge': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['badger.Badge']"}), + 'claim_code': ('django.db.models.fields.CharField', [], {'default': "'fj347h'", 'unique': 'True', 'max_length': '32', 'db_index': 'True'}), + 'claim_group': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'email': ('django.db.models.fields.EmailField', [], {'db_index': 'True', 'max_length': '75', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'reusable': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + }, + 'badger.nomination': { + 'Meta': {'object_name': 'Nomination'}, + 'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'approver': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'nomination_approver'", 'null': 'True', 'to': "orm['auth.User']"}), + 'award': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['badger.Award']", 'null': 'True', 'blank': 'True'}), + 'badge': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['badger.Badge']"}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'nomination_creator'", 'null': 'True', 'to': "orm['auth.User']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'nominee': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nomination_nominee'", 'to': "orm['auth.User']"}), + 'rejected_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'nomination_rejected_by'", 'null': 'True', 'to': "orm['auth.User']"}), + 'rejected_reason': ('django.db.models.fields.TextField', [], {'blank': 'True'}) + }, + 'badger.progress': { + 'Meta': {'unique_together': "(('badge', 'user'),)", 'object_name': 'Progress'}, + 'badge': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['badger.Badge']"}), + 'counter': ('django.db.models.fields.FloatField', [], {'default': '0', 'null': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'notes': ('badger.models.JSONField', [], {'null': 'True', 'blank': 'True'}), + 'percent': ('django.db.models.fields.FloatField', [], {'default': '0'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'progress_user'", 'to': "orm['auth.User']"}) + }, + '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'}) + } + } + + complete_apps = ['badger'] \ No newline at end of file diff --git a/badger/models.py b/badger/models.py index 153a79f..0e95026 100644 --- a/badger/models.py +++ b/badger/models.py @@ -385,9 +385,11 @@ class Badge(models.Model): image = models.ImageField(blank=True, null=True, storage=BADGE_UPLOADS_FS, upload_to=mk_upload_to('image','png'), help_text="Upload an image to represent the badge") + prerequisites_number = models.PositiveIntegerField("Number of prerequisites required", blank=True, null=True, + help_text="This many prerequisites have to be awarded to achieve this badge (0 or blank to require all)") prerequisites = models.ManyToManyField('self', symmetrical=False, blank=True, null=True, - help_text="When all of the selected badges have been awarded, this " + help_text="When the above number of the selected badges have been awarded, this " "badge will be automatically awarded.") # TODO: Rename? Eventually we'll want a globally-unique badge. That is, one # unique award for one person for the whole site. @@ -560,17 +562,23 @@ def award_to(self, awardee=None, email=None, awarder=None, description=description) def check_prerequisites(self, awardee, dep_badge, award): - """Check the prerequisites for this badge. If they're all met, award + """Check the prerequisites for this badge. If they're, award this badge to the user.""" if self.is_awarded_to(awardee): # Not unique, but badge auto-award from prerequisites should only # happen once. return None + award_count = 0 for badge in self.prerequisites.all(): - if not badge.is_awarded_to(awardee): - # Bail on the first unmet prerequisites - return None - return self.award_to(awardee) + if badge.is_awarded_to(awardee): + award_count += 1 + if self.prerequisites_number: + if award_count >= self.prerequisites_number: + return self.award_to(awardee) + else: # No pre-requisite number specified; need to check for all pre-requisites + if award_count >= self.prerequisites.all().count(): + return self.award_to(awardee) + return None def is_awarded_to(self, user): """Has this badge been awarded to the user?""" From dd3cbcea0f528b4b5e9b74ff0062fc7d2f2fa29b Mon Sep 17 00:00:00 2001 From: Victor Rajewski Date: Tue, 18 Jun 2013 08:49:23 +1000 Subject: [PATCH 3/3] Added field allows_awarding_badge to Badge, which specifies a 'badge awarding badge' for the current badge. If a user holds the allows_award_badge for a particular badge Foo, they will be allowed to award badge Foo to others. --- ...__add_field_badge_allows_awarding_badge.py | 129 ++++++++++++++++++ badger/models.py | 7 +- 2 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 badger/migrations/0009_auto__add_field_badge_allows_awarding_badge.py diff --git a/badger/migrations/0009_auto__add_field_badge_allows_awarding_badge.py b/badger/migrations/0009_auto__add_field_badge_allows_awarding_badge.py new file mode 100644 index 0000000..ef79343 --- /dev/null +++ b/badger/migrations/0009_auto__add_field_badge_allows_awarding_badge.py @@ -0,0 +1,129 @@ +# -*- coding: 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 field 'Badge.allows_awarding_badge' + db.add_column('badger_badge', 'allows_awarding_badge', + self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='+', null=True, to=orm['badger.Badge']), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'Badge.allows_awarding_badge' + db.delete_column('badger_badge', 'allows_awarding_badge_id') + + + 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'}) + }, + 'badger.award': { + 'Meta': {'ordering': "['-modified', '-created']", 'object_name': 'Award'}, + 'badge': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['badger.Badge']"}), + 'claim_code': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '32', 'db_index': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'award_creator'", 'null': 'True', 'to': "orm['auth.User']"}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'hidden': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"}) + }, + 'badger.badge': { + 'Meta': {'ordering': "['-modified', '-created']", 'unique_together': "(('title', 'slug'),)", 'object_name': 'Badge'}, + 'allows_awarding_badge': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['badger.Badge']"}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'nominations_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'nominations_autoapproved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'prerequisites': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['badger.Badge']", 'null': 'True', 'blank': 'True'}), + 'prerequisites_number': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'}), + 'title': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'unique': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'badger.deferredaward': { + 'Meta': {'ordering': "['-modified', '-created']", 'object_name': 'DeferredAward'}, + 'badge': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['badger.Badge']"}), + 'claim_code': ('django.db.models.fields.CharField', [], {'default': "'ynwjmh'", 'unique': 'True', 'max_length': '32', 'db_index': 'True'}), + 'claim_group': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'email': ('django.db.models.fields.EmailField', [], {'db_index': 'True', 'max_length': '75', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'reusable': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + }, + 'badger.nomination': { + 'Meta': {'object_name': 'Nomination'}, + 'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'approver': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'nomination_approver'", 'null': 'True', 'to': "orm['auth.User']"}), + 'award': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['badger.Award']", 'null': 'True', 'blank': 'True'}), + 'badge': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['badger.Badge']"}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'nomination_creator'", 'null': 'True', 'to': "orm['auth.User']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'nominee': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nomination_nominee'", 'to': "orm['auth.User']"}), + 'rejected_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'nomination_rejected_by'", 'null': 'True', 'to': "orm['auth.User']"}), + 'rejected_reason': ('django.db.models.fields.TextField', [], {'blank': 'True'}) + }, + 'badger.progress': { + 'Meta': {'unique_together': "(('badge', 'user'),)", 'object_name': 'Progress'}, + 'badge': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['badger.Badge']"}), + 'counter': ('django.db.models.fields.FloatField', [], {'default': '0', 'null': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'notes': ('badger.models.JSONField', [], {'null': 'True', 'blank': 'True'}), + 'percent': ('django.db.models.fields.FloatField', [], {'default': '0'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'progress_user'", 'to': "orm['auth.User']"}) + }, + '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'}) + } + } + + complete_apps = ['badger'] \ No newline at end of file diff --git a/badger/models.py b/badger/models.py index 0e95026..4ee46d4 100644 --- a/badger/models.py +++ b/badger/models.py @@ -391,6 +391,9 @@ class Badge(models.Model): blank=True, null=True, help_text="When the above number of the selected badges have been awarded, this " "badge will be automatically awarded.") + allows_awarding_badge = models.ForeignKey('self', blank=True, null=True, related_name='+', + help_text="Users who have have obtained the selected badge will be able to award the badge you are viewing") + # TODO: Rename? Eventually we'll want a globally-unique badge. That is, one # unique award for one person for the whole site. unique = models.BooleanField(default=True, @@ -487,7 +490,9 @@ def allows_award_to(self, user): return True if user == self.creator: return True - + if self.allows_awarding_badge.is_awarded_to(user): + return True + # TODO: List of delegates for whom awarding is allowed return False