Adopted Nomination logic from django-badger

This commit is contained in:
Les Orchard 2011-08-02 14:45:46 -04:00 коммит произвёл Les Orchard
Родитель 2a1c3a82e6
Коммит cc7c89ea88
8 изменённых файлов: 336 добавлений и 11 удалений

Просмотреть файл

@ -0,0 +1,13 @@
from django.contrib import admin
from django import forms
from django.db import models
from .models import (Badge, Nomination)
class NominationAdmin(admin.ModelAdmin):
pass
admin.site.register(Nomination, NominationAdmin)

Просмотреть файл

@ -11,7 +11,8 @@ try:
except ImportError, e:
from django.utils.translation import ugettext_lazy as _
from badger.models import (Badge, Award, Nomination)
from badger.models import (Award)
from badger_multiplayer.models import (Badge, Nomination)
class MyModelForm(forms.ModelForm):
@ -62,4 +63,3 @@ class BadgeNewForm(BadgeEditForm):
super(BadgeNewForm, self).__init__(*args, **kwargs)
#if not settings.RECAPTCHA_PRIVATE_KEY:
# del self.fields['captcha']

Просмотреть файл

@ -0,0 +1,145 @@
from django.db import models
from django.db.models import signals
from django.core.serializers.json import DjangoJSONEncoder
from django.utils import simplejson as json
from django.contrib.auth.models import User, AnonymousUser
from django.template.defaultfilters import slugify
try:
from commons.urlresolvers import reverse
except ImportError, e:
from django.core.urlresolvers import reverse
import badger.models
from badger.models import (Award, BadgerException,
BadgeAlreadyAwardedException,
get_permissions_for)
from .signals import (nomination_will_be_approved, nomination_was_approved,
nomination_will_be_accepted, nomination_was_accepted,
user_will_be_nominated, user_was_nominated,)
class Badge(badger.models.Badge):
"""Enhanced Badge model with multiplayer features"""
class Meta:
proxy = True
def nominate_for(self, nominee, nominator=None):
"""Nominate a nominee for this badge on the nominator's behalf"""
return Nomination.objects.create(badge=self, creator=nominator,
nominee=nominee)
def is_nominated_for(self, user):
return Nomination.objects.filter(nominee=user, badge=self).count() > 0
class NominationException(BadgerException):
"""Nomination model exception"""
class NominationApproveNotAllowedException(NominationException):
"""Attempt to approve a nomination was disallowed"""
class NominationAcceptNotAllowedException(NominationException):
"""Attempt to accept a nomination was disallowed"""
class NominationManager(models.Manager):
pass
class Nomination(models.Model):
"""Representation of a user nominated by another user for a badge"""
objects = NominationManager()
badge = models.ForeignKey(Badge)
nominee = models.ForeignKey(User, related_name="nomination_nominee",
blank=False, null=False)
accepted = models.BooleanField(default=False)
creator = models.ForeignKey(User, related_name="nomination_creator",
blank=True, null=True)
approver = models.ForeignKey(User, related_name="nomination_approver",
blank=True, null=True)
award = models.ForeignKey(Award, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True, blank=False)
modified = models.DateTimeField(auto_now=True, blank=False)
get_permissions_for = get_permissions_for
def __unicode__(self):
return u'Nomination for %s to %s by %s' % (self.badge, self.nominee,
self.creator)
def save(self, *args, **kwargs):
# Signals and some bits of logic only happen on a new nomination.
is_new = not self.pk
# Bail if this is an attempt to double-award a unique badge
if (is_new and self.badge.unique and
self.badge.is_awarded_to(self.nominee)):
raise BadgeAlreadyAwardedException()
if is_new:
user_will_be_nominated.send(sender=self.__class__,
nomination=self)
if self.is_approved() and self.is_accepted():
self.award = self.badge.award_to(self.nominee, self.approver)
super(Nomination, self).save(*args, **kwargs)
if is_new:
user_was_nominated.send(sender=self.__class__,
nomination=self)
def allows_approve_by(self, user):
if user.is_staff or user.is_superuser:
return True
if user == self.badge.creator:
return True
return False
def approve_by(self, approver):
"""Approve this nomination.
Also awards, if already accepted."""
if not self.allows_approve_by(approver):
raise NominationApproveNotAllowedException()
self.approver = approver
nomination_will_be_approved.send(sender=self.__class__,
nomination=self)
self.save()
nomination_was_approved.send(sender=self.__class__,
nomination=self)
return self
def is_approved(self):
"""Has this nomination been approved?"""
return self.approver is not None
def allows_accept(self, user):
if user.is_staff or user.is_superuser:
return True
if user == self.nominee:
return True
return False
def accept(self, user):
"""Accept this nomination for the nominee.
Also awards, if already approved."""
if not self.allows_accept(user):
raise NominationAcceptNotAllowedException()
self.accepted = True
nomination_will_be_accepted.send(sender=self.__class__,
nomination=self)
self.save()
nomination_was_accepted.send(sender=self.__class__,
nomination=self)
return self
def is_accepted(self):
"""Has this nomination been accepted?"""
return self.accepted

Просмотреть файл

@ -0,0 +1,14 @@
"""
Signals relating to badges.
"""
from django.dispatch import Signal
user_will_be_nominated = Signal(providing_args=["nomination"])
user_was_nominated = Signal(providing_args=["nomination"])
nomination_will_be_approved = Signal(providing_args=["nomination"])
nomination_was_approved = Signal(providing_args=["nomination"])
nomination_will_be_accepted = Signal(providing_args=["nomination"])
nomination_was_accepted = Signal(providing_args=["nomination"])

Просмотреть файл

@ -28,4 +28,3 @@ class BadgerTestCase(test.TestCase):
# Restore the settings.
settings.INSTALLED_APPS = self._original_installed_apps
loading.cache.loaded = False

Просмотреть файл

@ -0,0 +1,153 @@
import logging
from django.conf import settings
from django.core.management import call_command
from django.db.models import loading
from django.http import HttpRequest
from django.test.client import Client
from nose.tools import assert_equal, with_setup, assert_false, eq_, ok_
from nose.plugins.attrib import attr
from django.template.defaultfilters import slugify
from django.contrib.auth.models import User
from . import BadgerTestCase
import badger
import badger_multiplayer
from badger.models import (Award, Progress,
BadgeAwardNotAllowedException,
BadgeAlreadyAwardedException)
from badger_multiplayer.models import (Badge, Nomination,
NominationApproveNotAllowedException,
NominationAcceptNotAllowedException)
from badger_test.models import GuestbookEntry
class BadgerMultiplayerBadgeTest(BadgerTestCase):
def setUp(self):
self.user_1 = self._get_user(username="user_1",
email="user_1@example.com", password="user_1_pass")
def tearDown(self):
Nomination.objects.all().delete()
Award.objects.all().delete()
Badge.objects.all().delete()
def test_nominate_badge(self):
"""Can nominate a user for a badge"""
badge = self._get_badge()
nominator = self._get_user(username="nominator",
email="nominator@example.com", password="nomnom1")
nominee = self._get_user(username="nominee",
email="nominee@example.com", password="nomnom2")
ok_(not badge.is_nominated_for(nominee))
nomination = badge.nominate_for(nominator=nominator, nominee=nominee)
ok_(badge.is_nominated_for(nominee))
def test_approve_nomination(self):
"""A nomination can be approved"""
nomination = self._create_nomination()
ok_(not nomination.is_approved())
nomination.approve_by(nomination.badge.creator)
ok_(nomination.is_approved())
def test_accept_nomination(self):
"""A nomination can be accepted"""
nomination = self._create_nomination()
ok_(not nomination.is_accepted())
nomination.accept(nomination.nominee)
ok_(nomination.is_accepted())
def test_accept_nomination(self):
"""A nomination that is approved and accepted results in an award"""
nomination = self._create_nomination()
ok_(not nomination.badge.is_awarded_to(nomination.nominee))
nomination.approve_by(nomination.badge.creator)
nomination.accept(nomination.nominee)
ok_(nomination.badge.is_awarded_to(nomination.nominee))
ct = Award.objects.filter(nomination=nomination).count()
eq_(1, ct, "There should be an award associated with the nomination")
def test_disallowed_nomination_approval(self):
"""By default, only badge creator should be allowed to approve a
nomination."""
nomination = self._create_nomination()
other_user = self._get_user(username="other")
try:
nomination = nomination.approve_by(other_user)
ok_(False, "Nomination should not have succeeded")
except NominationApproveNotAllowedException, e:
ok_(True)
def test_disallowed_nomination_accept(self):
"""By default, only nominee should be allowed to accept a
nomination."""
nomination = self._create_nomination()
other_user = self._get_user(username="other")
try:
nomination = nomination.accept(other_user)
ok_(False, "Nomination should not have succeeded")
except NominationAcceptNotAllowedException, e:
ok_(True)
def _get_user(self, username="tester", email="tester@example.com",
password="trustno1"):
(user, created) = User.objects.get_or_create(username=username,
defaults=dict(email=email))
if created:
user.set_password(password)
user.save()
return user
def test_nomination_badge_already_awarded(self):
"""New nomination for an awarded unique badge cannot be created"""
user = self._get_user()
b = Badge.objects.create(slug='one-and-only', title='One and Only',
unique=True, creator=user)
n = b.nominate_for(user)
n.accept(user)
n.approve_by(user)
try:
n = Nomination.objects.create(badge=b, nominee=user)
ok_(False, 'BadgeAlreadyAwardedException should have been raised')
except BadgeAlreadyAwardedException, e:
pass
# Nominations stick around after award.
eq_(1, Nomination.objects.filter(badge=b, nominee=user).count())
def _get_badge(self, title="Test Badge",
description="This is a test badge", creator=None):
creator = creator or self.user_1
(badge, created) = Badge.objects.get_or_create(title=title,
defaults=dict(description=description, creator=creator))
return badge
def _create_nomination(self, badge=None, nominator=None, nominee=None):
badge = badge or self._get_badge()
nominator = nominator or self._get_user(username="nominator",
email="nominator@example.com", password="nomnom1")
nominee = nominee or self._get_user(username="nominee",
email="nominee@example.com", password="nomnom2")
nomination = badge.nominate_for(nominator=nominator, nominee=nominee)
return nomination

Просмотреть файл

@ -23,8 +23,10 @@ except ImportError, e:
from . import BadgerTestCase
from badger.models import (Badge, Award, Nomination,
BadgeAwardNotAllowedException,
from badger.models import (Award, Progress,
BadgeAwardNotAllowedException)
from badger_multiplayer.models import (Badge, Nomination,
NominationApproveNotAllowedException,
NominationAcceptNotAllowedException)
@ -40,7 +42,6 @@ class BadgerViewsTest(BadgerTestCase):
Award.objects.all().delete()
Badge.objects.all().delete()
@attr('current')
def test_create(self):
"""Can create badge with form"""
# Login should be required
@ -136,5 +137,3 @@ class BadgerViewsTest(BadgerTestCase):
user.set_password(password)
user.save()
return user

Просмотреть файл

@ -29,8 +29,10 @@ from django.views.decorators.http import (require_GET, require_POST,
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from badger.models import (Badge, Award, Nomination,
BadgeAwardNotAllowedException,
from badger.models import (Award, Progress,
BadgeAwardNotAllowedException)
from badger_multiplayer.models import (Badge, Nomination,
NominationApproveNotAllowedException,
NominationAcceptNotAllowedException)
@ -65,7 +67,7 @@ def edit(request, slug):
badge = get_object_or_404(Badge, slug=slug)
if not badge.allows_edit_by(request.user):
return HttpResponseForbidden()
if request.method != "POST":
form = BadgeEditForm(instance=badge)
else: