Improvements to admin, claim codes, login
* Fix to ?next parameter in post-login redirect * Simple claim code entry field in the header * Quick hack to stick a QR code on the DeferredAward detail page. * Admin improvements to better handle relations between badges, awards, and deferred awards.
This commit is contained in:
Родитель
a9a849cb7e
Коммит
85f3dc1c6a
|
@ -4,7 +4,12 @@ from django.contrib import admin
|
|||
from django import forms
|
||||
from django.db import models
|
||||
|
||||
from .models import (Badge, Award, Progress)
|
||||
try:
|
||||
from funfactory.urlresolvers import reverse
|
||||
except ImportError, e:
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from .models import (Badge, Award, Progress, DeferredAward)
|
||||
|
||||
|
||||
UPLOADS_URL = getattr(settings, 'BADGER_UPLOADS_URL',
|
||||
|
@ -20,16 +25,49 @@ def show_image(obj):
|
|||
img_url = "%s%s" % (UPLOADS_URL, obj.image)
|
||||
return ('<a href="%s" target="_new"><img src="%s" width="48" height="48" /></a>' %
|
||||
(img_url, img_url))
|
||||
|
||||
show_image.allow_tags = True
|
||||
show_image.short_description = "Image"
|
||||
|
||||
|
||||
class BadgerAdmin(admin.ModelAdmin):
|
||||
def build_related_link(self, model_name, name_single, name_plural, qs):
|
||||
link = '%s?%s' % (
|
||||
reverse('admin:badger_%s_changelist' % model_name, args=[]),
|
||||
'badge__exact=%s' % (self.id)
|
||||
)
|
||||
new_link = '%s?%s' % (
|
||||
reverse('admin:badger_%s_add' % model_name, args=[]),
|
||||
'badge=%s' % (self.id)
|
||||
)
|
||||
count = qs.count()
|
||||
what = (count == 1) and name_single or name_plural
|
||||
return ('<a href="%s">%s %s</a> (<a href="%s">new</a>)' %
|
||||
(link, count, what, new_link))
|
||||
|
||||
list_display = ("title", "slug", "unique", "creator", show_image, "created", )
|
||||
|
||||
def related_deferredawards_link(self):
|
||||
return build_related_link(self, 'deferredaward', 'deferred', 'deferred',
|
||||
self.deferredaward_set)
|
||||
|
||||
related_deferredawards_link.allow_tags = True
|
||||
related_deferredawards_link.short_description = "Deferred Awards"
|
||||
|
||||
|
||||
def related_awards_link(self):
|
||||
return build_related_link(self, 'award', 'award', 'awards',
|
||||
self.award_set)
|
||||
|
||||
related_awards_link.allow_tags = True
|
||||
related_awards_link.short_description = "Awards"
|
||||
|
||||
|
||||
class BadgeAdmin(admin.ModelAdmin):
|
||||
list_display = ("id", "title", show_image, "slug", "unique", "creator",
|
||||
related_awards_link, related_deferredawards_link, "created",)
|
||||
list_display_links = ('id', 'title',)
|
||||
search_fields = ("title", "slug", "image", "description",)
|
||||
filter_horizontal = ('prerequisites', )
|
||||
|
||||
prepopulated_fields = {"slug": ("title",)}
|
||||
formfield_overrides = {
|
||||
models.ManyToManyField: {
|
||||
"widget": forms.widgets.SelectMultiple(attrs={"size": 25})
|
||||
|
@ -37,17 +75,44 @@ class BadgerAdmin(admin.ModelAdmin):
|
|||
}
|
||||
|
||||
|
||||
def badge_link(self):
|
||||
url = reverse('admin:badger_badge_change', args=[self.badge.id])
|
||||
return '<a href="%s">%s</a>' % (url, self.badge)
|
||||
|
||||
badge_link.allow_tags = True
|
||||
badge_link.short_description = 'Badge'
|
||||
|
||||
|
||||
class AwardAdmin(admin.ModelAdmin):
|
||||
|
||||
list_display = (show_unicode, 'badge', 'user', 'creator', show_image, 'created', )
|
||||
|
||||
list_display = (show_unicode, badge_link, show_image, 'user', 'creator',
|
||||
'created', )
|
||||
fields = ('badge', 'user', 'creator', )
|
||||
search_fields = ("badge__title", "badge__slug", "badge__description",)
|
||||
|
||||
|
||||
class ProgressAdmin(admin.ModelAdmin):
|
||||
pass
|
||||
|
||||
|
||||
admin.site.register(Badge, BadgerAdmin)
|
||||
admin.site.register(Award, AwardAdmin)
|
||||
admin.site.register(Progress, ProgressAdmin)
|
||||
def claim_code_link(self):
|
||||
return '<a href="%s">%s</a>' % (self.get_claim_url(), self.claim_code)
|
||||
|
||||
claim_code_link.allow_tags = True
|
||||
claim_code_link.short_description = "Claim Code"
|
||||
|
||||
|
||||
class DeferredAwardAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', claim_code_link, badge_link, 'email', 'reusable',
|
||||
'creator', 'created', 'modified',)
|
||||
list_display_links = ('id',)
|
||||
list_filter = ('reusable', )
|
||||
fields = ('badge', 'claim_code', 'email', 'reusable', 'description',)
|
||||
readonly_fields = ('created', 'modified')
|
||||
search_fields = ("badge__title", "badge__slug", "badge__description",)
|
||||
|
||||
|
||||
for x in ((Badge, BadgeAdmin),
|
||||
(Award, AwardAdmin),
|
||||
(Progress, ProgressAdmin),
|
||||
(DeferredAward, DeferredAwardAdmin),):
|
||||
admin.site.register(*x)
|
||||
|
|
|
@ -5,6 +5,7 @@ from django.conf import settings
|
|||
|
||||
from django.contrib.auth.models import SiteProfileNotAvailable
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.utils.html import conditional_escape
|
||||
|
||||
try:
|
||||
from commons.urlresolvers import reverse
|
||||
|
@ -61,3 +62,13 @@ def user_awards(user):
|
|||
@register.function
|
||||
def user_badges(user):
|
||||
return Badge.objects.filter(creator=user)
|
||||
|
||||
|
||||
@register.function
|
||||
def qr_code_image(value, alt=None, size=150):
|
||||
url = conditional_escape("http://chart.apis.google.com/chart?%s" % \
|
||||
urllib.urlencode({'chs':'%sx%s' % (size, size), 'cht':'qr', 'chl':value, 'choe':'UTF-8'}))
|
||||
alt = conditional_escape(alt or value)
|
||||
|
||||
return Markup(u"""<img class="qrcode" src="%s" width="%s" height="%s" alt="%s" />""" %
|
||||
(url, size, size, alt))
|
||||
|
|
|
@ -267,21 +267,31 @@ class Badge(models.Model):
|
|||
"""Representation of a badge"""
|
||||
objects = BadgeManager()
|
||||
|
||||
title = models.CharField(max_length=255, blank=False, unique=True)
|
||||
slug = models.SlugField(blank=False, unique=True)
|
||||
description = models.TextField(blank=True)
|
||||
title = models.CharField(max_length=255, blank=False, unique=True,
|
||||
help_text="Short, descriptive title")
|
||||
slug = models.SlugField(blank=False, unique=True,
|
||||
help_text="Very short name, for use in URLs and links")
|
||||
description = models.TextField(blank=True,
|
||||
help_text="Longer description of the badge and its criteria")
|
||||
image = models.ImageField(blank=True, null=True,
|
||||
storage=BADGE_UPLOADS_FS,
|
||||
upload_to=mk_upload_to('image','png'))
|
||||
storage=BADGE_UPLOADS_FS, upload_to=mk_upload_to('image','png'),
|
||||
help_text="Upload an image to represent the badge")
|
||||
prerequisites = models.ManyToManyField('self', symmetrical=False,
|
||||
blank=True, null=True)
|
||||
unique = models.BooleanField(default=False)
|
||||
blank=True, null=True,
|
||||
help_text="When all 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.
|
||||
unique = models.BooleanField(default=False,
|
||||
help_text="Should only one award of this badge be allowed per "
|
||||
"person?")
|
||||
creator = models.ForeignKey(User, blank=True, null=True)
|
||||
created = models.DateTimeField(auto_now_add=True, blank=False)
|
||||
modified = models.DateTimeField(auto_now=True, blank=False)
|
||||
|
||||
class Meta:
|
||||
unique_together = ('title', 'slug')
|
||||
ordering = ['-modified', '-created']
|
||||
|
||||
get_permissions_for = get_permissions_for
|
||||
|
||||
|
@ -457,6 +467,9 @@ class Award(models.Model):
|
|||
|
||||
get_permissions_for = get_permissions_for
|
||||
|
||||
class Meta:
|
||||
ordering = ['-modified', '-created']
|
||||
|
||||
def __unicode__(self):
|
||||
by = self.creator and (' by %s' % self.creator) or ''
|
||||
return u'Award of %s to %s%s' % (self.badge, self.user, by)
|
||||
|
@ -682,12 +695,14 @@ class DeferredAward(models.Model):
|
|||
reusable = models.BooleanField(default=False)
|
||||
email = models.EmailField(blank=True, null=True, db_index=True)
|
||||
claim_code = models.CharField(max_length=CLAIM_CODE_LENGTH,
|
||||
default=make_random_code, editable=False, unique=True,
|
||||
db_index=True)
|
||||
default=make_random_code, unique=True, db_index=True)
|
||||
creator = models.ForeignKey(User, blank=True, null=True)
|
||||
created = models.DateTimeField(auto_now_add=True, blank=False)
|
||||
modified = models.DateTimeField(auto_now=True, blank=False)
|
||||
|
||||
class Meta:
|
||||
ordering = ['-modified', '-created']
|
||||
|
||||
def get_claim_url(self):
|
||||
"""Get the URL to a page where this DeferredAward can be claimed."""
|
||||
return reverse('badger.views.claim_deferred_award',
|
||||
|
|
|
@ -20,6 +20,8 @@ urlpatterns = patterns('badger.views',
|
|||
name='badger.award_detail'),
|
||||
url(r'^claim/(?P<claim_code>[^/]+)/?$', 'claim_deferred_award',
|
||||
name='badger.claim_deferred_award'),
|
||||
url(r'^claim/?$', 'claim_deferred_award',
|
||||
name='badger.claim_deferred_award_form'),
|
||||
url(r'^badge/(?P<slug>[^/]+)/award', 'award_badge',
|
||||
name='badger.award_badge'),
|
||||
url(r'^badge/(?P<slug>[^\.]+)\.json$', 'detail',
|
||||
|
|
|
@ -163,8 +163,10 @@ def award_detail(request, slug, id, format="html"):
|
|||
|
||||
@require_http_methods(['GET', 'POST'])
|
||||
@login_required
|
||||
def claim_deferred_award(request, claim_code):
|
||||
def claim_deferred_award(request, claim_code=None):
|
||||
"""Deferred award detail view"""
|
||||
if not claim_code:
|
||||
claim_code = request.GET.get('code', '').strip()
|
||||
deferred_award = get_object_or_404(DeferredAward, claim_code=claim_code)
|
||||
|
||||
if request.method == "POST":
|
||||
|
|
Загрузка…
Ссылка в новой задаче