Badge nominations and misc tweaks
* Nomination submission view, to create new nominations * Nomination detail view, affords approval and acceptance * Award model proxy that produces multiplayer Badge proxies
This commit is contained in:
Родитель
f66d12bac2
Коммит
84abb3a449
|
@ -12,33 +12,10 @@ except ImportError, e:
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from badger.models import (Award)
|
||||
from badger.forms import (MyModelForm, MyForm)
|
||||
from badger_multiplayer.models import (Badge, Nomination)
|
||||
|
||||
|
||||
class MyModelForm(forms.ModelForm):
|
||||
def as_ul(self):
|
||||
"Returns this form rendered as HTML <li>s -- excluding the <ul></ul>."
|
||||
return self._html_output(
|
||||
normal_row=(u'<li%(html_class_attr)s>%(label)s %(field)s' +
|
||||
'%(help_text)s%(errors)s</li>'),
|
||||
error_row=u'<li>%s</li>',
|
||||
row_ender='</li>',
|
||||
help_text_html=u' <p class="help">%s</p>',
|
||||
errors_on_separate_row=False)
|
||||
|
||||
|
||||
class MyForm(forms.Form):
|
||||
def as_ul(self):
|
||||
"Returns this form rendered as HTML <li>s -- excluding the <ul></ul>."
|
||||
return self._html_output(
|
||||
normal_row=(u'<li%(html_class_attr)s>%(label)s %(field)s' +
|
||||
'%(help_text)s%(errors)s</li>'),
|
||||
error_row=u'<li>%s</li>',
|
||||
row_ender='</li>',
|
||||
help_text_html=u' <p class="help">%s</p>',
|
||||
errors_on_separate_row=False)
|
||||
|
||||
|
||||
class BadgeEditForm(MyModelForm):
|
||||
|
||||
class Meta:
|
||||
|
@ -63,3 +40,10 @@ class BadgeNewForm(BadgeEditForm):
|
|||
super(BadgeNewForm, self).__init__(*args, **kwargs)
|
||||
#if not settings.RECAPTCHA_PRIVATE_KEY:
|
||||
# del self.fields['captcha']
|
||||
|
||||
class BadgeSubmitNominationForm(MyModelForm):
|
||||
|
||||
class Meta:
|
||||
model = Nomination
|
||||
fields = ('nominee', )
|
||||
|
||||
|
|
|
@ -18,14 +18,33 @@ from badger.models import (Award, BadgerException,
|
|||
|
||||
from .signals import (nomination_will_be_approved, nomination_was_approved,
|
||||
nomination_will_be_accepted, nomination_was_accepted,
|
||||
user_will_be_nominated, user_was_nominated,)
|
||||
user_will_be_nominated, user_was_nominated, )
|
||||
|
||||
|
||||
class Badge(badger.models.Badge):
|
||||
"""Enhanced Badge model with multiplayer features"""
|
||||
|
||||
class Meta:
|
||||
proxy = True
|
||||
|
||||
get_permissions_for = get_permissions_for
|
||||
|
||||
def allows_nominate_for(self, user):
|
||||
"""Is nominate_for() allowed for this user?"""
|
||||
if None == user:
|
||||
return True
|
||||
if user.is_anonymous():
|
||||
return False
|
||||
if user.is_staff or user.is_superuser:
|
||||
return True
|
||||
if user == self.creator:
|
||||
return True
|
||||
|
||||
# TODO: Flag to enable / disable nominations from anyone
|
||||
# TODO: List of delegates from whom nominations are accepted
|
||||
|
||||
return 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,
|
||||
|
@ -35,6 +54,20 @@ class Badge(badger.models.Badge):
|
|||
return Nomination.objects.filter(nominee=user, badge=self).count() > 0
|
||||
|
||||
|
||||
class Award(badger.models.Award):
|
||||
"""Enhanced Award model with multiplayer features"""
|
||||
|
||||
class Meta:
|
||||
proxy = True
|
||||
|
||||
@property
|
||||
def badge(self):
|
||||
"""Property that wraps the related badge in a multiplayer upgrade"""
|
||||
new_inst = Badge()
|
||||
new_inst.__dict__ = super(Award, self).badge.__dict__
|
||||
return new_inst
|
||||
|
||||
|
||||
class NominationException(BadgerException):
|
||||
"""Nomination model exception"""
|
||||
|
||||
|
@ -88,7 +121,14 @@ class Nomination(models.Model):
|
|||
nomination=self)
|
||||
|
||||
if self.is_approved() and self.is_accepted():
|
||||
self.award = self.badge.award_to(self.nominee, self.approver)
|
||||
# HACK: Convert the original-flavor Award into a multiplayer Award
|
||||
# before assigning to self.
|
||||
real_award = self.badge.award_to(self.nominee, self.approver)
|
||||
award = Award()
|
||||
award.__dict__ = real_award.__dict__
|
||||
self.award = award
|
||||
# This was the original code, which caused errors:
|
||||
# self.award = self.badge.award_to(self.nominee, self.approver)
|
||||
|
||||
super(Nomination, self).save(*args, **kwargs)
|
||||
|
||||
|
@ -96,11 +136,26 @@ class Nomination(models.Model):
|
|||
user_was_nominated.send(sender=self.__class__,
|
||||
nomination=self)
|
||||
|
||||
def allows_detail_by(self, user):
|
||||
if (user.is_staff or
|
||||
user.is_superuser or
|
||||
user == self.badge.creator or
|
||||
user == self.nominee or
|
||||
user == self.creator ):
|
||||
return True
|
||||
|
||||
# TODO: List of delegates empowered by badge creator to approve nominations
|
||||
|
||||
return False
|
||||
|
||||
def allows_approve_by(self, user):
|
||||
if user.is_staff or user.is_superuser:
|
||||
return True
|
||||
if user == self.badge.creator:
|
||||
return True
|
||||
|
||||
# TODO: List of delegates empowered by badge creator to approve nominations
|
||||
|
||||
return False
|
||||
|
||||
def approve_by(self, approver):
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
<dl class="badge" data-slug="{{ badge.slug }}">
|
||||
{% if award and award.image %}
|
||||
<dt>Image:</dt>
|
||||
<dd class="image"><img src="{{ award.image.url }}" width="256" height="256" /></dd>
|
||||
{% elif badge.image %}
|
||||
<dt>Image:</dt>
|
||||
<dd class="image"><img src="{{ badge.image.url }}" width="256" height="256" /></dd>
|
||||
{% endif %}
|
||||
<dt>Title:</dt>
|
||||
<dd class="title">{{ badge.title }}</dd>
|
||||
{% if badge.description %}
|
||||
<dt>Description:<dt>
|
||||
<dd class="description">{{ badge.description }}</dd>
|
||||
{% endif %}
|
||||
{% if badge.allows_edit_by(request.user) %}
|
||||
<dt>Actions:</dt>
|
||||
<dd><ul>
|
||||
<li><a class="edit_badge" href="{{ url('badger_multiplayer.views.edit', badge.slug) }}">edit</a></li>
|
||||
</ul></dd>
|
||||
{% endif %}
|
||||
</dl>
|
|
@ -0,0 +1,22 @@
|
|||
{% extends "badger/base.html" %}
|
||||
|
||||
{% block pageid %}badge_nominate{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h2>Submit a badge nomination</h2>
|
||||
|
||||
<form id="nominate_badge" method="POST" action="" enctype="multipart/form-data">
|
||||
{{ csrf() }}
|
||||
<ul>
|
||||
{{ form.as_ul() }}
|
||||
<li><input type="submit" class="submit" value="Nominate"></li>
|
||||
</ul>
|
||||
</form>
|
||||
|
||||
<section class="badge">
|
||||
<h3>Badge</h3>
|
||||
{% include "badger/includes/badge_full.html" %}
|
||||
</section>
|
||||
|
||||
{% endblock %}
|
|
@ -0,0 +1,6 @@
|
|||
{% if badge.allows_nominate_for(request.user) %}
|
||||
<li><a class="edit_badge" href="{{ url('badger_multiplayer.views.nominate_for', badge.slug) }}">{{ _('Submit nomination') }}</a></li>
|
||||
{% endif %}
|
||||
{% if badge.allows_edit_by(request.user) %}
|
||||
<li><a class="edit_badge" href="{{ url('badger_multiplayer.views.edit', badge.slug) }}">{{ _('Edit badge') }}</a></li>
|
||||
{% endif %}
|
|
@ -0,0 +1,58 @@
|
|||
{% extends "badger/base.html" %}
|
||||
|
||||
{% block pageid %}nomination_detail{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<section class="nomination">
|
||||
<h2>Nomination</h2>
|
||||
<dl>
|
||||
{% set show_approve = not nomination.is_approved() and nomination.allows_approve_by(request.user) %}
|
||||
{% set show_accept = not nomination.is_accepted() and nomination.allows_accept(request.user) %}
|
||||
{% if show_approve or show_accept %}
|
||||
<dt>Actions:</dt><dd><ul>
|
||||
{% if show_approve %}
|
||||
<li><form method="POST">
|
||||
{{ csrf() }}
|
||||
<input type="hidden" name="action" value="approve_by" />
|
||||
<button>{{ _('Approve nomination') }}</button>
|
||||
</form></li>
|
||||
{% endif %}
|
||||
{% if show_accept %}
|
||||
<li><form method="POST">
|
||||
{{ csrf() }}
|
||||
<input type="hidden" name="action" value="accept" />
|
||||
<button>{{ _('Accept nomination') }}</button>
|
||||
</form></li>
|
||||
{% endif %}
|
||||
</ul></dd>
|
||||
{% endif %}
|
||||
{% if nomination.award %}
|
||||
<dt>Award:</dt>
|
||||
<dd><a href="{{ nomination.award.get_absolute_url() }}">{{ nomination.award }}</a></dd>
|
||||
{% endif %}
|
||||
<dt>Accepted?:</dt>
|
||||
<dd>{{ nomination.accepted and "Yes" or "No" }}</dd>
|
||||
<dt>Approved?:</dt>
|
||||
<dd>{{ nomination.approver and "Yes" or "No" }}</dd>
|
||||
<dt>Nominee:</dt>
|
||||
<dd><a href="{{ nomination.nominee.get_absolute_url() }}">{{ nomination.nominee }}</a></dd>
|
||||
<dt>Nominator:</dt>
|
||||
<dd><a href="{{ nomination.creator.get_absolute_url() }}">{{ nomination.creator }}</a></dd>
|
||||
{% if nomination.approver %}
|
||||
<dt>Approver:</dt>
|
||||
<dd><a href="{{ nomination.approver.get_absolute_url() }}">{{ nomination.approver }}</a></dd>
|
||||
{% endif %}
|
||||
<dt>Created:</dt>
|
||||
<dd>{{ nomination.created }}</dd>
|
||||
<dt>Modified:</dt>
|
||||
<dd>{{ nomination.modified }}</dd>
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
<section class="badge">
|
||||
<h3>Badge</h3>
|
||||
{% include "badger/includes/badge_full.html" %}
|
||||
</section>
|
||||
|
||||
{% endblock %}
|
|
@ -8,10 +8,14 @@ from .feeds import BadgesRecentFeed
|
|||
|
||||
|
||||
urlpatterns = patterns('badger_multiplayer.views',
|
||||
url(r'^create$', 'create',
|
||||
url(r'^;create$', 'create',
|
||||
name='badger_multiplayer.create_badge'),
|
||||
url(r'^badges/(?P<slug>[^/]+)/edit$', 'edit',
|
||||
url(r'^detail/(?P<slug>[^/]+);nominate$', 'nominate_for',
|
||||
name='badger_multiplayer.nominate_for'),
|
||||
url(r'^detail/(?P<slug>[^/]+);edit$', 'edit',
|
||||
name='badger_multiplayer.badge_edit'),
|
||||
url(r'^detail/(?P<slug>[^/]+)/nominations/(?P<id>[^/]+)/?$', 'nomination_detail',
|
||||
name='badger.nomination_detail'),
|
||||
|
||||
url(r'^feeds/(?P<format>[^/]+)/badges/?$', BadgesRecentFeed(),
|
||||
name="badger_multiplayer.feeds.badges_recent"),
|
||||
|
|
|
@ -36,7 +36,8 @@ from badger_multiplayer.models import (Badge, Nomination,
|
|||
NominationApproveNotAllowedException,
|
||||
NominationAcceptNotAllowedException)
|
||||
|
||||
from badger_multiplayer.forms import (BadgeNewForm, BadgeEditForm)
|
||||
from badger_multiplayer.forms import (BadgeNewForm, BadgeEditForm,
|
||||
BadgeSubmitNominationForm)
|
||||
|
||||
|
||||
@require_http_methods(['GET', 'POST'])
|
||||
|
@ -83,3 +84,51 @@ def edit(request, slug):
|
|||
return render_to_response('badger_multiplayer/badge_edit.html', dict(
|
||||
badge=badge, form=form,
|
||||
), context_instance=RequestContext(request))
|
||||
|
||||
|
||||
@require_http_methods(['GET', 'POST'])
|
||||
@login_required
|
||||
def nomination_detail(request, slug, id, format="html"):
|
||||
"""Show details on a nomination, provide for approval and acceptance"""
|
||||
badge = get_object_or_404(Badge, slug=slug)
|
||||
nomination = get_object_or_404(Nomination, badge=badge, pk=id)
|
||||
if not nomination.allows_detail_by(request.user):
|
||||
return HttpResponseForbidden()
|
||||
|
||||
if request.method == "POST":
|
||||
action = request.POST.get('action', '')
|
||||
if action == 'approve_by':
|
||||
nomination.approve_by(request.user)
|
||||
elif action == 'accept':
|
||||
nomination.accept(request.user)
|
||||
return HttpResponseRedirect(reverse(
|
||||
'badger_multiplayer.views.nomination_detail',
|
||||
args=(slug, id)))
|
||||
|
||||
return render_to_response('badger_multiplayer/nomination_detail.html', dict(
|
||||
badge=badge, nomination=nomination,
|
||||
), context_instance=RequestContext(request))
|
||||
|
||||
|
||||
@require_http_methods(['GET', 'POST'])
|
||||
@login_required
|
||||
def nominate_for(request, slug):
|
||||
"""Submit nomination for a badge"""
|
||||
badge = get_object_or_404(Badge, slug=slug)
|
||||
if not badge.allows_nominate_for(request.user):
|
||||
return HttpResponseForbidden()
|
||||
|
||||
if request.method != "POST":
|
||||
form = BadgeSubmitNominationForm()
|
||||
else:
|
||||
form = BadgeSubmitNominationForm(request.POST, request.FILES)
|
||||
if form.is_valid():
|
||||
award = badge.nominate_for(form.cleaned_data['nominee'],
|
||||
request.user)
|
||||
return HttpResponseRedirect(reverse(
|
||||
'badger_multiplayer.views.nomination_detail',
|
||||
args=(badge.slug, award.id, )))
|
||||
|
||||
return render_to_response('badger_multiplayer/badge_nominate_for.html', dict(
|
||||
form=form, badge=badge,
|
||||
), context_instance=RequestContext(request))
|
||||
|
|
Загрузка…
Ссылка в новой задаче