Adopted Nomination logic from django-badger
This commit is contained in:
Родитель
2a1c3a82e6
Коммит
cc7c89ea88
|
@ -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)
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче