diff --git a/.gitignore b/.gitignore index abc4b21..aedb730 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.pyc -htdocs/media/ +htdocs/ +static/ media/ .idea .gitignore diff --git a/.idea/encodings.xml b/.idea/encodings.xml index d821048..f758959 100644 --- a/.idea/encodings.xml +++ b/.idea/encodings.xml @@ -1,4 +1,6 @@ - + + + \ No newline at end of file diff --git a/aggregator/admin.py b/aggregator/admin.py index 49b7c84..dd7243f 100644 --- a/aggregator/admin.py +++ b/aggregator/admin.py @@ -1,6 +1,8 @@ from django.contrib import admin + from models import Feed, FeedItem + admin.site.register( Feed, list_display=["title", "public_url", "last_update", 'is_functional'], diff --git a/aggregator/feeds.py b/aggregator/feeds.py index f152dd9..463f753 100644 --- a/aggregator/feeds.py +++ b/aggregator/feeds.py @@ -1,4 +1,5 @@ import django.contrib.syndication.views + from .models import FeedItem diff --git a/aggregator/management/commands/update-feeds.py b/aggregator/management/commands/update-feeds.py index 4760c25..7e71b17 100644 --- a/aggregator/management/commands/update-feeds.py +++ b/aggregator/management/commands/update-feeds.py @@ -3,9 +3,10 @@ Update feeds for Django community page. Requires Mark Pilgrim's excellent Universal Feed Parser (http://feedparser.org) """ -from aggregator.models import Feed from django.core.management.base import BaseCommand +from aggregator.models import Feed + class Command(BaseCommand): help = "Updates all RSS Feeds" diff --git a/aggregator/models.py b/aggregator/models.py index 892a286..ad22620 100644 --- a/aggregator/models.py +++ b/aggregator/models.py @@ -5,14 +5,16 @@ Created on 05.02.2011 """ from datetime import datetime, timedelta +import HTMLParser +import urllib2 + from django.conf import settings from django.contrib.sites.models import Site from django.utils import timezone -from utils.html5 import models -import HTMLParser import django.db.models import feedparser -import urllib2 + +from utils.html5 import models class FeedManager(django.db.models.Manager): @@ -35,7 +37,7 @@ class FeedItemManager(django.db.models.Manager): return self.select_related().filter(feed__site=site)[:max_items] -class Feed(models.Model): +class Feed(django.db.models.Model): title = models.CharField(max_length=500) site = models.ForeignKey(Site) feed_url = models.URLField(unique=True, max_length=255) @@ -51,7 +53,8 @@ class Feed(models.Model): parsed_feed = feedparser.parse(self.feed_url) html_parser = HTMLParser.HTMLParser() - if parsed_feed.bozo and type(parsed_feed.bozo_exception) == urllib2.URLError: + if parsed_feed.bozo and type( + parsed_feed.bozo_exception) == urllib2.URLError: self.is_functional = False return self.save() @@ -68,16 +71,22 @@ class Feed(models.Model): feed_entry.get("content", u"") )) ) - date_modified = feed_entry.get("published_parsed", parsed_feed.get("published_parsed", timezone.now)) - date_modified = timezone.make_aware(datetime(*date_modified[:6]), timezone.get_current_timezone()) + date_modified = feed_entry.get( + "published_parsed", + parsed_feed.get("published_parsed", + timezone.now)) + date_modified = timezone.make_aware( + datetime(*date_modified[:6]), + timezone.get_current_timezone()) - feed_item, updated = self.feed_items.get_or_create(guid=guid, - defaults={ - 'title': title, - 'link': link, - 'summary': summary, - 'date_modified': date_modified - }) + feed_item, updated = self.feed_items.get_or_create( + guid=guid, + defaults={ + 'title': title, + 'link': link, + 'summary': summary, + 'date_modified': date_modified + }) feed_item.save() self.last_update = timezone.now() return self.save() @@ -86,7 +95,7 @@ class Feed(models.Model): ordering = ("title",) -class FeedItem(models.Model): +class FeedItem(django.db.models.Model): feed = models.ForeignKey(Feed, related_name='feed_items') title = models.CharField(max_length=500) link = models.URLField(max_length=500) diff --git a/aggregator/sitemaps.py b/aggregator/sitemaps.py index e8ddf2d..a447596 100644 --- a/aggregator/sitemaps.py +++ b/aggregator/sitemaps.py @@ -1,7 +1,9 @@ from django.contrib.sitemaps import Sitemap + from models import FeedItem + # noinspection PyMethodMayBeStatic class FeedItemSitemap(Sitemap): changefreq = "never" diff --git a/aggregator/templatetags/aggregator.py b/aggregator/templatetags/aggregator.py index 0e7a5cd..d9f4d79 100644 --- a/aggregator/templatetags/aggregator.py +++ b/aggregator/templatetags/aggregator.py @@ -1,9 +1,9 @@ from django import template + from models import Feed class FeedListNode(template.Node): - def __init__(self, varname): self.varname = varname @@ -26,5 +26,6 @@ def do_get_feed_list(parser, token): "First argument to '%s' tag must be 'as'" % bits[0] return FeedListNode(bits[2]) + register = template.Library() register.tag('get_feed_list', do_get_feed_list) diff --git a/cleanup.sh b/cleanup.sh index 08081c5..468fa96 100755 --- a/cleanup.sh +++ b/cleanup.sh @@ -1,12 +1,23 @@ #!/bin/sh echo "aktualisiere Übersetzungen..." -cd src -./manage.py makemessages -l de -./manange.py compilemessages -a +unset DJANGO_SETTINGS_MODULE +for dir in * + do + if [ -d $dir/locale ] + then + echo -n "$dir: " + cd $dir + django-admin.py makemessages -l de + cd .. + fi + done +sleep 5s +export DJANGO_SETTINGS_MODULE="kasu.settings.production" +./manage.py compilemessages echo "lösche den Python Compiler Cache..." find . -name "*.pyc" -exec rm -rf {} \; -touch kasu.wsgi ./manage.py collectstatic --noinput ./manage.py generateimages +touch kasu/wsgi.py diff --git a/gallery/forms.py b/gallery/forms.py index e731f3d..ae00c98 100644 --- a/gallery/forms.py +++ b/gallery/forms.py @@ -3,11 +3,13 @@ Created on 03.10.2011 @author: christian """ -from . import models from django import forms from django.utils.translation import ugettext as _ from django.contrib.auth import get_user_model -from utils.html5.widgets import DateTimeInput + +from . import models +from events.models import Event + user_query = get_user_model().objects.all() @@ -15,8 +17,8 @@ user_query = get_user_model().objects.all() class PhotoUploadForm(forms.Form): error_css_class = 'error' required_css_class = 'required' - photographer = forms.ModelChoiceField(user_query, required=True,) - event = forms.ModelChoiceField(models.Event.objects.all(), required=True,) + photographer = forms.ModelChoiceField(user_query, required=True, ) + event = forms.ModelChoiceField(Event.objects.all(), required=True, ) upload = forms.FileField( label=_('Images'), required=True, @@ -38,20 +40,3 @@ class EditPhotoForm(forms.ModelForm): fields = ('event', 'name', 'description', 'photographer', 'anchor_horizontal', 'anchor_vertical', 'created_date', 'on_startpage') - - -class EventForm(forms.ModelForm): - error_css_class = 'error' - required_css_class = 'required' - - start = forms.DateTimeField( - label=_('start'), required=True, - widget=DateTimeInput() # widget=SplitDateTimeWidget() - ) - end = forms.DateTimeField( - label=_('end'), required=False, - widget=DateTimeInput() # widget=SplitDateTimeWidget() - ) - - class Meta(object): - model = models.Event diff --git a/gallery/models.py b/gallery/models.py index 6217ccc..929d3bd 100644 --- a/gallery/models.py +++ b/gallery/models.py @@ -5,29 +5,11 @@ import os from django.conf import settings from django.core.urlresolvers import reverse from django.db import models -from django.template.defaultfilters import slugify -from django.utils.timezone import now from django.utils.translation import ugettext as _ -from imagekit import ImageSpec -import imagekit -from imagekit.models import ImageSpecField -from pilkit import processors import pyexiv2 -from utils import COUNTRIES, OverwriteStorage - - -CHOICES_HORIZONTAL = ( - (0.00000001, _('left')), - (0.5, _('center')), - (1, _('right')) -) - -CHOICES_VERTICAL = ( - (0.00000001, _('top')), - (0.5, _('middle')), - (1, _('bottom')) -) +from utils import OverwriteStorage +from kasu import image_models def get_upload_path(instance, filename): @@ -42,231 +24,10 @@ def get_upload_path(instance, filename): @type filename: String """ extension = filename[filename.rfind('.') + 1:] - if isinstance(instance, Event): - if instance.id: - return "events/%s.%s" % (instance.id, extension) - else: - return "events/%s.%s" % (slugify(instance.name), extension) - elif isinstance(instance, Location): - if instance.id: - return "events/location/%s.%s" % (instance.id, extension) - else: - return "events/location/%s.%s" % (instance.id, extension) - elif isinstance(instance, Photo): + if isinstance(instance, Photo): return "events/%s/%s" % (instance.event.id, filename) -def post_save_image(sender, instance=None, created=False, raw=False, **kwargs): - """ - Reganerate the images. - """ - os.remove(instance.display.path) - os.remove(instance.callout.path) - os.remove(instance.thumbnail.path) - - """ - instance.callout.generate(force=True) - instance.display.generate(force=True) - instance.thumbnail.generate(force=True) - """ - - -class CalloutImage(ImageSpec): - format = 'PNG' - width = 940 - height = 300 - - @property - def processors(self): - model, field_name = imagekit.utils.get_field_info(self.source) # @UnusedVariable @IgnorePep8 - anchor = model.get_anchor() - if anchor: - return [processors.Transpose(), processors.ResizeToFill( - width=self.width, - height=self.height, anchor=anchor - )] - else: - return [processors.Transpose(), processors.SmartResize( - width=self.width, - height=self.height - )] - - -class DisplayImage(ImageSpec): - format = 'PNG' - processors = [processors.Transpose(), - processors.ResizeToFit(width=940, height=940, upscale=False)] - - -class ThumbnailImage(CalloutImage): - format = 'PNG' - width = 140 - height = 140 - - -imagekit.register.generator('kasu:image:callout', CalloutImage) -imagekit.register.generator('kasu:image:display', DisplayImage) -imagekit.register.generator('kasu:image:thumbnail', ThumbnailImage) - - -class ImageModel(models.Model): - callout = ImageSpecField(source='image', id='kasu:image:callout') - display = ImageSpecField(source='image', id='kasu:image:display') - thumbnail = ImageSpecField(source='image', id='kasu:image:thumbnail') - - def get_anchor(self): - try: - anchor_horizontal = getattr(self, 'anchor_horizontal') - anchor_vertical = getattr(self, 'anchor_vertical') - except AttributeError: - return None - if anchor_horizontal and anchor_vertical: - return self.anchor_horizontal, self.anchor_vertical - else: - return None - - class Meta: - abstract = True - - -class EventManager(models.Manager): - def current_event(self): - try: - current = self.filter(start__lte=now()) - current = current.filter(end__gte=now()) - return current.order_by('start', 'end')[0] - except: - return None - - def next_event(self): - try: - return self.filter(start__gt=now()).order_by('start', 'end')[0] - except: - return None - - def archive(self): - return self.filter(start__lt=now()) - - def upcoming(self, limit=3): - result = self.filter(start__gt=now()).order_by('start', 'end') - if limit: - return result[1:(limit + 1)] - else: - return result - - -class Event(ImageModel): - name = models.CharField(_('Name'), max_length=255) - description = models.TextField(_("Description"), blank=True) - location = models.ForeignKey('Location') - start = models.DateTimeField(_('Start')) - end = models.DateTimeField(_('End'), blank=True, null=True) - url = models.URLField(_('Homepage'), blank=True) - image = models.ImageField(_("Image"), upload_to=get_upload_path, - storage=OverwriteStorage(), blank=True, null=True) - is_tournament = models.BooleanField(_('Tournament'), default=False, - help_text=_(u'This event is a tournament, different rules apply for \ - the kyu ranking.')) - photo_count = models.PositiveIntegerField(default=0, editable=False) - event_series = models.ForeignKey('Event', blank=True, null=True, - on_delete=models.SET_NULL, editable=False, - verbose_name=_('Event Series'), - help_text=_(u'Wenn dieser Event zu einer Veranstaltungsreihe gehört \ - werden Ort, Beschreibung, Bild und Homepage von dem hier angegebenen \ - Event übernommen.')) - objects = EventManager() - - class Meta(object): - verbose_name = _('Event') - verbose_name_plural = _('Events') - ordering = ('-start', '-end',) - - def __unicode__(self): - try: - return "%(name)s (%(date)s)" % {'name': self.name, - 'date': self.start.date()} - except: - return "New Event Model" - - def get_absolute_url(self): - kwargs = { - 'pk': self.id, - 'year': self.start.strftime('%Y'), - 'month': self.start.strftime('%m') - } - return reverse('event-detail', kwargs=kwargs) - - def get_edit_url(self): - kwargs = { - 'pk': self.id, - 'year': self.start.strftime('%Y'), - 'month': self.start.strftime('%m') - } - return reverse('event-form', kwargs=kwargs) - - def get_callout(self): - if self.image: - return self.callout - elif self.photo_set.count(): - return self.photo_set.all().order_by('?')[0].callout - elif self.location.image: - return self.location.callout - else: - return None - - def get_thumbnail(self): - if self.image: - return self.thumbnail - elif self.photo_set.count(): - return self.photo_set.all().order_by('?')[0].thumbnail - elif self.location.image: - return self.location.thumbnail - else: - return None - - def save(self, **kwargs): - if self.event_series: - master_event = self.event_series - self.description = master_event.description - self.location = master_event.location - self.url = master_event.url - self.image = master_event.image - self.photo_count = self.photo_set.count() - models.Model.save(self, **kwargs) - - # Update the rest of the event series: - for sub_event in Event.objects.filter(event_series=self): - sub_event.save() - - # Update the Hanchans if necesery: - for hanchan in self.hanchan_set.all(): - hanchan.save() - - -class Location(ImageModel): - name = models.CharField(_("Name"), max_length=200) - description = models.TextField(_("Description"), blank=True) - image = models.ImageField(_("Image"), upload_to=get_upload_path, - storage=OverwriteStorage(), blank=True, null=True) - url = models.URLField(_('Homepage'), blank=True) - postal_code = models.CharField(_('Postal Code'), max_length=6) - street_address = models.CharField(_('Street Address'), max_length=127) - locality = models.CharField(_('Locality'), max_length=127) - country = models.CharField(_('Country'), max_length=2, choices=COUNTRIES) - - class Meta(object): - verbose_name = _('Venue') - verbose_name_plural = _('Venues') - - def __unicode__(self): - return self.name - - @property - def address(self): - address = (self.street_address, self.locality, self.country,) - return ','.join(address) - - class PhotoManager(models.Manager): def get_random(self, startpage=True): if startpage: @@ -279,26 +40,26 @@ class PhotoManager(models.Manager): return Photo() -class Photo(ImageModel): +class Photo(image_models.ImageModel): name = models.CharField(_("Name"), max_length=100, blank=True) image = models.ImageField(_("Image"), upload_to=get_upload_path, storage=OverwriteStorage()) anchor_horizontal = models.FloatField( _('horizontal Anchorpoint'), - choices=CHOICES_HORIZONTAL, + choices=image_models.CHOICES_HORIZONTAL, blank=True, null=True, help_text='Der Ankerpunkt ist der interessante Teil des Bildes,\ welcher nie abgeschnitten werden darf' ) anchor_vertical = models.FloatField( _('vertical Anchorpoint'), - choices=CHOICES_VERTICAL, + choices=image_models.CHOICES_VERTICAL, blank=True, null=True, help_text='Wenn kein Ankerpunkt von Hand (horizontal und vertikal)\ festgelegt wird, versucht die Software diesen selbst zu erraten.' ) - event = models.ForeignKey(Event) + event = models.ForeignKey('events.Event') description = models.TextField( _("Description"), max_length=300, @@ -321,10 +82,12 @@ class Photo(ImageModel): orientation = 1 class Meta: + get_latest_by = "created_date" + ordering = ["created_date"] + db_table = 'events_photo' verbose_name = _('Event Image') verbose_name_plural = _('Event Images') - ordering = ["created_date"] - get_latest_by = "created_date" + def __unicode__(self): return os.path.basename(self.image.name) @@ -395,9 +158,14 @@ class Photo(ImageModel): Triggers to save related Event to save. This should force an update for the denormalized Photo count. """ - ImageModel.save(self, **kwargs) + super(Photo, self).save() self.save_metadata() - self.event.save() -models.signals.post_save.connect(post_save_image, sender=Photo) +def update_event(sender, instance=None, created=False, raw=False, **kwargs): + image_models.regenerate_image_cache(sender, instance=instance) + instance.event.save() + + +models.signals.post_save.connect(update_event, sender=Photo) +models.signals.post_delete.connect(update_event, sender=Photo) diff --git a/gallery/templates/gallery/photo_confirm_delete.html b/gallery/templates/gallery/photo_confirm_delete.html index 50475f9..ba444c1 100644 --- a/gallery/templates/gallery/photo_confirm_delete.html +++ b/gallery/templates/gallery/photo_confirm_delete.html @@ -1,4 +1,4 @@ -{% extends "base.html" %} +{% extends "events/event_detail.html" %} {% load i18n comments %} {% block maincontent %} diff --git a/gallery/templates/gallery/photo_detail.html b/gallery/templates/gallery/photo_detail.html index aae31b2..e7392b5 100644 --- a/gallery/templates/gallery/photo_detail.html +++ b/gallery/templates/gallery/photo_detail.html @@ -1,4 +1,4 @@ -{% extends "events/photo_list.html" %} +{% extends "gallery/photo_list.html" %} {% load i18n comments %} {% block title %} {{ photo.name }} - {{ photo.event.name }} {% endblock %} @@ -22,35 +22,36 @@ {% endif %} +

{{ photo.description }}

+ - {% if perms.events.change_photo %} + +{% endblock %} + +{% block comment %} + {% render_comment_list for photo %} + {% render_comment_form for photo %} +{% endblock %} + +{% block buttonbar %} +{% if perms.events.change_photo %}
{% csrf_token %} -
- {% include "form.html" %}

{% trans 'download' %}

-
- {% else %} -

{{ photo.description }}

- - - {% endif %} - - {% render_comment_list for photo %} - {% render_comment_form for photo %} +{% endif %} {% endblock %} diff --git a/gallery/templates/gallery/photo_upload.html b/gallery/templates/gallery/photo_upload.html index 312e06c..ea86dcb 100644 --- a/gallery/templates/gallery/photo_upload.html +++ b/gallery/templates/gallery/photo_upload.html @@ -1,4 +1,4 @@ -{% extends "events/photo_gallery.html" %} +{% extends "events/event_detail.html" %} {% load i18n comments %} {% block maincontent %} diff --git a/gallery/urls.py b/gallery/urls.py index e69de29..174fdbd 100644 --- a/gallery/urls.py +++ b/gallery/urls.py @@ -0,0 +1,18 @@ +# -*- encoding: utf-8 -*- +from django.conf.urls import patterns, url + +from .views import * + +urlpatterns = patterns( + '', + url(r'^$', EventGallery.as_view(), name='event-gallery'), + url(r'^(?P[\d]+)/$', EventPhotoList.as_view(), + name='event-photo-list'), + url(r'^(?P[\d]+)/upload/$', EventPhotoUpload.as_view(), + name='event-photo-upload'), + url(r'^(?P[\d]+)/(?P[\d]+)/$', EventPhoto.as_view(), + name='event-photo'), + url(r'^delete/(?P[\d]+)/$', DeleteEventPhoto.as_view(), + name='delete-event-photo'), + url(r'^upload/$', EventPhotoUpload.as_view(), name='event-photo-upload'), +) \ No newline at end of file diff --git a/gallery/views.py b/gallery/views.py index 7b28829..a70e921 100644 --- a/gallery/views.py +++ b/gallery/views.py @@ -5,159 +5,55 @@ from datetime import timedelta from django.contrib.auth.decorators import permission_required from django.contrib.auth import get_user_model from django.core.urlresolvers import reverse -from django.http import HttpResponse, Http404 +from django.http import Http404 from django.shortcuts import redirect from django.utils import timezone from django.utils.decorators import method_decorator from django.utils.translation import ugettext as _ from django.views import generic -from icalendar import Calendar, Event import pyexiv2 -from utils.mixins import PermissionRequiredMixin - -from . import models, forms +from events.models import Event +from .models import Photo +from . import forms class DeleteEventPhoto(generic.DeleteView): - model = models.Photo - """ - def get_object(self, queryset=None): - return models.Photo.objects.get(pk=self.kwargs['pk']) - """ + model = Photo def get_success_url(self): return reverse('event-photo-list', args=[self.object.event.id]) + def get_context_data(self, **kwargs): + context = super(DeleteEventPhoto, self).get_context_data() + context['event'] = self.object.event + return context + @method_decorator(permission_required('events.delete_photo')) def dispatch(self, *args, **kwargs): return super(DeleteEventPhoto, self).dispatch(*args, **kwargs) -class EventArchiveIndex(generic.ArchiveIndexView): - allow_empty = True - context_object_name = 'event_list' - date_field = 'start' - model = models.Event - queryset = model.objects.all() - paginate_by = 15 - - - def get_context_data(self, **kwargs): - context = generic.ArchiveIndexView.get_context_data(self, **kwargs) - context['is_archive'] = True - return context - - -class EventArchiveMonth(generic.MonthArchiveView): - date_field = 'start' - make_object_list = True - model = models.Event - month_format = '%m' - paginate_by = 15 - template_name = 'events/event_archive.html' - - def get_context_data(self, **kwargs): - context = generic.MonthArchiveView.get_context_data(self, **kwargs) - context['is_archive'] = True - return context - - -class EventArchiveYear(generic.YearArchiveView): - date_field = 'start' - make_object_list = True - model = models.Event - paginate_by = 15 - template_name = 'events/event_archive.html' - year_format = '%Y' - - def get_context_data(self, **kwargs): - context = generic.YearArchiveView.get_context_data(self, **kwargs) - context['is_archive'] = True - return context - - -class EventDetail(generic.DetailView): - model = models.Event - - def get_context_data(self, **kwargs): - context = generic.DetailView.get_context_data(self, **kwargs) - context['form'] = forms.PhotoUploadForm(initial={'event': self.object, 'photographer': self.request.user}) - return context - - -class EventForm(PermissionRequiredMixin, generic.UpdateView): - form_class = forms.EventForm - permission_required = 'events.add_event' - - def get_object(self, queryset=None): - """ - If an id has been submitted, try return the existing Event for an update, - else creates a new one. - @param queryset: - """ - if self.kwargs.get('pk'): - event = models.Event.objects.get(pk=self.kwargs['pk']) - if event.event_series: - return event.event_series - else: - return event - else: - return models.Event() - - class EventGallery(generic.ListView): - template_name = 'events/photo_gallery.html' - queryset = models.Event.objects.filter(start__lt=timezone.now(), photo_count__gt=0) + template_name = 'gallery/photo_gallery.html' + queryset = Event.objects.filter(start__lt=timezone.now(), photo_count__gt=0) paginate_by = 12 -class EventListIcal(generic.View): - """ - Generates an returns an iCal File with all upcoming events. - """ - - def add_event(self, event): - ics_event = Event() - dtstart = timezone.localtime(event.start) - dtend = timezone.localtime(event.end) - - ics_event.add('DTSTART', dtstart) - ics_event.add('SUMMARY', event.name) - ics_event.add('DESCRIPTION', event.description) - ics_event.add('LOCATION', event.location.address) - ics_event.add('URL', 'http://www.kasu.at' + event.get_absolute_url()) - ics_event['UID'] = 'event-%d@www.kasu.at' % event.pk - ics_event.add('PRIORITY', 5) - if event.end: - ics_event.add('DTEND', dtend) - self.calendar.add_component(ics_event) - - def get(self, request, *args, **kwargs): - response = HttpResponse(mimetype="text/calendar; charset=UTF-8") - self.calendar = Calendar() - self.calendar.add('prodid', 'http://www.kasu.at/') - self.calendar.add('version', '2.0') - for event in models.Event.objects.upcoming(limit=None): - self.add_event(event) - response.write(self.calendar.to_ical()) - return response - - class EventPhoto(generic.UpdateView): form_class = forms.EditPhotoForm - model = models.Photo - template_name = 'events/photo_detail.html' + model = Photo + template_name = 'gallery/photo_detail.html' def get_context_data(self, **kwargs): context = super(EventPhoto, self).get_context_data() - event = models.Event.objects.get(id=self.kwargs['event']) - context['event'] = event + context['event'] = self.object.event return context def post(self, request, *args, **kwargs): - if request.POST.get('rotate') and request.user.has_perm('events.change_photo'): - photo = models.Photo.objects.get(pk=kwargs['pk']) + if request.POST.get('rotate') and request.user.has_perm( + 'events.change_photo'): + photo = Photo.objects.get(pk=kwargs['pk']) photo.rotate(request.POST['rotate']) # return redirect(photo.get_absolute_url()) return self.get(request) @@ -172,20 +68,21 @@ class EventPhotoList(generic.ListView): def get_context_data(self, **kwargs): context = generic.ListView.get_context_data(self, **kwargs) context['event'] = self.event - context['form'] = forms.PhotoUploadForm(initial={'event': self.event, 'photographer': self.request.user}) + context['form'] = forms.PhotoUploadForm( + initial={'event': self.event, 'photographer': self.request.user}) return context def get_queryset(self): try: - self.event = models.Event.objects.get(id=self.kwargs['event']) - return models.Photo.objects.filter(event=self.event) - except models.Event.DoesNotExist: + self.event = Event.objects.get(id=self.kwargs['event']) + return Photo.objects.filter(event=self.event) + except Event.DoesNotExist: raise Http404(_('Event does not exist')) class EventPhotoUpload(generic.FormView): form_class = forms.PhotoUploadForm - template_name = 'events/photo_upload.html' + template_name = 'gallery/photo_upload.html' @method_decorator(permission_required('events.add_photo')) def dispatch(self, *args, **kwargs): @@ -193,7 +90,7 @@ class EventPhotoUpload(generic.FormView): def get_context_data(self, **kwargs): context = generic.FormView.get_context_data(self, **kwargs) - context['event_list'] = models.Event.objects.archive()[:12] + context['event_list'] = Event.objects.archive()[:12] return context def get_initial(self): @@ -208,14 +105,16 @@ class EventPhotoUpload(generic.FormView): """ """ - self.event = models.Event.objects.get(id=self.request.REQUEST.get('event')) - photographer = self.request.POST.get('photographer', self.request.user.id) + self.event = Event.objects.get( + id=self.request.REQUEST.get('event')) + photographer = self.request.POST.get('photographer', + self.request.user.id) photographer = get_user_model().objects.get(id=photographer) self.counter = 1 for upload in self.request.FILES.getlist('upload'): name = upload.name created_date, description = self.read_exif(upload) - photo = models.Photo( + photo = Photo( event=self.event, photographer=photographer, image=upload, @@ -241,7 +140,3 @@ class EventPhotoUpload(generic.FormView): description = '' return created_date, description - -class UpcomingEvents(generic.ListView): - queryset = models.Event.objects.upcoming(limit=None) - paginate_by = 16 diff --git a/kasu/static/css/common.css b/kasu/static/css/common.css index 7f0584d..bb77e00 100644 --- a/kasu/static/css/common.css +++ b/kasu/static/css/common.css @@ -299,46 +299,28 @@ ul.info li { } /** PAGINATOR **/ -.paginator { - clear: both; - border: 1px solid #d3d7cf; - border-radius: 10px; - text-align: center; - background-color: #f9f9f9; - box-shadow: inset 0px 1px 0px 0px #ffffff; - background: -webkit-gradient(linear, left top, left bottom, color-stop(0.05, #f9f9f9 - ), color-stop(1, #e9e9e9) ); - background: -moz-linear-gradient(center top, #f9f9f9 5%, #e9e9e9 100%); - padding: 4px 10px 2px 10px; +.pagination { + text-align:center } -.paginator a, .paginator .current { +.pagination a, .pagination .current, .pagination .next, .pagination .previous { display: inline-block; - margin: 0px 2px; - padding: 2px; - min-width: 17px; - color: #2e3436; - text-decoration: none; - border-radius: 5px; + text-decoration: none; + padding: 0 0.5em 0 0.5em; } -.paginator .current { - border: none; - color: #a40000; - background: #fff; - border-radius: 5px; -} - -.paginator .next { - display: inline-block; +.pagination .next { float: right; + background: none; } -.paginator .prev { - display: inline-block; + +.pagination .previous { float: left; + background: none; } + .center { text-align: center; } @@ -403,4 +385,4 @@ ul.tabs li.active a {border-bottom: 3px solid #bc0a19; color: #bc0a19} } fieldset.comment {padding: 0} fieldset.comment legend {margin-left: 15px} -fieldset.comment .buttonbar {margin: 0; width: 100%} \ No newline at end of file +fieldset.comment .buttonbar {margin: 0; width: 100%} diff --git a/kasu/static/css/desktop.css b/kasu/static/css/desktop.css index c6c54ff..24167fd 100644 --- a/kasu/static/css/desktop.css +++ b/kasu/static/css/desktop.css @@ -136,14 +136,14 @@ ul.main_menu {padding:0px;} width: 920px; } -#navigation { +#navigation, .pagination { clear: both; background: url(../img/navigation-bg.png) no-repeat left top; height: 56px; list-style: none; margin: 0 auto; - padding: 8px 0 0 30px; - width: 920px; + padding: 8px 35px 0px 25px; + width: 900px; } #navigation a { @@ -434,6 +434,23 @@ ul.tabs li.active a { text-shadow: 1px 1px 0px #98231a; } +.pagination a, .pagination .current, .pagination .next, .pagination .previous { + display: inline-block; + padding: 2px; + color: #FFF; + font-weight: bold; + height: 33px; + text-decoration: none; + padding: 17px 0.5em 0 0.5em; +} + +.pagination .current { + color: #a40000; +} + +.pagination .disabled {color: #ccc} + + img.avatar { border: none; box-shadow: 2px 2px 2px #888; diff --git a/kasu/static/css/mobile.css b/kasu/static/css/mobile.css index a900b98..77aa61f 100644 --- a/kasu/static/css/mobile.css +++ b/kasu/static/css/mobile.css @@ -337,6 +337,12 @@ fieldset ul li { } ul.tabs {margin-top:1em;} -.paginator {clear:both;} +.pagination {clear:both;} +.pagination a, .pagination .current, .pagination .next, .pagination .previous { + display: inline-block; + text-decoration: none; + padding: 0 0.5em 0 0.5em; +} + .gallery {float: left; width:150px; height:150px; margin: 10px;} -.gallery h3 {font-size: 12pt;} \ No newline at end of file +.gallery h3 {font-size: 12pt;} diff --git a/kasu/templates/paginator.html b/kasu/templates/paginator.html index 59b09d2..7db6853 100644 --- a/kasu/templates/paginator.html +++ b/kasu/templates/paginator.html @@ -1,20 +1,22 @@ {% load i18n %} -
-{% if page_obj.has_previous %} - -{% else %} - « {% trans "Prev" %} -{% endif %} -{% for page in paginator.page_range %} - {% ifequal page_obj.number page %} - {{page}} - {% else %} - {{page}} - {% endifequal %} -{% endfor %} -{% if page_obj.has_next %} - -{% else %} - {% trans "Next" %} » -{% endif %} -
\ No newline at end of file + + diff --git a/mahjong_ranking/__init__.py b/mahjong_ranking/__init__.py index 62a612a..7879747 100644 --- a/mahjong_ranking/__init__.py +++ b/mahjong_ranking/__init__.py @@ -30,7 +30,6 @@ DAN_RANKS = ( DAN_RANKS_DICT = dict([(dan, points) for points, dan in DAN_RANKS]) MIN_HANCHANS_FOR_LADDER = 10 - logger = getLogger('kasu.mahjong_ranking') diff --git a/mahjong_ranking/admin.py b/mahjong_ranking/admin.py index ae10470..0958ee4 100644 --- a/mahjong_ranking/admin.py +++ b/mahjong_ranking/admin.py @@ -7,9 +7,10 @@ Created on 19.09.2011 """ # import stuff we need from django from django.contrib import admin +from django.utils.translation import ugettext as _ + from . import models, set_dirty from forms import PlayerFormSet -from django.utils.translation import ugettext as _ def recalculate(modeladmin, request, queryset): @@ -27,7 +28,10 @@ def recalculate(modeladmin, request, queryset): set_dirty(season=ranking_season.id) elif isinstance(modeladmin, LadderRankingAdmin): for ladder_ranking in queryset: - set_dirty(user=ladder_ranking.user_id, season=ladder_ranking.season_id) # @IgnorePep8 + set_dirty(user=ladder_ranking.user_id, + season=ladder_ranking.season_id) # @IgnorePep8 + + recalculate.short_description = _("Recalculate") @@ -35,7 +39,7 @@ class PlayerInline(admin.TabularInline): extra = 4 formset = PlayerFormSet readonly_fields = ('placement', 'kyu_points', 'dan_points', 'bonus_points', - 'comment',) + 'comment',) max_num = 4 model = models.Player @@ -43,7 +47,7 @@ class PlayerInline(admin.TabularInline): class EventRankingAdmin(admin.ModelAdmin): list_filter = ['event'] list_display = ('placement', 'user', 'event', 'avg_placement', 'avg_score', - 'hanchan_count', 'good_hanchans', 'won_hanchans', 'dirty') + 'hanchan_count', 'good_hanchans', 'won_hanchans', 'dirty') list_display_links = ('user',) actions = [recalculate] @@ -53,7 +57,7 @@ class HanchanAdmin(admin.ModelAdmin): date_hierarchy = 'start' list_filter = ['season', 'event'] list_display = ('event', 'start', 'player_names', 'comment', - 'confirmed', 'valid', 'check_validity') + 'confirmed', 'valid', 'check_validity') inlines = (PlayerInline,) readonly_fields = ('valid', 'check_validity') @@ -66,13 +70,14 @@ class HanchanAdmin(admin.ModelAdmin): class KyuDanAdmin(admin.ModelAdmin): actions = [recalculate] list_display = ('user', 'kyu', 'kyu_points', 'dan', 'dan_points', - 'hanchan_count', 'dirty') + 'hanchan_count', 'dirty') class LadderRankingAdmin(admin.ModelAdmin): actions = [recalculate] list_display = ('placement', 'season', 'user', 'avg_placement', - 'avg_score', 'hanchan_count', 'good_hanchans', 'won_hanchans', 'dirty') + 'avg_score', 'hanchan_count', 'good_hanchans', + 'won_hanchans', 'dirty') list_display_links = ('user',) list_filter = ('season',) diff --git a/mahjong_ranking/forms.py b/mahjong_ranking/forms.py index eadb039..4f6117e 100644 --- a/mahjong_ranking/forms.py +++ b/mahjong_ranking/forms.py @@ -12,7 +12,6 @@ from django.utils import timezone from django.utils.translation import ugettext as _ from utils.html5 import forms - from . import models @@ -81,7 +80,6 @@ class PlayerForm(forms.ModelForm): class PlayerInlineFormSet(BaseInlineFormSet): - def clean(self): """Checks that no two articles have the same title.""" for form in self.forms: @@ -102,6 +100,7 @@ class SeasonSelectForm(django.forms.Form): season_list = season_list.values_list('season__id', 'season__name') self.fields['season'] = django.forms.ChoiceField(choices=season_list) + PlayerFormSet = inlineformset_factory( models.Hanchan, models.Player, diff --git a/mahjong_ranking/management/commands/random-ranking.py b/mahjong_ranking/management/commands/random-ranking.py index 10b03e2..1bdac6f 100644 --- a/mahjong_ranking/management/commands/random-ranking.py +++ b/mahjong_ranking/management/commands/random-ranking.py @@ -4,13 +4,16 @@ Generate Randum Mahjong Hanchans to the the Raning System """ -from django.contrib import auth -from django.core.management.base import BaseCommand -from events.models import Event -from mahjong_ranking import models import random from datetime import timedelta +from django.contrib import auth +from django.core.management.base import BaseCommand + +from events.models import Event +from mahjong_ranking import models + + class Command(BaseCommand): help = "Deletes all expired user registrations from the database" @@ -23,7 +26,8 @@ class Command(BaseCommand): player_list = list() ostwind_list = list() for user in user_list: - player_list.append(models.Player(user=user, hanchan=hanchan, score=25000)) + player_list.append( + models.Player(user=user, hanchan=hanchan, score=25000)) for player in player_list: player.save() @@ -33,8 +37,8 @@ class Command(BaseCommand): ostwind = ostwind_list.pop() while not end_of_game: score = random.randrange(1300, 8000, 100) - loser = player_list[random.randrange(0,4,1)] - winner = player_list[random.randrange(0,4,1)] + loser = player_list[random.randrange(0, 4, 1)] + winner = player_list[random.randrange(0, 4, 1)] winner.score += score print 'Ostwind: %s, Gewinner: %s, Verlierer: %s, %d Punkte' % ( @@ -73,9 +77,9 @@ class Command(BaseCommand): print "" def create_hanchan(self, event): - start = event.start + timedelta(minutes = random.randrange(00, 300, 15)) + start = event.start + timedelta(minutes=random.randrange(00, 300, 15)) print event.name, start - print '='*80 + print '=' * 80 hanchan = models.Hanchan(event=event, start=start) hanchan.save() self.add_players(hanchan) @@ -87,7 +91,7 @@ class Command(BaseCommand): self.user_list = list(auth.get_user_model().objects.all()) for event in Event.objects.all(): - for i in range(random.randrange(2,8)): + for i in range(random.randrange(2, 8)): self.create_hanchan(event) diff --git a/mahjong_ranking/middleware.py b/mahjong_ranking/middleware.py index a921e8c..5ac5676 100644 --- a/mahjong_ranking/middleware.py +++ b/mahjong_ranking/middleware.py @@ -6,6 +6,7 @@ Created on 23.05.2011 """ from django.core.cache import cache from django.db import transaction + from mahjong_ranking import models from . import logger @@ -30,7 +31,8 @@ class DenormalizationUpdateMiddleware(object): if len(event_ranking_queue) > 0: while len(event_ranking_queue) > 0: event_id, user_id = event_ranking_queue.pop() - logger.info("recalculate %d tournament Ranking in %s", user_id, event_id) + logger.info("recalculate %d tournament Ranking in %s", user_id, + event_id) ranking = models.EventRanking.objects.get_or_create( event_id=event_id, user_id=user_id)[0] ranking.recalculate() @@ -57,7 +59,8 @@ class DenormalizationUpdateMiddleware(object): user_id=user_id, season_id=season_id)[0] ranking.recalculate() else: - logger.error('Season: %i; Benutzer Nr. %i - existiert nicht!', season_id, user_id) + logger.error('Season: %i; Benutzer Nr. %i - existiert nicht!', + season_id, user_id) cache.set('ladder_ranking_queue', ladder_ranking_queue, 360) transaction.commit() diff --git a/mahjong_ranking/models.py b/mahjong_ranking/models.py index 04df791..ae5b4e1 100644 --- a/mahjong_ranking/models.py +++ b/mahjong_ranking/models.py @@ -1,6 +1,7 @@ # -*- encoding: utf-8 -*- from datetime import date, timedelta + from django.conf import settings from django.core.cache import cache from django.core.exceptions import ValidationError @@ -9,11 +10,12 @@ from django.db import models from django.db.models.aggregates import Sum from django.utils import timezone from django.utils.translation import ugettext as _ -from events.models import Event +from events.models import Event from . import KYU_RANKS, DAN_RANKS, DAN_RANKS_DICT, MIN_HANCHANS_FOR_LADDER from . import logger, set_dirty + kyu_dan_rankings = set() ladder_rankings = set() ladder_seasons = set() @@ -53,8 +55,10 @@ class EventRanking(models.Model): zur neuberrechnung zu markieren. Mittlerweile wird ein lokaler Cache dafür verwendet, das ist schneller. """ - logger.info(u'Recalculate EventRanking for Player %s in %s', self.user, self.event.name) # @IgnorePep8 - event_hanchans = Player.objects.valid_hanchans(user=self.user_id, event=self.event_id) # @IgnorePep8 + logger.info(u'Recalculate EventRanking for Player %s in %s', self.user, + self.event.name) # @IgnorePep8 + event_hanchans = Player.objects.valid_hanchans(user=self.user_id, + event=self.event_id) # @IgnorePep8 aggregator = event_hanchans.aggregate( models.Avg('placement'), models.Avg('score'), @@ -78,7 +82,9 @@ class Hanchan(models.Model): Außerdem gehört jede Hanchan zu einer Veranstaltung. """ comment = models.TextField(_('Comment'), blank=True) - confirmed = models.BooleanField(_('Has been Confirmed'), default=True, help_text=_('Only valid and confirmed Hanchans will be counted in the rating.')) # @IgnorePep8 + confirmed = models.BooleanField(_('Has been Confirmed'), default=True, + help_text=_( + 'Only valid and confirmed Hanchans will be counted in the rating.')) # @IgnorePep8 event = models.ForeignKey(Event) player_names = models.CharField(max_length=127, editable=False) players = models.ManyToManyField( @@ -86,8 +92,10 @@ class Hanchan(models.Model): through='Player', verbose_name=_('Players') ) - season = models.ForeignKey('LadderSeason', blank=True, null=True, editable=False) # @IgnorePep8 - start = models.DateTimeField(_('Start'), help_text=_('This is crucial to get the right Hanchans that scores')) # @IgnorePep8 + season = models.ForeignKey('LadderSeason', blank=True, null=True, + editable=False) # @IgnorePep8 + start = models.DateTimeField(_('Start'), help_text=_( + 'This is crucial to get the right Hanchans that scores')) # @IgnorePep8 valid = models.BooleanField(_('Is Valid'), default=False) class Meta(object): @@ -96,7 +104,8 @@ class Hanchan(models.Model): verbose_name_plural = _(u'Hanchans') def __str__(self): - return "Hanchan am {0:%d.%m.%Y} um {0:%H:%M} ({1})".format(self.start, self.player_names) + return "Hanchan am {0:%d.%m.%Y} um {0:%H:%M} ({1})".format(self.start, + self.player_names) def check_validity(self): """ @@ -148,12 +157,14 @@ class Hanchan(models.Model): Die Gültigkeit wird geprüft und die Sasion in der die Hanchan liegt wird aktualisert. """ - logger.debug("Hanchan clean() wurde getriggert!") + super(Hanchan, self).clean() # if self.pk and self.player_set.distinct().count() != 4: - # raise ValidationError( + # raise ValidationError( # _('For a Hanchan exactly 4 players are needed.')) - if self.start and self.start > timezone.now(): + if not self.event_id: + raise ValidationError(_("Hanchan has no event")) + elif self.start and self.start > timezone.now(): raise ValidationError(_("It's not allowed to enter future games.")) elif not (self.event.start <= self.start <= self.event.end): raise ValidationError(_("Only games during the event are allowed")) @@ -195,7 +206,8 @@ class Hanchan(models.Model): def save(self, **kwargs): logger.debug("Hanchan save() wurde getriggert!") - self.season = self.season or LadderSeason.objects.get_by_date(self.start) + self.season = self.season or LadderSeason.objects.get_by_date( + self.start) if self.pk: self.check_validity() self.compute_player_placements() @@ -245,7 +257,8 @@ class KyuDanRanking(models.Model): self.wins_in_a_row = 0 if self.dan and self.wins_in_a_row > 2: - logger.info('adding bonuspoints for 3 wins in a row for %s', self.user) # @IgnorePep8 + logger.info('adding bonuspoints for 3 wins in a row for %s', + self.user) # @IgnorePep8 new_dan_rank = self.dan + 1 new_dan_points = DAN_RANKS_DICT[new_dan_rank] + 1 bonus_points = new_dan_points - self.dan_points @@ -253,7 +266,8 @@ class KyuDanRanking(models.Model): logger.debug("Stats for %s:", self.user) logger.debug("current dan_points: %d", self.dan_points) logger.debug("current dan: %d", self.dan) - logger.debug("min required points for the next dan: %d", new_dan_points) # @IgnorePep8 + logger.debug("min required points for the next dan: %d", + new_dan_points) # @IgnorePep8 logger.debug("bonus points to add: %d", bonus_points) hanchan.dan_points += bonus_points @@ -424,7 +438,8 @@ class LadderRanking(models.Model): return reverse('player-ladder-score', args=[self.user.username]) def recalculate(self): - logger.info(u'Recalculate LadderRanking for Player %s in Season %s', self.user, self.season) # @IgnorePep8 + logger.info(u'Recalculate LadderRanking for Player %s in Season %s', + self.user, self.season) # @IgnorePep8 ladder_hanchans = Player.objects.ladder_hanchans( self.user_id, self.season_id) aggregate = ladder_hanchans.aggregate( @@ -443,7 +458,6 @@ class LadderRanking(models.Model): class LadderSeasonManager(models.Manager): - def current(self): """ Returns the current season and caches the result for 12 hours @@ -489,6 +503,14 @@ class LadderSeason(models.Model): def __unicode__(self): return self.name + def get_absolute_url(self): + """ + URL zur Hanchanliste des Events wo diese Hanchan gelistet wurde. + """ + return reverse('mahjong-ladder', kwargs={'season': self.pk}) + + + def recalculate(self): logger.info(u'Recalculate LadderSeason %s', self.name) self.ladderranking_set.update(placement=None) @@ -519,7 +541,8 @@ class PlayerManager(models.Manager): queryset = queryset.filter(kyu_points__isnull=False).select_related() return queryset - def ladder_hanchans(self, user=None, season=None, num_hanchans=None, max_age=None): # @IgnorePep8 + def ladder_hanchans(self, user=None, season=None, num_hanchans=None, + max_age=None): # @IgnorePep8 queryset = self.valid_hanchans(user).order_by('-hanchan__start') queryset = queryset.select_related() season = season or LadderSeason.objects.current() @@ -593,7 +616,8 @@ class Player(models.Model): ordering = ['-score'] def __str__(self): - return "{0}'s Punkte vom {1: %d.%m.%Y um %H:%M}".format(self.user.username, self.hanchan.start) + return "{0}'s Punkte vom {1: %d.%m.%Y um %H:%M}".format( + self.user.username, self.hanchan.start) def save(self, mark_dirty=True, season_id=None, *args, **kwargs): season_id = season_id or self.hanchan.season_id @@ -606,12 +630,15 @@ class Player(models.Model): else: return self if season_id: - logger.debug("Marking %s's season no. %i ranking for recalculation.", self.user, season_id) # @IgnorePep8 + logger.debug( + "Marking %s's season no. %i ranking for recalculation.", + self.user, season_id) # @IgnorePep8 set_dirty(season=season_id, user=self.user_id) logger.debug("Marking season no %i for recalculation.", season_id) set_dirty(season=season_id) if self.hanchan.event.is_tournament: - logger.debug("Marking tournament %s for recalculation.", self.hanchan.event) # @IgnorePep8 + logger.debug("Marking tournament %s for recalculation.", + self.hanchan.event) # @IgnorePep8 set_dirty(event=self.hanchan.event_id, user=self.user_id) return self @@ -622,4 +649,5 @@ def update_ranking_delete(sender, instance, **kwargs): # @UnusedVariable if instance.season_id: set_dirty(season=instance.season_id, user=player.user_id) + models.signals.pre_delete.connect(update_ranking_delete, sender=Hanchan) diff --git a/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html b/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html index 344fa9d..6632af5 100644 --- a/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html +++ b/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html @@ -1,17 +1,11 @@ -{% extends "events/event_site.html" %} +{% extends "events/event_detail.html" %} {% load i18n comments%} {% block title %}{% trans "Tournament Ranking" %}: {{ event.name }}{% endblock %} +{% block teaser %}

{% trans "Tournament Ranking" %}: {{ event.name }}

{% endblock %} -{% block event_content %} - -{% if event.is_tournament %} - -{% endif %} +{% block maincontent %}
@@ -21,13 +15,14 @@ - + - - - - + + + + + {% for player in eventranking_list %} @@ -42,11 +37,12 @@ {% endif %} - + - - + + + {% endwith %} {% empty %} diff --git a/mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html b/mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html index 72d9b05..4831404 100644 --- a/mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html +++ b/mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html @@ -1,10 +1,10 @@ -{% extends "base.html" %} +{% extends "events/event_detail.html" %} {% load i18n comments %} {% block meta_title %}{% trans 'Delete Hanchan' %}{% endblock %} -{% block content %} - +{% block maincontent %} + {% csrf_token %}
{% trans "Delete Hanchan" %} diff --git a/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html b/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html index 39608d1..9f8d574 100644 --- a/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html +++ b/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html @@ -1,11 +1,11 @@ -{% extends "events/event_site.html" %} +{% extends "events/event_detail.html" %} {% load i18n comments fieldset_extras %} {% block title %} {% if hanchan.id %}{% trans "Edit Hanchan" %}{% else %}{% trans "Add Hanchan" %}{% endif %} {% endblock %} -{% block event_content %} +{% block maincontent %} {% get_fieldset "event, start" from form as event_formset %} {% if perms.mahjong_ranking.delete_hanchan %} {% get_fieldset "comment, confirmed" from form as hanchan_formset %} diff --git a/mahjong_ranking/templates/mahjong_ranking/hanchan_list.html b/mahjong_ranking/templates/mahjong_ranking/hanchan_list.html index cd8c674..d625165 100644 --- a/mahjong_ranking/templates/mahjong_ranking/hanchan_list.html +++ b/mahjong_ranking/templates/mahjong_ranking/hanchan_list.html @@ -1,53 +1,56 @@ -{% extends "events/event_site.html" %} - -{% load i18n comments %} +{% extends "events/event_detail.html" %} +{% load i18n humanize %} {% block title %}Hanchans: {{ event.name }}{% endblock %} -{% block event_content %} - -{% if event.is_tournament %} - -{% endif %} - +{% block maincontent %} +

{% trans 'Played Hanchans' %}

+

 

{% for hanchan in hanchan_list %} -

{{hanchan.start|time:'H:i'}}: {{ hanchan.player_names }}

- {% for player in hanchan.player_set.all %} -
- -

{{player.placement}}. - {{ player.user }}

- {% trans 'Score' %}: {{player.score}} -
- {% endfor %} - {% if not hanchan.valid %} -

Ungültig: {{hanchan.check_validity}}

- {% elif not hanchan.confirmed %} -

Diese Hanchan wurde nicht anerkannt und wird daher nicht gezählt.

- {% elif hanchan.comment %} -

{{ hanchan.comment }}

- {% endif %} - +

{{hanchan.start|time:'H:i'}}: {{ hanchan.player_names }}

+{% for player in hanchan.player_set.all %} + {{ player.user }} +
+ {{ player.user }} +

{{ player.placement|ordinal }} {% trans 'Place' %}
+ {% trans 'Score' %}: {{ player.score|intcomma }}
+ {% if player.dan_points != None %} + {% trans 'Dan Points' %}: {{ player.dan_points }} + {% else %} + {% trans 'Kyu Points' %}: {{ player.kyu_points|default:0 }} + {% endif %} +

+
+{% endfor %} +{% if not hanchan.valid %} +

Ungültig: {{hanchan.check_validity}}

+{% elif not hanchan.confirmed %} +

Diese Hanchan wurde nicht anerkannt und wird daher nicht gezählt.

+{% elif hanchan.comment %} +

{{ hanchan.comment }}

+{% endif %} + {% empty %} -

{% trans 'No Hanchan has been added to this event yet.'%}

+

{% trans 'No Hanchan has been added to this event yet.'%}

{% endfor %} {% endblock %} {% block buttonbar %} - {% if perms.mahjong_ranking.add_hanchan %} - {% trans 'Add' %} {% trans 'Edit Event' %} - {% trans 'Add' %} {% trans 'Add Hanchan' %} - {% endif %} +{% if perms.mahjong_ranking.add_hanchan %} +{% trans 'Add' %} {% trans 'Edit Event' %} +{% trans 'Add' %} {% trans 'Add Hanchan' %} +{% endif %} {% endblock %} \ No newline at end of file diff --git a/mahjong_ranking/templates/mahjong_ranking/ladderranking_list.html b/mahjong_ranking/templates/mahjong_ranking/ladderranking_list.html index 6b7bbc7..f958bc8 100644 --- a/mahjong_ranking/templates/mahjong_ranking/ladderranking_list.html +++ b/mahjong_ranking/templates/mahjong_ranking/ladderranking_list.html @@ -1,7 +1,9 @@ {% extends "base.html" %} {% load i18n comments%} -{% block teaser %}

Mahjong Ranking - {{season.name}}

{% endblock %} +{% block teaser %} +

Mahjong Ranking - {{season.name}}

+{% endblock %} {% block maincontent %}
@@ -49,14 +51,6 @@ {% endblock %} {% block redbox %} -{% if is_archive %} -

{% trans 'Ladder Archive' %}

- -{% else %}

{% trans 'Latest Hanchans' %}

    {% for hanchan in latest_hanchan_list %} @@ -69,9 +63,17 @@

{% trans 'Latest Events' %}

    - {% for event in latest_event_list|slice:":3" %} + {% for event in latest_event_list %}
  • {{event.name}}
  • {% endfor %}
-{% endif %} +

{% trans 'Ladder Archive' %}

+ + + + {% endblock %} \ No newline at end of file diff --git a/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html b/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html index 206b2f5..590468f 100644 --- a/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html +++ b/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html @@ -2,7 +2,9 @@ {% load i18n %} {% block title %} {% trans 'Kyu Score for' %} {{player.username}} {% endblock %} + {% block teaser %}

{% trans 'Invalid hanchans with' %} {{membership.user.username}}

{% endblock %} + {% block score_list %}

{% trans 'Invalid hanchans with' %} {{membership.user.username}}

diff --git a/mahjong_ranking/urls.py b/mahjong_ranking/urls.py index 695f5df..abf43ae 100644 --- a/mahjong_ranking/urls.py +++ b/mahjong_ranking/urls.py @@ -6,49 +6,37 @@ Created on 03.10.2011 @author: christian """ from django.conf.urls import * # @UnusedWildImport +from django.views.generic import RedirectView + import views + urlpatterns = patterns( '', - url(r'^$', views.LadderRankingList.as_view(), name="mahjong-ladder"), - url(r'archive/$', - views.LadderRankingList.as_view(), - kwargs={'is_archive': True}, - name="mahjong-ladder-archive"), - url(r'archive/(?P[\d]+)/$', - views.LadderRankingList.as_view(), - name="mahjong-ladder-archive"), - url(r'players/$', - views.KyuDanRankingList.as_view(), + url('^$', RedirectView.as_view(pattern_name='mahjong-ladder')), + url(r'players/$', views.KyuDanRankingList.as_view(), name="kyudanranking-list"), - url(r'players/(?P[\+\-\w]+)/$', - views.KyuDanRankingList.as_view(), + url(r'players/(?P[\+\-\w]+)/$', views.KyuDanRankingList.as_view(), name="kyudanranking-list"), - url(r'event/(?P[\d]+)/$', - views.EventHanchanList.as_view(), + url(r'ranking/$', views.LadderRankingList.as_view(), name="mahjong-ladder"), + url(r'ranking/(?P[\d]+)/$', views.LadderRankingList.as_view(), + name="mahjong-ladder"), + url(r'ranking/event/(?P[\d]+)/$', views.EventHanchanList.as_view(), name="event-hanchan-list"), - url(r'event/(?P[\d]+)/ranking/$', - views.EventRankingList.as_view(), - name="event-ranking"), - url(r'event/(?P[\d]+)/add-hanchan/$', - views.HanchanForm.as_view(), - name="add-hanchan-form"), - url(r'hanchan/(?P[\d]+)/edit/$', - views.HanchanForm.as_view(), + url(r'ranking/event/(?P[\d]+)/ranking/$', + views.EventRankingList.as_view(), name="event-ranking"), + url(r'ranking/event/(?P[\d]+)/add-hanchan/$', + views.HanchanForm.as_view(), name="add-hanchan-form"), + url(r'hanchan/(?P[\d]+)/edit/$', views.HanchanForm.as_view(), name="edit-hanchan"), - url(r'hanchan/(?P[\d]+)/delete/$', - views.DeleteHanchan.as_view(), + url(r'hanchan/(?P[\d]+)/delete/$', views.DeleteHanchan.as_view(), name="delete-hanchan"), - url(r'dan_score/(?P[\-\.\d\w]+)/$', - views.PlayerDanScore.as_view(), - name="player-dan-score"), - url(r'invalid_score/(?P[\-\.\d\w]+)/$', - views.PlayerInvalidScore.as_view(), - name="player-invalid-score"), - url(r'kyu_score/(?P[\-\.\d\w]+)/$', - views.PlayerKyuScore.as_view(), - name="player-kyu-score"), - url(r'ladder_score/(?P[\-\.\d\w]+)/$', - views.PlayerLadderScore.as_view(), - name="player-ladder-score"), + url(r'player/(?P[\-\.\d\w]+)/dan/$', + views.PlayerDanScore.as_view(), name="player-dan-score"), + url(r'player/(?P[\-\.\d\w]+)/invalid/$', + views.PlayerInvalidScore.as_view(), name="player-invalid-score"), + url(r'player/(?P[\-\.\d\w]+)/kyu/$', + views.PlayerKyuScore.as_view(), name="player-kyu-score"), + url(r'player/(?P[\-\.\d\w]+)/ladder/$', + views.PlayerLadderScore.as_view(), name="player-ladder-score"), ) diff --git a/mahjong_ranking/views.py b/mahjong_ranking/views.py index f6c5aeb..44b7b47 100644 --- a/mahjong_ranking/views.py +++ b/mahjong_ranking/views.py @@ -11,6 +11,7 @@ from django.views import generic import xlwt from events.models import Event +from events.views import EventDetailMixin from . import forms, models from membership.models import Membership from utils.mixins import LoginRequiredMixin, PermissionRequiredMixin @@ -30,7 +31,7 @@ kyu_dan_order = { } -class DeleteHanchan(PermissionRequiredMixin, generic.DeleteView): +class DeleteHanchan(EventDetailMixin, PermissionRequiredMixin, generic.DeleteView): """ Fragt zuerst nach, ob die Hanchan wirklich gelöscht werden soll. Wir die Frage mit "Ja" beantwortet, wird die die Hanchan gelöscht. @@ -42,10 +43,10 @@ class DeleteHanchan(PermissionRequiredMixin, generic.DeleteView): def get_success_url(self): return reverse('event-hanchan-list', - kwargs={'event': self.object.event.pk}) + kwargs={'event': self.object.event.pk}) -class HanchanForm(PermissionRequiredMixin, generic.UpdateView): +class HanchanForm(EventDetailMixin, PermissionRequiredMixin, generic.UpdateView): """ Ein Formular um eine neue Hanchan anzulegen, bzw. eine bestehende zu bearbeitsen @@ -130,7 +131,7 @@ class HanchanForm(PermissionRequiredMixin, generic.UpdateView): return self.form_invalid(form, formset) -class EventHanchanList(generic.ListView): +class EventHanchanList(EventDetailMixin, generic.ListView): """ Auflistung aller Hanchan die während der Veranstaltung gespielt wurden. """ @@ -146,13 +147,8 @@ class EventHanchanList(generic.ListView): except models.Event.DoesNotExist: raise django.http.Http404(_('Event does not exist')) - def get_context_data(self, **kwargs): - context = generic.ListView.get_context_data(self, **kwargs) - context['event'] = self.event - return context - -class EventRankingList(generic.ListView): +class EventRankingList(EventDetailMixin, generic.ListView): """ Anzeige des Eventrankings, daß erstellt wurde falls der Termin als internes Turnier markiert wurde. @@ -168,11 +164,6 @@ class EventRankingList(generic.ListView): except models.Event.DoesNotExist: raise django.http.Http404(_('Event does not exist')) - def get_context_data(self, **kwargs): - context = generic.ListView.get_context_data(self, **kwargs) - context['event'] = self.event - return context - class KyuDanRankingList(generic.ListView): """ @@ -183,7 +174,8 @@ class KyuDanRankingList(generic.ListView): paginate_by = 25 def dispatch(self, request, *args, **kwargs): - self.order_by = kyu_dan_order[kwargs.get('order_by', self.default_order)] # @IgnorePep8 + self.order_by = kyu_dan_order[ + kwargs.get('order_by', self.default_order)] # @IgnorePep8 return generic.ListView.dispatch(self, request, *args, **kwargs) def get_queryset(self): @@ -202,7 +194,8 @@ class LadderRankingList(generic.ListView): def get_queryset(self): try: if self.kwargs.get('season'): - self.season = models.LadderSeason.objects.get(pk=self.kwargs['season']) + self.season = models.LadderSeason.objects.get( + pk=self.kwargs['season']) self.is_archive = True elif self.kwargs.get('is_archive'): self.season = models.LadderSeason.objects.order_by('-pk')[1] @@ -211,16 +204,18 @@ class LadderRankingList(generic.ListView): self.season = models.LadderSeason.objects.current() except models.LadderSeason.DoesNotExist: raise django.http.Http404(_('Season does not exist')) - queryset = models.LadderRanking.objects.filter(season=self.season, placement__isnull=False).select_related() + queryset = models.LadderRanking.objects.filter(season=self.season, + placement__isnull=False).select_related() return queryset def get_context_data(self, **kwargs): context = generic.ListView.get_context_data(self, **kwargs) context['is_archive'] = self.is_archive context['season'] = self.season - context['season_archive'] = models.LadderSeason.objects.all() - context['latest_hanchan_list'] = models.Hanchan.objects.filter(valid=True)[:5] - context['latest_event_list'] = Event.objects.archive()[:5] + context['season_list'] = models.LadderSeason.objects.all() + context['latest_hanchan_list'] = models.Hanchan.objects.filter( + valid=True)[:3] + context['latest_event_list'] = Event.objects.archive()[:3] return context @@ -238,11 +233,13 @@ class LadderRankingExcel(generic.View): response = django.http.HttpResponse(mimetype=u'application/msexcel') filename = urllib.quote(self.filename.encode('utf-8')) - response['Content-Disposition'] = "attachment; filename*=UTF-8''%s" % filename + response[ + 'Content-Disposition'] = "attachment; filename*=UTF-8''%s" % filename - field_names = [u"Login", u"Name", u"E-Mail", u"Telefon", u"Handy", u"Geburtstag", - u"T-Shirt", u"Teams", u"Gr.", u"Kg", u"Notfall Adresse", - u"Notfall Nummer", u"Notizen", ] + field_names = [u"Login", u"Name", u"E-Mail", u"Telefon", u"Handy", + u"Geburtstag", + u"T-Shirt", u"Teams", u"Gr.", u"Kg", u"Notfall Adresse", + u"Notfall Nummer", u"Notizen", ] # Erstelle ein Workbook (Das ist eine Excel Datei) @@ -253,7 +250,8 @@ class LadderRankingExcel(generic.View): sheet = workbook.add_sheet('Mitglieder', cell_overwrite_ok=False) sheet.set_panes_frozen(True) sheet.set_horz_split_pos(1) # in general, freeze after last heading row - sheet.set_remove_splits(True) # if user does unfreeze, don't leave a split there + sheet.set_remove_splits( + True) # if user does unfreeze, don't leave a split there for column in range(0, len(field_names)): sheet.write(0, column, field_names[column], style=header) @@ -267,13 +265,17 @@ class LadderRankingExcel(generic.View): profile = user.get_profile() self.set_col(sheet, current_row, 3, profile.telephone or None) self.set_col(sheet, current_row, 4, profile.mobilephone or None) - self.set_col(sheet, current_row, 5, profile.birthday or None, style=self.date) - self.set_col(sheet, current_row, 6, profile.shirt_size or None, style=self.center) + self.set_col(sheet, current_row, 5, profile.birthday or None, + style=self.date) + self.set_col(sheet, current_row, 6, profile.shirt_size or None, + style=self.center) self.set_col(sheet, current_row, 7, self.get_other_teams(user)) self.set_col(sheet, current_row, 8, profile.height or None) self.set_col(sheet, current_row, 9, profile.weight or None) - self.set_col(sheet, current_row, 10, profile.emergency_contact or None) - self.set_col(sheet, current_row, 11, profile.emergency_phone or None) + self.set_col(sheet, current_row, 10, + profile.emergency_contact or None) + self.set_col(sheet, current_row, 11, + profile.emergency_phone or None) except Membership.DoesNotExist: pass current_row += 1 @@ -290,17 +292,22 @@ class PlayerScore(LoginRequiredMixin, generic.ListView): def get(self, request, *args, **kwargs): try: - self.user = auth.get_user_model().objects.get(username=self.kwargs.get('username')) - self.membership = Membership.objects.get_or_create(user=self.user)[0] + self.user = auth.get_user_model().objects.get( + username=self.kwargs.get('username')) + self.membership = Membership.objects.get_or_create(user=self.user)[ + 0] except auth.get_user_model().DoesNotExist: - raise django.http.Http404(_("No user found matching the name %s") % self.kwargs.get('username')) + raise django.http.Http404( + _("No user found matching the name %s") % self.kwargs.get( + 'username')) return generic.ListView.get(self, request, *args, **kwargs) def get_context_data(self, **kwargs): context = generic.ListView.get_context_data(self, **kwargs) context['membership'] = self.membership try: - context['kyu_dan_ranking'] = models.KyuDanRanking.objects.get(user=self.user) + context['kyu_dan_ranking'] = models.KyuDanRanking.objects.get( + user=self.user) except models.KyuDanRanking.DoesNotExist: context['ranking'] = None try: @@ -312,7 +319,6 @@ class PlayerScore(LoginRequiredMixin, generic.ListView): return context - class PlayerDanScore(PlayerScore): template_name = 'mahjong_ranking/player_dan_score.html' @@ -339,16 +345,20 @@ class PlayerLadderScore(PlayerScore): def get_context_data(self, **kwargs): context = PlayerScore.get_context_data(self, **kwargs) - season_list = models.LadderRanking.objects.filter(user=self.user).select_related('user') + season_list = models.LadderRanking.objects.filter( + user=self.user).select_related('user') season_list = season_list.values_list('id', 'season__name') context['season'] = self.season context['seasons_select_form'] = forms.SeasonSelectForm(user=self.user) - context['seasons_select_field'] = django.forms.ChoiceField(choices=season_list) + context['seasons_select_field'] = django.forms.ChoiceField( + choices=season_list) return context def get_queryset(self, **kwargs): if self.request.GET.get('season'): - self.season = models.LadderSeason.objects.get(pk=self.request.GET['season']) + self.season = models.LadderSeason.objects.get( + pk=self.request.GET['season']) else: self.season = models.LadderSeason.objects.current() - return models.Player.objects.ladder_hanchans(user=self.user, season=self.season) + return models.Player.objects.ladder_hanchans(user=self.user, + season=self.season) diff --git a/manage.py b/manage.py index 0d1dc37..7d14ffc 100755 --- a/manage.py +++ b/manage.py @@ -3,6 +3,6 @@ import os import sys if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "kasu.settings") from django.core.management import execute_from_command_line + execute_from_command_line(sys.argv) diff --git a/membership/admin.py b/membership/admin.py index e36c9d8..7a2f8c3 100644 --- a/membership/admin.py +++ b/membership/admin.py @@ -5,10 +5,11 @@ Created on 19.09.2011 """ # import stuff we need from django from django.contrib import admin -from membership.models import Membership, ActivationRequest from django.utils.translation import ugettext as _ from imagekit.admin import AdminThumbnail +from membership.models import Membership, ActivationRequest + def activate_user(modeladmin, request, queryset): for activation in queryset: @@ -45,7 +46,8 @@ class MembershipAdmin(admin.ModelAdmin): list_display_links = ('nickname',) fieldsets = ( (None, { - 'fields': ('gender', ('first_name', 'last_name'), ('email', 'website')) + 'fields': ( + 'gender', ('first_name', 'last_name'), ('email', 'website')) }), (_('Membership'), { 'classes': ('collapse',), diff --git a/membership/forms.py b/membership/forms.py index 9ca08d1..fb6f532 100644 --- a/membership/forms.py +++ b/membership/forms.py @@ -3,11 +3,12 @@ Created on 03.10.2011 @author: Christian """ -from . import models from django.conf import settings from django.contrib import auth from django.contrib.sites.models import Site from django.utils.translation import ugettext_lazy as _ + +from . import models from utils.html5 import forms from utils.massmailer import MassMailer @@ -26,25 +27,29 @@ class MembershipForm(forms.ModelForm): ) def clean_birthday(self): - if self.cleaned_data['membership'] and not self.cleaned_data['birthday']: + if self.cleaned_data['membership'] and not self.cleaned_data[ + 'birthday']: raise forms.ValidationError(_('For your membership, we need this. \ Please fill out this field yet.')) return self.cleaned_data['birthday'] def clean_telephone(self): - if self.cleaned_data['membership'] and not self.cleaned_data['telephone']: + if self.cleaned_data['membership'] and not self.cleaned_data[ + 'telephone']: raise forms.ValidationError(_('For your membership, we need this. \ Please fill out this field yet.')) return self.cleaned_data['telephone'] def clean_street_name(self): - if self.cleaned_data['membership'] and not self.cleaned_data['street_name']: + if self.cleaned_data['membership'] and not self.cleaned_data[ + 'street_name']: raise forms.ValidationError(_('For your membership, we need this. \ Please fill out this field yet.')) return self.cleaned_data['street_name'] def clean_post_code(self): - if self.cleaned_data['membership'] and not self.cleaned_data['post_code']: + if self.cleaned_data['membership'] and not self.cleaned_data[ + 'post_code']: raise forms.ValidationError(_('For your membership, we need this. \ Please fill out this field yet.')) return self.cleaned_data['post_code'] @@ -103,7 +108,8 @@ class RegistrationForm(forms.ModelForm): """ Validate that the supplied email address is unique for the site. """ - if auth.get_user_model().objects.filter(email__iexact=self.cleaned_data['email']): + if auth.get_user_model().objects.filter( + email__iexact=self.cleaned_data['email']): raise forms.ValidationError(_(u'This email address is already in \ use. Please supply a different email address.')) return self.cleaned_data['email'] @@ -139,6 +145,7 @@ class RegistrationForm(forms.ModelForm): user.is_active = False if commit: user.save() - activation = models.ActivationRequest.objects.create_pending_registration(user) + activation = models.ActivationRequest.objects.create_pending_registration( + user) self.send_email(activation) return user diff --git a/membership/management/commands/cleanup-registration.py b/membership/management/commands/cleanup-registration.py index c22a15a..48c7848 100644 --- a/membership/management/commands/cleanup-registration.py +++ b/membership/management/commands/cleanup-registration.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from django.core.management.base import BaseCommand + from membership.models import ActivationRequest diff --git a/membership/management/commands/get-user.py b/membership/management/commands/get-user.py index c636f9d..98109e5 100644 --- a/membership/management/commands/get-user.py +++ b/membership/management/commands/get-user.py @@ -8,11 +8,12 @@ It might help your debugging to know or you might want to contact the user to tell them you have fixed the problem. """ +from optparse import make_option + from django.conf import settings from django.contrib import auth from django.contrib.sessions.models import Session from django.core.management.base import BaseCommand -from optparse import make_option class Command(BaseCommand): @@ -45,7 +46,8 @@ class Command(BaseCommand): self.stderr.write('Session "%s" does not exist' % session_key) continue except settings.AUTH_USER_MODEL.DoesNotExist: - self.stderr.write('Session "%s" has no registed User' % session_key) + self.stderr.write( + 'Session "%s" has no registed User' % session_key) continue if options['delete']: self.stdout.write('deleting %s' % user.username) diff --git a/membership/models.py b/membership/models.py index c9c55a6..c753b51 100644 --- a/membership/models.py +++ b/membership/models.py @@ -1,7 +1,10 @@ # -*- encoding: utf-8 -*- -from . import PAID_MEMBERSHIP_GROUP from datetime import timedelta +from os import path +import random +import hashlib + from django.utils import timezone from django.conf import settings from django.contrib.auth import get_user_model @@ -10,10 +13,10 @@ from django.db import models from django.utils.translation import ugettext as _ from imagekit.models import ImageSpecField from imagekit.processors import SmartResize -from os import path + +from . import PAID_MEMBERSHIP_GROUP from utils import OverwriteStorage -import random -import hashlib + GENDER_CHOICES = ( ('m', _('Male')), @@ -150,7 +153,8 @@ class MembershipManager(models.Manager): if user: return super(MembershipManager, self).get(user=user) elif username: - return super(MembershipManager, self).get(user__username=username) + return super(MembershipManager, self).get( + user__username=username) except Membership.DoesNotExist: if username: user = get_user_model().objects.get(username=username) diff --git a/membership/templates/membership/membership_detail.html b/membership/templates/membership/membership_detail.html index e04aec9..9b9d32e 100644 --- a/membership/templates/membership/membership_detail.html +++ b/membership/templates/membership/membership_detail.html @@ -6,14 +6,13 @@ {% block teaser %}

{% trans 'profile for' %} {{membership.user.username|title}}

{% endblock %} {% block navigation %} -{% if kyu_dan_ranking %} -{% endif %} {% endblock %} {% block maincontent %} diff --git a/membership/templates/membership/register_form.html b/membership/templates/membership/register_form.html index a266bdc..19a66fc 100644 --- a/membership/templates/membership/register_form.html +++ b/membership/templates/membership/register_form.html @@ -1,28 +1,39 @@ {% extends "base.html" %} -{% load i18n %} +{% load i18n fieldset_extras %} {% load url from future %} {% block title %}{% trans "Registration"%}{% endblock %} +{% block teaser%} +

{% trans "Registration"%}

+
+
+{% endblock %} {% block maincontent %} -
-

{% trans "Registration" %}

-

{% blocktrans %} - After you've provided your account data, you'll receive an email asking you to verify your email address. - You have to click on the link in this verification email to confirm your email address, otherwise your can't login. - {% endblocktrans %}

-
+
+ {% csrf_token %} +
+ {% trans "Name"%} + {% get_fieldset "first_name, last_name, username" from form as form1 %} + {% with form1 as form %}{% include "form.html" %}{% endwith %} +
+
+ {% trans "Security"%} + {% get_fieldset "email, password1, password2, recaptcha" from form as form2 %} + {% with form2 as form %}{% include "form.html" %}{% endwith %} +
- -{% csrf_token %} -
-{% trans "Registration"%} -{% include "form.html" %} -

- - -

-
+
+

{% blocktrans %}After you've provided your account data, you'll + receive an email asking you to verify your email address. + You have to click on the link in this verification email to + confirm your email address, otherwise your can't login. + {% endblocktrans %}

+

+ + +

+
diff --git a/membership/urls.py b/membership/urls.py index 9e0f7a7..9213c82 100644 --- a/membership/urls.py +++ b/membership/urls.py @@ -27,21 +27,4 @@ urlpatterns = patterns( url(r'^(?P[\-\.\d\w]+)/edit/$', views.EditMembership.as_view(), name="membership-edit") -) -""" -urlpatterns += patterns('social_auth.views', - url(r'^login/(?P[^/]+)/$', 'auth', - name='socialauth_begin'), - url(r'^complete/(?P[^/]+)/$', 'complete', - name='socialauth_complete'), - url(r'^associate/(?P[^/]+)/$', 'auth', - name='socialauth_associate_begin'), - url(r'^associate/complete/(?P[^/]+)/$', 'complete', - name='socialauth_associate_complete'), - url(r'^disconnect/(?P[^/]+)/$', 'disconnect', - name='socialauth_disconnect'), - url(r'^disconnect/(?P[^/]+)/(?P[^/]+)/$', - 'disconnect', - name='socialauth_disconnect_individual'), -) -""" \ No newline at end of file +) \ No newline at end of file diff --git a/membership/views.py b/membership/views.py index d8af4f5..f38f51c 100644 --- a/membership/views.py +++ b/membership/views.py @@ -9,7 +9,6 @@ from django.contrib.auth import get_user_model from mahjong_ranking.models import KyuDanRanking, LadderRanking, LadderSeason from utils import mixins - from . import forms, models @@ -49,7 +48,8 @@ class ActivateRegistration(generic.DetailView): def login(self, user): backend = auth.get_backends()[0] - user.backend = "%s.%s" % (backend.__module__, backend.__class__.__name__) # @IgnorePep8 + user.backend = "%s.%s" % ( + backend.__module__, backend.__class__.__name__) # @IgnorePep8 auth.login(self.request, user) messages.success(self.request, _('Activation successful. \ You can now login anytime with you username and password.')) @@ -81,7 +81,8 @@ class MembershipDetail(mixins.LoginRequiredMixin, generic.DetailView): def get_object(self, queryset=None): if self.kwargs.get('username'): - user = get_object_or_404(get_user_model(), username=self.kwargs['username']) + user = get_object_or_404(get_user_model(), + username=self.kwargs['username']) return models.Membership.objects.get_or_create(user=user)[0] elif self.request.user.is_authenticated(): return models.Membership.objects.get(user=self.request.user) diff --git a/templates/404.html b/templates/404.html deleted file mode 100644 index 8dde320..0000000 --- a/templates/404.html +++ /dev/null @@ -1,29 +0,0 @@ -{% extends "base.html" %} - -{% block title %}404 - Seite nicht gefunden{% endblock %} - -{% block maincontent %} -

404 - Nōten!

-

Unter der Adresse {{request.path}} wohnt zur Zeit kein Inhalt.
-Unsere Empfehlung: Gehe zurück zum Start.

- - -
-

Ursachen

-

Tote Links sind ein bislang ungelöstes Problem des Hypertextes und im Kern darauf zurückzuführen, dass das Internet ein dezentrales Netzwerk ist. Daher kann die Integrität desselbigen niemals sichergestellt werden.

-

Die Gründe für das Existieren von toten Links können sehr unterschiedlich sein und vor allem an sehr unterschiedlichen Stellen auftreten. In der Praxis häufig anzutreffende Gründe sind unter anderem:

-
    -
  • Die Datei, auf die die URL verweist, ist verschoben, umbenannt oder gelöscht worden.
  • -
  • Der Link auf der Ursprungseite ist fehlerhaft angegeben, beispielsweise bei der Groß- oder Kleinschreibung im URL-Bestandteil (URLs sind case sensitive) nach der Angabe des Domainnamens.
  • -
  • Die gesuchte Domain ist neu bei einem Registrar vergeben worden und die Website selber noch ohne jeden Inhalt.
  • -
  • Der Webserver ist nicht (mehr) erreichbar, beispielsweise wegen Netzproblemen oder weil der Rechner abgeschaltet ist.
  • -
  • Der Host- bzw. Domainname der URL existiert nicht (mehr) oder kann nicht im DNS aufgelöst werden.
  • -
-
- -
-

Lösungsmöglichkeiten

-

Eine Möglichkeit, die allerdings eher die Symptome der Dead Links bekämpft, ist die Wayback Machine des Internetarchivs. Durch chronologische Kopien von Webseiten kann Zugriff auf teilweise längst nicht mehr im Original vorhandene Webseiten gewährt werden.

-

Ursachenbekämpfung betreiben hingegen Gremien wie das W3C mit der Kampagne Cool URIs don't change[1], die in der Öffentlichkeit das Bewusstsein für die Notwendigkeit persistenter URLs wecken. Zudem gibt es bereits Systeme, die das Ziel von unabänderlichen URLs verfolgen, beispielsweise das des Persistent Uniform Resource Locators.

-
-{% endblock %} \ No newline at end of file diff --git a/templates/base.html b/templates/base.html deleted file mode 100644 index ac12d0d..0000000 --- a/templates/base.html +++ /dev/null @@ -1,205 +0,0 @@ -{% load i18n %} - - - - Kasu - {% block title %}{{ current_top_page.menu_name|default:"traditionelle asiatische Spielkultur"}}{% endblock %} - - - - - - - - - - - - {% block opengraph %} - - - - - {% endblock %} - {% block extra_head %}{% endblock %} - - -
- - - -
- {% block teaser %} -

{{page.title}} {{title}}

- {% endblock %} - -
- -{% block navigation %} -{% if current_top_page.subpages.count %} - -{% endif %} -{% endblock %} - -{% block messages %} -{% if messages %} -
    - {% for message in messages %} -
  • {{ message }}
  • - {% endfor %} -
-{% endif %} -{% endblock %} - -
- {% block maincontent %} -
{% block content %}{% endblock %}
- - {% endblock %} - {% block paginator %} - {% if page_obj.has_other_pages %}{% include 'paginator.html' %}{% endif %} - {% endblock %} - - {% block comments %}{% endblock %} -
-

- {% block buttonbar %} - {% if current_page and perms.content.change_page %} {% trans "Edit Page" %}{% endif %} - {% if current_page and perms.content.add_page %} {% trans "Add Subpage" %}{% endif %} - {% block additional_buttonbar %}{% endblock %} - {% endblock %} -

- -
- -
-

Herausgeber: Verein Kasu - traditionelle asiatische Spielkultur ({% trans "imprint" %}{% trans "contact" %}) -

- -
- {% csrf_token %} - - - - -
- - - - - \ No newline at end of file diff --git a/templates/comments/form.html b/templates/comments/form.html deleted file mode 100644 index 576f274..0000000 --- a/templates/comments/form.html +++ /dev/null @@ -1,51 +0,0 @@ -{% load comments i18n %} -
- {% csrf_token %} -
- {% trans "New Comment" %} - {% if user.is_authenticated %} -

- {{form.honeypot}} {{form.honeypot.label}} - {% for field in form.hidden_fields %}{{ field }}{% endfor %} - -

-
-
-
-

{{user}}

- -

{% trans 'now' %}

-
-
{{form.comment}}
-
-

- - -

- {% else %} -
-
-
-

{% trans "not logged in" %}

-
-
- -
-
-

- {% trans 'register' %} - {% trans 'login' %} -

- {% endif %} -
- \ No newline at end of file diff --git a/templates/comments/list.html b/templates/comments/list.html deleted file mode 100644 index 0c2fec7..0000000 --- a/templates/comments/list.html +++ /dev/null @@ -1,18 +0,0 @@ -{% load i18n django_markdown %} -

{% trans 'Comments' %}

-{% for comment in comment_list %} -
-
- -
-
-

{{comment.user}}

- -
-
{{comment.comment|markdown_safe}}
-
-{% endfor %} \ No newline at end of file diff --git a/templates/comments/posted.html b/templates/comments/posted.html deleted file mode 100644 index efc4ce5..0000000 --- a/templates/comments/posted.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "base.html" %} -{% load i18n %} - -{% block title %}{% trans "Thank you for your comment" %}{% endblock %} - -{% block content %} -

{% trans "Thank you for your comment" %}!

-{% endblock %} \ No newline at end of file diff --git a/templates/comments/preview.html b/templates/comments/preview.html deleted file mode 100644 index 4923736..0000000 --- a/templates/comments/preview.html +++ /dev/null @@ -1,29 +0,0 @@ -{% extends "base.html" %} -{% load i18n django_markdown %} - -{% block title %}{% trans "Preview your comment" %}{% endblock %} - -{% block maincontent %} - {% if form.errors %} -

{% blocktrans count form.errors|length as counter %}Please correct the error below{% plural %}Please correct the errors below{% endblocktrans %}

- {% else %} -

{% trans "Preview your comment" %}

-
-
- -
-
- {{comment.user}} -
-
-
{{comment|markdown_safe}}
-
- - {% endif %} - - {% include "comments/form.html" %} -{% endblock %} \ No newline at end of file diff --git a/templates/form.html b/templates/form.html deleted file mode 100644 index 5f5cf56..0000000 --- a/templates/form.html +++ /dev/null @@ -1,9 +0,0 @@ -{% for field in form.visible_fields %} -
- - {{ field }} - {%if field.help_text %}

{{field.help_text}}

{% endif %} - {%if field.errors %}{{ field.errors }}{% endif %} -
-{% endfor %} -{% for hidden in form.hidden_fields %}{{ hidden }}{% endfor %} \ No newline at end of file diff --git a/templates/google25dabc1a49a9ef03.html b/templates/google25dabc1a49a9ef03.html deleted file mode 100644 index a877b36..0000000 --- a/templates/google25dabc1a49a9ef03.html +++ /dev/null @@ -1 +0,0 @@ -google-site-verification: google25dabc1a49a9ef03.html \ No newline at end of file diff --git a/templates/index.html b/templates/index.html deleted file mode 100644 index 10bdcf7..0000000 --- a/templates/index.html +++ /dev/null @@ -1,115 +0,0 @@ -{% extends "base.html" %} -{% load i18n comments%} - -{% block jumbotron_background %}{{ random_photo.url }}{% endblock %} - -{% block teaser %} -

{{title}}

-
{{content}}
-{% endblock %} - -{% block redbox %} - {% if current_event %} -

{% trans "Current Event" %}

-

{{ current_event.name}}

-

{% trans "since" %} - -

-
    -
  • {% trans "Start" %}: {{current_event.start|date:'DATETIME_FORMAT'}}
  • -
  • {% trans "Location" %}: {{ current_event.location }}
  • -
- - {% else %} -

{% trans "Next Event" %}

-

{{ next_event.name}}

-

{% trans "in" %} - -

-
    -
  • {% trans "Start" %}: {{next_event.start|date:'DATETIME_FORMAT' }}
  • -
  • {% trans "Location" %}: {{ next_event.location }}
  • -
- - {% endif %} -

{% trans "Upcoming events" %} iCal Feed

-
    - {% for event in upcoming_events %} -
  • {{event.start|date:'d. M:'}} {{event.name}}
  • - {% endfor %} -
-{% endblock %} - -{% block maincontent %} -
- {% for article in recent_article_list %}{% get_comment_count for article as comment_count %} - - {% endfor %} -
- - -{% endblock %} - -{% if perms.content.add_article %}{% block addidional_buttonbar %} -{% trans "Add Article" %} -{% endblock %}{% endif %} - diff --git a/templates/paginator.html b/templates/paginator.html deleted file mode 100644 index 59b09d2..0000000 --- a/templates/paginator.html +++ /dev/null @@ -1,20 +0,0 @@ -{% load i18n %} -
-{% if page_obj.has_previous %} - -{% else %} - « {% trans "Prev" %} -{% endif %} -{% for page in paginator.page_range %} - {% ifequal page_obj.number page %} - {{page}} - {% else %} - {{page}} - {% endifequal %} -{% endfor %} -{% if page_obj.has_next %} - -{% else %} - {% trans "Next" %} » -{% endif %} -
\ No newline at end of file diff --git a/templates/registration/login.html b/templates/registration/login.html deleted file mode 100644 index a79ff4d..0000000 --- a/templates/registration/login.html +++ /dev/null @@ -1,64 +0,0 @@ -{% extends "base.html" %} - -{% load url from future %} -{% load i18n %} - -{% block title %}{% trans 'login' %}{% endblock %} - -{% block teaser %}

{% trans 'login' %}

{% endblock %} - -{% block maincontent %} -
-

Auf der Seite Anmelden

- -
-

{% trans "Have you already registered?" %}

-{% blocktrans %} -

As a registered member you can:

-
    -
  • leave comments on this page.
  • -
  • subscribe to our Newsletter
  • -
  • apply to a membership to our club
  • -
  • club-members have access to our ranking-system
  • -
-{% endblocktrans %} -{% blocktrans %} -

You can register here with your Google, or Facebook account. -If you don't own such an account, or do not want to use it for authentication, -you can fill out our registration form.

-{% endblocktrans %} - -
- - -{% csrf_token %} -
-{% trans 'login' %} -{% csrf_token %} -{% include 'form.html' %} -{% if form.errors %} -

{% blocktrans %}Your username and password didn't match. Please try again.{% endblocktrans %}

-{% endif %} - -

{% trans 'Forgot your Password?'%}

-
-
-
- - - -
-

{% trans "or login with an existing Account" %}

-{% trans 'Login with Facebook' %} -{% trans 'Login with twitter' %} -{% trans 'Login with Google' %} - - -
- -{% endblock %} \ No newline at end of file diff --git a/templates/registration/password_change_done.html b/templates/registration/password_change_done.html deleted file mode 100644 index 207e2b3..0000000 --- a/templates/registration/password_change_done.html +++ /dev/null @@ -1,9 +0,0 @@ -{% extends "base.html" %} -{% load i18n %} - -{% block title %}{% trans 'Password change successful' %}{% endblock %} - -{% block content %} -

{% trans 'Password change successful' %}

-

{% trans 'Your password was changed.' %}

-{% endblock %} \ No newline at end of file diff --git a/templates/registration/password_change_form.html b/templates/registration/password_change_form.html deleted file mode 100644 index 4ae01a1..0000000 --- a/templates/registration/password_change_form.html +++ /dev/null @@ -1,28 +0,0 @@ -{% extends "base.html" %} -{% load i18n %} - -{% block title %}{% trans 'Password change' %}{% endblock %} - -{% block callout %} -
-

{% trans 'Password change' %}

-

{% trans "Please enter your old password, for security's sake, and then enter your new password twice so we can verify you typed it in correctly." %}

-
-{% endblock %} - -{% block content %} -
- Passwort ändern: -
- {%csrf_token%} - {% if form.errors %}

Es sind Fehler beim ändern des Passwortes aufgetreten

{% endif %} - {% include 'form.html' %} -
- -
- -
-
-{% endblock %} diff --git a/templates/registration/password_reset_complete.html b/templates/registration/password_reset_complete.html deleted file mode 100644 index d08684c..0000000 --- a/templates/registration/password_reset_complete.html +++ /dev/null @@ -1,10 +0,0 @@ -{% extends "base.html" %} -{% load i18n %} - -{% block title %}{% trans 'Password reset complete' %}{% endblock %} - -{% block content %} -

{% trans 'Password reset complete' %}

-

{% trans "Your password has been set. You may go ahead and log in now." %}

-

{% trans 'Log in' %}

-{% endblock %} diff --git a/templates/registration/password_reset_confirm.html b/templates/registration/password_reset_confirm.html deleted file mode 100644 index 333436c..0000000 --- a/templates/registration/password_reset_confirm.html +++ /dev/null @@ -1,32 +0,0 @@ -{% extends "base.html" %} -{% load i18n %} - -{% block title %}{% trans 'Password reset' %}{% endblock %} - -{% block maincontent %} -{% if validlink %} -

{% trans 'Enter new password' %}

-

{% trans "Please enter your new password twice so we can verify you typed it in correctly." %}

-
-{% csrf_token %} -
- {% trans 'Change my password' %} -
    - {%for element in form %} -

    {{element.label_tag}} {{element}} - {%if element.help_text %} {% endif %} - {%if element.errors %}{{element.errors }} {% endif %} - - {% endfor %} -

-

-
- - - -{% else %} -

{% trans 'Password reset unsuccessful' %}

-

{% trans "The password reset link was invalid, possibly because it has already been used. Please request a new password reset." %}

-{% endif %} - -{% endblock %} diff --git a/templates/registration/password_reset_done.html b/templates/registration/password_reset_done.html deleted file mode 100644 index da90320..0000000 --- a/templates/registration/password_reset_done.html +++ /dev/null @@ -1,30 +0,0 @@ -{% extends "base.html" %} -{% load i18n %} - -{% block title %}{% trans 'Password reset successful' %}{% endblock %} - -{% block maincontent %} - -
-

{% trans 'Password reset successful' %}

-

Wir haben dir eine E-Mail mit Anweisungen zum Zurücksetzen deines Passwort an die angegebene E-Mail-Adresse geschickt.
-Du solltest diese in Kürze erhalten.

-
- -

E-Mail nicht angekommen?

-
-

Etwas Warten...

-

Einige Anti-Spam Techniken verzögern den Empfang von E-Mails. - Bei solchen Postfächern kann der Empfang einzelner Mails bis zu 30 Minuten dauern.

-
- -
-

Junk Mails prüfen

-

Bitte überprüfe den "Junk" bzw. "SPAM" Ordner deines Postfaches. - Automatisch generierte E-Mails werden leider sehr oft falsch von SPAM-Filtern geschluckt

-
-
-

Vorbei schauen

-

Bitte Überprüfe die Richigkeit deiner angegebenen E-Mail Adresse. Wenn deine angegebne E-Mail Adresse nicht mehr aktuell ist, trete mit uns bitte in persönlichen Kontakt

-
-{% endblock %} diff --git a/templates/registration/password_reset_form.html b/templates/registration/password_reset_form.html deleted file mode 100644 index 3339438..0000000 --- a/templates/registration/password_reset_form.html +++ /dev/null @@ -1,34 +0,0 @@ -{% extends "base.html" %} -{% load i18n %} - -{% block title %}{% trans "Password reset" %}{% endblock %} - -{% block maincontent %} - -

{% trans "Password reset" %}

-
- -

Du hast dein Passwort vergessen?

-

Macht nichts!
-Solange die E-Mail Adresse von dir noch gültig ist, kannst du dein Passwort jederzeit wieder ändern.

- -
- -
-{% csrf_token %} -
- E-Mail zusenden - {% for element in form %} -

- - {{element}} - {%if element.errors %} {{element.errors }} {% endif %} -

- {% endfor %} -
-

-
- -

Einfach deine E-Mail-Adresse eingeben und wir senden dir die Anweisungen zum Zurücksetzen deines Passworts.

- -{% endblock %} diff --git a/templates/robots.txt b/templates/robots.txt deleted file mode 100644 index d1a6f5f..0000000 --- a/templates/robots.txt +++ /dev/null @@ -1,4 +0,0 @@ -User-agent: * -Disallow: /cgi-bin/ -Disallow: /admin/ -Disallow: /users/ \ No newline at end of file diff --git a/utils/__init__.py b/utils/__init__.py index 472a603..e276d4d 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -3,11 +3,13 @@ Created on 28.09.2011 @author: christian """ +from django.core.files.storage import FileSystemStorage +from django.utils.translation import ugettext as _ + from .countries import COUNTRIES from .html_cleaner import HtmlCleaner from .massmailer import MassMailer -from django.core.files.storage import FileSystemStorage -from django.utils.translation import ugettext as _ + STATUS_REJECTED, STATUS_WAITING, STATUS_PUBLISHED = -1, 0, 1 STATUS_CHOICES = ( @@ -22,6 +24,7 @@ class OverwriteStorage(FileSystemStorage): """ Returns same name for existing file and deletes existing file on save. """ + def _save(self, name, content): if self.exists(name): self.delete(name) diff --git a/utils/forms.py b/utils/forms.py index 9e07df5..dd276dc 100644 --- a/utils/forms.py +++ b/utils/forms.py @@ -3,9 +3,10 @@ Created on 24.11.2011 @author: christian """ -from django import forms import datetime +from django import forms + class DateInput(forms.widgets.DateInput): input_type = 'date' @@ -13,9 +14,9 @@ class DateInput(forms.widgets.DateInput): def __init__(self, attrs=None, **kwargs): forms.widgets.DateInput.__init__(self, - attrs=attrs, - format='%Y-%m-%d', - **kwargs) + attrs=attrs, + format='%Y-%m-%d', + **kwargs) class NumberInput(forms.widgets.Input): @@ -23,8 +24,7 @@ class NumberInput(forms.widgets.Input): class TimeInput(forms.widgets.Select): - - def __init__(self, attrs=None,): + def __init__(self, attrs=None, ): timeset = datetime.datetime(2000, 1, 1, 0, 0) choices = [('', '-------')] while timeset < datetime.datetime(2000, 1, 2, 0, 0): @@ -37,7 +37,7 @@ class TimeInput(forms.widgets.Select): def render(self, name, value, attrs=None, choices=()): return forms.widgets.Select.render(self, name, value, attrs=attrs, - choices=choices) + choices=choices) class SplitDateTimeWidget(forms.widgets.MultiWidget): diff --git a/utils/html5/base.py b/utils/html5/base.py index b9daaac..6377811 100644 --- a/utils/html5/base.py +++ b/utils/html5/base.py @@ -1,15 +1,18 @@ import re + from django.core.urlresolvers import reverse from django.core.serializers.json import DjangoJSONEncoder from django.http import HttpResponse from django.utils.encoding import smart_unicode, force_unicode + + try: import json except ImportError: from django.utils import simplejson as json -class LookupBase(object): +class LookupBase(object): @classmethod def name(cls): app_name = cls.__module__.split('.')[-2].lower() @@ -69,7 +72,6 @@ class LookupInvalid(Exception): class LookupRegistry(object): - def __init__(self): self._registry = {} @@ -82,8 +84,8 @@ class LookupRegistry(object): self.validate(lookup) name = force_unicode(lookup.name()) if name in self._registry: - raise LookupAlreadyRegistered(u'The name %s is already registered'\ - % name) + raise LookupAlreadyRegistered(u'The name %s is already registered' \ + % name) self._registry[name] = lookup def unregister(self, lookup): diff --git a/utils/html5/forms.py b/utils/html5/forms.py index 24e8052..f2c10bf 100644 --- a/utils/html5/forms.py +++ b/utils/html5/forms.py @@ -48,7 +48,7 @@ class AutoCompleteSelectField(Html5Mixin, django.forms.Field): self.allow_new = kwargs.pop('allow_new', False) if not kwargs['widget']: kwargs['widget'] = self.widget(lookup_class, - allow_new=self.allow_new) + allow_new=self.allow_new) super(AutoCompleteSelectField, self).__init__(*args, **kwargs) def to_python(self, value): @@ -172,9 +172,9 @@ class PhoneField(Html5Mixin, django.forms.CharField): widget = widgets.PhoneInput def __init__(self, regex=None, max_length=None, min_length=None, - error_message=None, *args, **kwargs): + error_message=None, *args, **kwargs): super(PhoneField, self).__init__(max_length, min_length, - *args, **kwargs) + *args, **kwargs) self._set_regex(u'^[0-9+-/ ]+$') def _get_regex(self): @@ -184,7 +184,7 @@ class PhoneField(Html5Mixin, django.forms.CharField): regex = re.compile(regex, re.UNICODE) self._regex = regex if hasattr(self, '_regex_validator') \ - and self._regex_validator in self.validators: + and self._regex_validator in self.validators: self.validators.remove(self._regex_validator) self._regex_validator = validators.RegexValidator(regex=regex) self.validators.append(self._regex_validator) @@ -193,68 +193,68 @@ class PhoneField(Html5Mixin, django.forms.CharField): class ReCaptchaField(django.forms.fields.CharField): + def __init__(self, *args, **kwargs): + self.widget = widgets.ReCaptchaInput + self.required = True + super(ReCaptchaField, self).__init__(*args, **kwargs) - def __init__(self, *args, **kwargs): - self.widget = widgets.ReCaptchaInput - self.required = True - super(ReCaptchaField, self).__init__(*args, **kwargs) + def _check_recaptcha(self, challenge_value, response_value, remote_ip): + """ + Submits a reCAPTCHA request for verification. + Returns RecaptchaResponse for the request - def _check_recaptcha(self, challenge_value, response_value, remote_ip): - """ - Submits a reCAPTCHA request for verification. - Returns RecaptchaResponse for the request + @param challenge_value: value of recaptcha_challenge_field + @param response_value: value of recaptcha_response_field + @param remoteip -- the user's ip address - @param challenge_value: value of recaptcha_challenge_field - @param response_value: value of recaptcha_response_field - @param remoteip -- the user's ip address + """ + import urllib + import urllib2 - """ - import urllib - import urllib2 - private_key = settings.RECAPTCHA_PRIVATE_KEY - challenge_value = challenge_value.encode('utf-8') - response_value = response_value.encode('utf-8') - params = urllib.urlencode({ - 'privatekey': private_key, - 'remoteip': remote_ip, - 'challenge': challenge_value, - 'response': response_value, - }) + private_key = settings.RECAPTCHA_PRIVATE_KEY + challenge_value = challenge_value.encode('utf-8') + response_value = response_value.encode('utf-8') + params = urllib.urlencode({ + 'privatekey': private_key, + 'remoteip': remote_ip, + 'challenge': challenge_value, + 'response': response_value, + }) - request = urllib2.Request( - url="http://www.google.com/recaptcha/api/verify", - data=params, - headers={ - "Content-type": "application/x-www-form-urlencoded", - "User-agent": "reCAPTCHA Python" - } - ) - httpresp = urllib2.urlopen(request) + request = urllib2.Request( + url="http://www.google.com/recaptcha/api/verify", + data=params, + headers={ + "Content-type": "application/x-www-form-urlencoded", + "User-agent": "reCAPTCHA Python" + } + ) + httpresp = urllib2.urlopen(request) - return_values = httpresp.read().splitlines() - httpresp.close() + return_values = httpresp.read().splitlines() + httpresp.close() - return_code = return_values[0] - if (return_code == "true"): - return True - else: - return False + return_code = return_values[0] + if (return_code == "true"): + return True + else: + return False - def clean(self, values): - challenge_value = values[0] - response_value = values[1] - super(ReCaptchaField, self).clean(response_value) - if not challenge_value: - raise util.ValidationError( - _(u'The CAPTCHA challenge is missing.')) - elif not response_value: - raise util.ValidationError( - _(u'The CAPTCHA solution is missing.')) - elif self._check_recaptcha(challenge_value, response_value): - return challenge_value - else: - raise util.ValidationError( - _(u'The CAPTCHA solution was incorrect.')) + def clean(self, values): + challenge_value = values[0] + response_value = values[1] + super(ReCaptchaField, self).clean(response_value) + if not challenge_value: + raise util.ValidationError( + _(u'The CAPTCHA challenge is missing.')) + elif not response_value: + raise util.ValidationError( + _(u'The CAPTCHA solution is missing.')) + elif self._check_recaptcha(challenge_value, response_value): + return challenge_value + else: + raise util.ValidationError( + _(u'The CAPTCHA solution was incorrect.')) class RegexField(Html5Mixin, django.forms.RegexField): diff --git a/utils/html5/models.py b/utils/html5/models.py index 764fd16..9a29122 100644 --- a/utils/html5/models.py +++ b/utils/html5/models.py @@ -4,15 +4,13 @@ Created on 08.05.2011 @author: christian """ from django.db import models -from django.db.models import ForeignKey, Model, SET_NULL # @UnusedImport -from django.db.models import SET_DEFAULT, ManyToManyField # @UnusedImport +from django.db.models import ForeignKey # @UnusedImport from django.utils import six from . import forms, widgets class BooleanField(models.BooleanField): - def formfield(self, **kwargs): defaults = {'form_class': forms.BooleanField} defaults.update(kwargs) @@ -20,7 +18,6 @@ class BooleanField(models.BooleanField): class CharField(models.CharField): - def formfield(self, **kwargs): defaults = {'form_class': forms.CharField} defaults.update(kwargs) @@ -28,7 +25,6 @@ class CharField(models.CharField): class DateField(models.DateField): - def formfield(self, **kwargs): defaults = { 'form_class': forms.DateField} @@ -37,7 +33,6 @@ class DateField(models.DateField): class DateTimeField(models.DateTimeField): - def formfield(self, **kwargs): defaults = {'form_class': forms.DateTimeField} defaults.update(kwargs) @@ -52,7 +47,6 @@ class EmailField(models.EmailField): class FileField(models.FileField): - def formfield(self, **kwargs): defaults = {'form_class': forms.FileField} defaults.update(kwargs) @@ -60,7 +54,6 @@ class FileField(models.FileField): class ForeignKey(models.ForeignKey): - def formfield(self, **kwargs): db = kwargs.pop('using', None) if isinstance(self.rel.to, six.string_types): @@ -83,7 +76,6 @@ class ImageField(models.ImageField): class IntegerField(models.IntegerField): - def formfield(self, **kwargs): defaults = {'form_class': forms.IntegerField} defaults.update(kwargs) @@ -91,7 +83,6 @@ class IntegerField(models.IntegerField): class NullBooleanField(models.NullBooleanField): - def formfield(self, **kwargs): defaults = {'form_class': forms.BooleanField} defaults.update(kwargs) @@ -99,7 +90,6 @@ class NullBooleanField(models.NullBooleanField): class PositiveSmallIntegerField(models.PositiveSmallIntegerField): - def formfield(self, **kwargs): defaults = { 'form_class': forms.IntegerField, @@ -111,7 +101,6 @@ class PositiveSmallIntegerField(models.PositiveSmallIntegerField): class PositiveIntegerField(models.IntegerField): - def formfield(self, **kwargs): defaults = { 'form_class': forms.IntegerField, @@ -122,7 +111,6 @@ class PositiveIntegerField(models.IntegerField): class SlugField(models.SlugField): - def formfield(self, **kwargs): defaults = {'form_class': forms.SlugField} defaults.update(kwargs) @@ -130,9 +118,7 @@ class SlugField(models.SlugField): class TextField(models.TextField): - def formfield(self, **kwargs): - defaults = { 'form_class': forms.CharField, 'widget': widgets.Textarea @@ -142,7 +128,6 @@ class TextField(models.TextField): class URLField(models.URLField): - def formfield(self, **kwargs): defaults = {'form_class': forms.URLField} defaults.update(kwargs) diff --git a/utils/html5/views.py b/utils/html5/views.py index 93d6035..7d6e322 100644 --- a/utils/html5/views.py +++ b/utils/html5/views.py @@ -4,6 +4,7 @@ Created on 05.08.2011 @author: christian """ from django.http import Http404 + from . import registry diff --git a/utils/html5/widgets.py b/utils/html5/widgets.py index 08523a1..2514c18 100644 --- a/utils/html5/widgets.py +++ b/utils/html5/widgets.py @@ -14,7 +14,6 @@ from django.utils.safestring import mark_safe class AutoCompleteWidget(widgets.TextInput): - def __init__(self, lookup_class, attrs=None, *args, **kwargs): self.lookup_class = lookup_class self.allow_new = kwargs.pop('allow_new', False) @@ -29,7 +28,8 @@ class AutoCompleteWidget(widgets.TextInput): self.qs.update(qs_dict) def build_attrs(self, extra_attrs=None, **kwargs): - attrs = super(AutoCompleteWidget, self).build_attrs(extra_attrs, **kwargs) # @IgnorePep8 + attrs = super(AutoCompleteWidget, self).build_attrs(extra_attrs, + **kwargs) # @IgnorePep8 url = self.lookup_class.url() if self.qs: url = '%s?%s' % (url, urlencode(self.qs)) @@ -40,9 +40,9 @@ class AutoCompleteWidget(widgets.TextInput): class AutoComboboxWidget(AutoCompleteWidget): - def build_attrs(self, extra_attrs=None, **kwargs): - attrs = super(AutoComboboxWidget, self).build_attrs(extra_attrs, **kwargs) # @IgnorePep8 + attrs = super(AutoComboboxWidget, self).build_attrs(extra_attrs, + **kwargs) # @IgnorePep8 attrs[u'data-selectable-type'] = 'combobox' return attrs @@ -66,7 +66,8 @@ class DateTimeInput(widgets.MultiWidget): A Widget that splits datetime input into two boxes. """ - def __init__(self, attrs=None, date_format='%Y-%m-%d', time_format='%H:%M'): # @IgnorePep8 + def __init__(self, attrs=None, date_format='%Y-%m-%d', + time_format='%H:%M'): # @IgnorePep8 widgets = ( DateInput(attrs=attrs, date_format=date_format), TimeInput(attrs=attrs, time_format=time_format) @@ -92,7 +93,8 @@ class CheckboxInput(widgets.CheckboxInput): result = False if result: final_attrs['checked'] = 'checked' - if not (value is True or value is False or value is None or value == ''): # @IgnorePep8 + if not ( + value is True or value is False or value is None or value == ''): # @IgnorePep8 # Only add the 'value' attribute if a value is non-empty. final_attrs['value'] = force_unicode(value) @@ -132,12 +134,13 @@ class ReCaptchaInput(widgets.Widget): src="https://www.google.com/recaptcha/api/challenge?k=%(public_key)s"> """ return mark_safe(javascript % {'public_key': - settings.RECAPTCHA_PUBLIC_KEY, 'theme': 'red'}) + settings.RECAPTCHA_PUBLIC_KEY, + 'theme': 'red'}) def value_from_datadict(self, data, files, name): return [data.get(self.recaptcha_challenge_name, None), @@ -145,13 +148,11 @@ class ReCaptchaInput(widgets.Widget): class SelectableMultiWidget(widgets.MultiWidget): - def update_query_parameters(self, qs_dict): self.widgets[0].update_query_parameters(qs_dict) class Textarea(widgets.Widget): - def __init__(self, attrs=None): # The 'rows' and 'cols' attributes are required for HTML correctness. default_attrs = {'cols': '40', 'rows': '10'} @@ -163,7 +164,9 @@ class Textarea(widgets.Widget): value = '' if value is None else value final_attrs = self.build_attrs(attrs, name=name) return mark_safe(u'%s' % (flatatt(final_attrs), - conditional_escape(force_unicode(value)))) + conditional_escape( + force_unicode( + value)))) class TextInput(widgets.TextInput): @@ -192,7 +195,6 @@ class URLInput(widgets.Input): class LookupMultipleHiddenInput(widgets.MultipleHiddenInput): - def __init__(self, lookup_class, *args, **kwargs): self.lookup_class = lookup_class super(LookupMultipleHiddenInput, self).__init__(*args, **kwargs) @@ -221,21 +223,22 @@ class LookupMultipleHiddenInput(widgets.MultipleHiddenInput): return mark_safe(u'\n'.join(inputs)) def build_attrs(self, extra_attrs=None, **kwargs): - attrs = super(LookupMultipleHiddenInput, self).build_attrs(extra_attrs, **kwargs) # @IgnorePep8 + attrs = super(LookupMultipleHiddenInput, self).build_attrs(extra_attrs, + **kwargs) # @IgnorePep8 attrs[u'data-selectable-type'] = 'hidden-multiple' return attrs class AutoCompleteSelectMultipleWidget(SelectableMultiWidget): - def __init__(self, lookup_class, *args, **kwargs): self.lookup_class = lookup_class widgets = [ AutoCompleteWidget(lookup_class, allow_new=False, - attrs={u'data-selectable-multiple': 'true'}), + attrs={u'data-selectable-multiple': 'true'}), LookupMultipleHiddenInput(lookup_class) ] - super(AutoCompleteSelectMultipleWidget, self).__init__(widgets, *args, **kwargs) # @IgnorePep8 + super(AutoCompleteSelectMultipleWidget, self).__init__(widgets, *args, + **kwargs) # @IgnorePep8 def value_from_datadict(self, data, files, name): return self.widgets[1].value_from_datadict(data, files, name + '_1') @@ -244,19 +247,20 @@ class AutoCompleteSelectMultipleWidget(SelectableMultiWidget): if value and not hasattr(value, '__iter__'): value = [value] value = [u'', value] - return super(AutoCompleteSelectMultipleWidget, self).render(name, value, attrs) # @IgnorePep8 + return super(AutoCompleteSelectMultipleWidget, self).render(name, value, + attrs) # @IgnorePep8 class AutoComboboxSelectMultipleWidget(SelectableMultiWidget): - def __init__(self, lookup_class, *args, **kwargs): self.lookup_class = lookup_class widgets = [ AutoComboboxWidget(lookup_class, allow_new=False, - attrs={u'data-selectable-multiple': 'true'}), + attrs={u'data-selectable-multiple': 'true'}), LookupMultipleHiddenInput(lookup_class) ] - super(AutoComboboxSelectMultipleWidget, self).__init__(widgets, *args, **kwargs) # @IgnorePep8 + super(AutoComboboxSelectMultipleWidget, self).__init__(widgets, *args, + **kwargs) # @IgnorePep8 def value_from_datadict(self, data, files, name): return self.widgets[1].value_from_datadict(data, files, name + '_1') @@ -265,11 +269,11 @@ class AutoComboboxSelectMultipleWidget(SelectableMultiWidget): if value and not hasattr(value, '__iter__'): value = [value] value = [u'', value] - return super(AutoComboboxSelectMultipleWidget, self).render(name, value, attrs) # @IgnorePep8 + return super(AutoComboboxSelectMultipleWidget, self).render(name, value, + attrs) # @IgnorePep8 class AutoCompleteSelectWidget(SelectableMultiWidget): - def __init__(self, lookup_class, *args, **kwargs): self.lookup_class = lookup_class self.allow_new = kwargs.pop('allow_new', False) @@ -277,7 +281,8 @@ class AutoCompleteSelectWidget(SelectableMultiWidget): AutoCompleteWidget(lookup_class, allow_new=self.allow_new), widgets.HiddenInput(attrs={u'data-selectable-type': 'hidden'}) ] - super(AutoCompleteSelectWidget, self).__init__(widget_set, *args, **kwargs) # @IgnorePep8 + super(AutoCompleteSelectWidget, self).__init__(widget_set, *args, + **kwargs) # @IgnorePep8 def decompress(self, value): if value: @@ -294,7 +299,6 @@ class AutoCompleteSelectWidget(SelectableMultiWidget): class AutoComboboxSelectWidget(SelectableMultiWidget): - def __init__(self, lookup_class, *args, **kwargs): self.lookup_class = lookup_class self.allow_new = kwargs.pop('allow_new', False) @@ -302,7 +306,8 @@ class AutoComboboxSelectWidget(SelectableMultiWidget): AutoComboboxWidget(lookup_class, allow_new=self.allow_new), widgets.HiddenInput(attrs={u'data-selectable-type': 'hidden'}) ] - super(AutoComboboxSelectWidget, self).__init__(widget_set, *args, **kwargs) # @IgnorePep8 + super(AutoComboboxSelectWidget, self).__init__(widget_set, *args, + **kwargs) # @IgnorePep8 def decompress(self, value): if value: diff --git a/utils/html_cleaner.py b/utils/html_cleaner.py index f134efb..0cedce7 100644 --- a/utils/html_cleaner.py +++ b/utils/html_cleaner.py @@ -8,13 +8,19 @@ from BeautifulSoup import BeautifulSoup class HtmlCleaner(object): ACCEPTABLE_ELEMENTS = ['a', 'abbr', 'acronym', 'address', 'area', 'b', - 'big', 'blockquote', 'br', 'button', 'caption', 'center', 'cite', - 'code', 'col', 'colgroup', 'dd', 'del', 'dfn', 'dir', 'div', 'dl', - 'dt', 'em', 'font', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', - 'img', 'ins', 'kbd', 'label', 'legend', 'li', 'map', 'menu', 'ol', - 'p', 'pre', 'q', 's', 'samp', 'small', 'span', 'strike', - 'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'tfoot', 'th', - 'thead', 'tr', 'tt', 'u', 'ul', 'var'] + 'big', 'blockquote', 'br', 'button', 'caption', + 'center', 'cite', + 'code', 'col', 'colgroup', 'dd', 'del', 'dfn', 'dir', + 'div', 'dl', + 'dt', 'em', 'font', 'h1', 'h2', 'h3', 'h4', 'h5', + 'h6', 'hr', 'i', + 'img', 'ins', 'kbd', 'label', 'legend', 'li', 'map', + 'menu', 'ol', + 'p', 'pre', 'q', 's', 'samp', 'small', 'span', + 'strike', + 'strong', 'sub', 'sup', 'table', 'tbody', 'td', + 'tfoot', 'th', + 'thead', 'tr', 'tt', 'u', 'ul', 'var'] ACCEPTABELE_ATTRIBUTES = [ 'abbr', 'accept', 'accept-charset', 'accesskey', diff --git a/utils/management/commands/compresscss.py b/utils/management/commands/compresscss.py index ce34234..e5debc4 100644 --- a/utils/management/commands/compresscss.py +++ b/utils/management/commands/compresscss.py @@ -22,10 +22,10 @@ class Command(BaseCommand): help = _("Reads raw CSS from stdin, and writes compressed CSS to stdout.") option_list = BaseCommand.option_list + ( make_option('-w', '--wrap', - type='int', - default=None, - metavar='N', - help="Wrap output to approximately N chars per line."), + type='int', + default=None, + metavar='N', + help="Wrap output to approximately N chars per line."), ) def remove_comments(self, css): @@ -65,7 +65,6 @@ class Command(BaseCommand): """Remove unnecessary whitespace characters.""" def pseudoclasscolon(css): - """ Prevents 'p :link' from becoming 'p:link'. @@ -157,13 +156,15 @@ class Command(BaseCommand): def condense_hex_colors(self, css): """Shorten colors from #AABBCC to #ABC where possible.""" - regex = re.compile(r"([^\"'=\s])(\s*)#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])") + regex = re.compile( + r"([^\"'=\s])(\s*)#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])") match = regex.search(css) while match: first = match.group(3) + match.group(5) + match.group(7) second = match.group(4) + match.group(6) + match.group(8) if first.lower() == second.lower(): - css = css.replace(match.group(), match.group(1) + match.group(2) + '#' + first) + css = css.replace(match.group(), + match.group(1) + match.group(2) + '#' + first) match = regex.search(css, match.end() - 3) else: match = regex.search(css, match.end()) @@ -235,7 +236,8 @@ class Command(BaseCommand): css = '' """Read each .css file in the css_input directory, and append their content""" - for file_name in fnmatch.filter(sorted(os.listdir(css_input)), '*.css'): + for file_name in fnmatch.filter(sorted(os.listdir(css_input)), + '*.css'): print ' Adding: %s' % file_name with open(os.path.join(css_input, file_name), 'r') as css_file: css += css_file.read() diff --git a/utils/management/commands/scss-compiler.py b/utils/management/commands/scss-compiler.py index bc6943d..1b219ab 100644 --- a/utils/management/commands/scss-compiler.py +++ b/utils/management/commands/scss-compiler.py @@ -3,13 +3,13 @@ Created on 06.06.2011 @author: christian """ +import os +import fnmatch + from django.conf import settings -from django.contrib.sites.models import Site +from django.contrib.sites.models import Site from django.core.management.base import BaseCommand from django.utils.translation import ugettext as _ -from optparse import make_option -import os, re, fnmatch -from scss import parser class Command(BaseCommand): @@ -22,13 +22,13 @@ class Command(BaseCommand): def handle(self, *args, **options): CSS_ROOT = os.path.join(settings.STATICFILES_DIRS[0], 'css') for site in Site.objects.all(): - css_input = os.path.join(CSS_ROOT, site.domain) + css_input = os.path.join(CSS_ROOT, site.domain) css_output = '%s/%s.css' % (CSS_ROOT, site.domain.replace('.', '_')) print _("Compressing CSS for %s") % site.name print "Input Dir: %s" % css_input print "Output File: %s" % css_output - + try: os.makedirs(css_input) except OSError: @@ -36,11 +36,12 @@ class Command(BaseCommand): css = '' """Read each .css file in the css_input directory, and append their content""" - for file_name in fnmatch.filter(sorted(os.listdir(css_input)), '*.css'): + for file_name in fnmatch.filter(sorted(os.listdir(css_input)), + '*.css'): print ' Adding: %s' % file_name with open(os.path.join(css_input, file_name), 'r') as css_file: css += css_file.read() with open(css_output, 'w') as css_file: css_file.write(self.compress(css)) - #file.write(css) + # file.write(css) diff --git a/utils/massmailer.py b/utils/massmailer.py index 608abbb..f283331 100644 --- a/utils/massmailer.py +++ b/utils/massmailer.py @@ -1,4 +1,5 @@ import logging + from django.core import mail from django.contrib.auth.models import User from django.contrib.sites.models import Site @@ -66,7 +67,7 @@ class MassMailer(object): for recipient in self.recipients: mail_context['recipient'] = recipient mail_to = "%s %s <%s>" % (recipient.first_name, - recipient.last_name, recipient.email) + recipient.last_name, recipient.email) message = mail.EmailMultiAlternatives( subject=self.subject, body=self.txt_template.render(mail_context), @@ -92,7 +93,7 @@ class MassMailer(object): return True else: self.log.info('Sending eMail "%s" to %d people', self.subject, - len(self.mail_queue)) + len(self.mail_queue)) self.log.debug(self.recipients) self.open_smtp_connection() diff --git a/utils/mixins.py b/utils/mixins.py index 79be509..7dc77b0 100644 --- a/utils/mixins.py +++ b/utils/mixins.py @@ -20,13 +20,16 @@ class LoginRequiredMixin(object): def dispatch(self, request, *args, **kwargs): if request.user.is_authenticated(): - return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs) + return super(LoginRequiredMixin, self).dispatch(request, *args, + **kwargs) elif self.raise_exception: # if an exception was desired return http.HttpResponseForbidden() # return a forbidden response. else: messages.error(request, _("You need to be logged in")) path = urlquote(request.get_full_path()) - return http.HttpResponseRedirect("%s?%s=%s" % (self.login_url, self.redirect_field_name, path)) + return http.HttpResponseRedirect( + "%s?%s=%s" % (self.login_url, self.redirect_field_name, path)) + class PermissionRequiredMixin(object): """ @@ -60,18 +63,23 @@ class PermissionRequiredMixin(object): def dispatch(self, request, *args, **kwargs): # Verify class settings - if self.permission_required is None or len(self.permission_required.split(".")) != 2: - raise ImproperlyConfigured("'PermissionRequiredMixin' requires 'permission_required' attribute to be set.") + if self.permission_required is None or len( + self.permission_required.split(".")) != 2: + raise ImproperlyConfigured( + "'PermissionRequiredMixin' requires 'permission_required' attribute to be set.") has_permission = request.user.has_perm(self.permission_required) if has_permission: - return super(PermissionRequiredMixin, self).dispatch(request, *args, **kwargs) + return super(PermissionRequiredMixin, self).dispatch(request, *args, + **kwargs) elif self.raise_exception: return http.HttpResponseForbidden() else: messages.warning(request, self.permission_failed_message) path = urlquote(request.get_full_path()) - return http.HttpResponseRedirect("%s?%s=%s" % (self.login_url, self.redirect_field_name, path)) + return http.HttpResponseRedirect( + "%s?%s=%s" % (self.login_url, self.redirect_field_name, path)) + class SuperuserRequiredMixin(object): """ @@ -83,10 +91,13 @@ class SuperuserRequiredMixin(object): def dispatch(self, request, *args, **kwargs): if request.user.is_superuser: # If the user is a standard user, - return super(SuperuserRequiredMixin, self).dispatch(request, *args, **kwargs) + return super(SuperuserRequiredMixin, self).dispatch(request, *args, + **kwargs) elif self.raise_exception: # *and* if an exception was desired return http.HttpResponseForbidden() # return a forbidden response. else: - messages.error(request, _("You don't have the permissions for this")) + messages.error(request, + _("You don't have the permissions for this")) path = urlquote(request.get_full_path()) - return http.HttpResponseRedirect("%s?%s=%s" % (self.login_url, self.redirect_field_name, path)) + return http.HttpResponseRedirect( + "%s?%s=%s" % (self.login_url, self.redirect_field_name, path)) diff --git a/utils/templatetags/markup.py b/utils/templatetags/markup.py index e750f00..c49a377 100644 --- a/utils/templatetags/markup.py +++ b/utils/templatetags/markup.py @@ -12,6 +12,7 @@ import markdown register = template.Library() + @register.filter(name='markdown', is_safe=True) def markdown_filter(value, arg=''): """ @@ -41,7 +42,8 @@ def markdown_filter(value, arg=''): if extensions and extensions[0] == "safe": extensions = extensions[1:] return mark_safe(markdown.markdown( - force_text(value), extensions, safe_mode=True, enable_attributes=False)) + force_text(value), extensions, safe_mode=True, + enable_attributes=False)) else: return mark_safe(markdown.markdown( force_text(value), extensions, safe_mode=False))
{% trans "Nickname" %} {% trans "Name" %} {% trans 'Average' %}HanchansHanchans
{% trans 'Placement' %}{% trans "Score" %}{% trans "won" %}{% trans "good" %}{% trans 'Placement' %}{% trans "Score" %}{% trans "count" %}{% trans "good" %}{% trans "won" %}
{{player.user}}{{profile.last_name}} {{profile.first_name}}{% if user.is_authenticated %}{{profile.last_name}} {{profile.first_name}}{% else %} ---{% endif %} {{player.avg_placement|floatformat:2 }} {{player.avg_score|floatformat:0 }}{{player.won_hanchans}}{{player.good_hanchans}}{{player.hanchan_count}}{{player.good_hanchans}}{{player.won_hanchans}}