Paginator der besser ins Design passt.

This commit is contained in:
Christian Berg
2014-12-10 00:23:36 +01:00
parent 2011d3ce25
commit 711c303f9a
75 changed files with 675 additions and 1599 deletions

3
.gitignore vendored
View File

@@ -1,5 +1,6 @@
*.pyc *.pyc
htdocs/media/ htdocs/
static/
media/ media/
.idea .idea
.gitignore .gitignore

4
.idea/encodings.xml generated
View File

@@ -1,4 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" /> <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false">
<file url="PROJECT" charset="UTF-8" />
</component>
</project> </project>

View File

@@ -1,6 +1,8 @@
from django.contrib import admin from django.contrib import admin
from models import Feed, FeedItem from models import Feed, FeedItem
admin.site.register( admin.site.register(
Feed, Feed,
list_display=["title", "public_url", "last_update", 'is_functional'], list_display=["title", "public_url", "last_update", 'is_functional'],

View File

@@ -1,4 +1,5 @@
import django.contrib.syndication.views import django.contrib.syndication.views
from .models import FeedItem from .models import FeedItem

View File

@@ -3,9 +3,10 @@ Update feeds for Django community page. Requires Mark Pilgrim's excellent
Universal Feed Parser (http://feedparser.org) Universal Feed Parser (http://feedparser.org)
""" """
from aggregator.models import Feed
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from aggregator.models import Feed
class Command(BaseCommand): class Command(BaseCommand):
help = "Updates all RSS Feeds" help = "Updates all RSS Feeds"

View File

@@ -5,14 +5,16 @@ Created on 05.02.2011
""" """
from datetime import datetime, timedelta from datetime import datetime, timedelta
import HTMLParser
import urllib2
from django.conf import settings from django.conf import settings
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
from django.utils import timezone from django.utils import timezone
from utils.html5 import models
import HTMLParser
import django.db.models import django.db.models
import feedparser import feedparser
import urllib2
from utils.html5 import models
class FeedManager(django.db.models.Manager): 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] 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) title = models.CharField(max_length=500)
site = models.ForeignKey(Site) site = models.ForeignKey(Site)
feed_url = models.URLField(unique=True, max_length=255) feed_url = models.URLField(unique=True, max_length=255)
@@ -51,7 +53,8 @@ class Feed(models.Model):
parsed_feed = feedparser.parse(self.feed_url) parsed_feed = feedparser.parse(self.feed_url)
html_parser = HTMLParser.HTMLParser() 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 self.is_functional = False
return self.save() return self.save()
@@ -68,16 +71,22 @@ class Feed(models.Model):
feed_entry.get("content", u"") feed_entry.get("content", u"")
)) ))
) )
date_modified = feed_entry.get("published_parsed", parsed_feed.get("published_parsed", timezone.now)) date_modified = feed_entry.get(
date_modified = timezone.make_aware(datetime(*date_modified[:6]), timezone.get_current_timezone()) "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, feed_item, updated = self.feed_items.get_or_create(
defaults={ guid=guid,
'title': title, defaults={
'link': link, 'title': title,
'summary': summary, 'link': link,
'date_modified': date_modified 'summary': summary,
}) 'date_modified': date_modified
})
feed_item.save() feed_item.save()
self.last_update = timezone.now() self.last_update = timezone.now()
return self.save() return self.save()
@@ -86,7 +95,7 @@ class Feed(models.Model):
ordering = ("title",) ordering = ("title",)
class FeedItem(models.Model): class FeedItem(django.db.models.Model):
feed = models.ForeignKey(Feed, related_name='feed_items') feed = models.ForeignKey(Feed, related_name='feed_items')
title = models.CharField(max_length=500) title = models.CharField(max_length=500)
link = models.URLField(max_length=500) link = models.URLField(max_length=500)

View File

@@ -1,7 +1,9 @@
from django.contrib.sitemaps import Sitemap from django.contrib.sitemaps import Sitemap
from models import FeedItem from models import FeedItem
# noinspection PyMethodMayBeStatic # noinspection PyMethodMayBeStatic
class FeedItemSitemap(Sitemap): class FeedItemSitemap(Sitemap):
changefreq = "never" changefreq = "never"

View File

@@ -1,9 +1,9 @@
from django import template from django import template
from models import Feed from models import Feed
class FeedListNode(template.Node): class FeedListNode(template.Node):
def __init__(self, varname): def __init__(self, varname):
self.varname = 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] "First argument to '%s' tag must be 'as'" % bits[0]
return FeedListNode(bits[2]) return FeedListNode(bits[2])
register = template.Library() register = template.Library()
register.tag('get_feed_list', do_get_feed_list) register.tag('get_feed_list', do_get_feed_list)

View File

@@ -1,12 +1,23 @@
#!/bin/sh #!/bin/sh
echo "aktualisiere Übersetzungen..." echo "aktualisiere Übersetzungen..."
cd src unset DJANGO_SETTINGS_MODULE
./manage.py makemessages -l de for dir in *
./manange.py compilemessages -a 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..." echo "lösche den Python Compiler Cache..."
find . -name "*.pyc" -exec rm -rf {} \; find . -name "*.pyc" -exec rm -rf {} \;
touch kasu.wsgi
./manage.py collectstatic --noinput ./manage.py collectstatic --noinput
./manage.py generateimages ./manage.py generateimages
touch kasu/wsgi.py

View File

@@ -3,11 +3,13 @@ Created on 03.10.2011
@author: christian @author: christian
""" """
from . import models
from django import forms from django import forms
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.contrib.auth import get_user_model 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() user_query = get_user_model().objects.all()
@@ -15,8 +17,8 @@ user_query = get_user_model().objects.all()
class PhotoUploadForm(forms.Form): class PhotoUploadForm(forms.Form):
error_css_class = 'error' error_css_class = 'error'
required_css_class = 'required' required_css_class = 'required'
photographer = forms.ModelChoiceField(user_query, required=True,) photographer = forms.ModelChoiceField(user_query, required=True, )
event = forms.ModelChoiceField(models.Event.objects.all(), required=True,) event = forms.ModelChoiceField(Event.objects.all(), required=True, )
upload = forms.FileField( upload = forms.FileField(
label=_('Images'), label=_('Images'),
required=True, required=True,
@@ -38,20 +40,3 @@ class EditPhotoForm(forms.ModelForm):
fields = ('event', 'name', 'description', 'photographer', fields = ('event', 'name', 'description', 'photographer',
'anchor_horizontal', 'anchor_vertical', 'anchor_horizontal', 'anchor_vertical',
'created_date', 'on_startpage') '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

View File

@@ -5,29 +5,11 @@ import os
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db import models 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 django.utils.translation import ugettext as _
from imagekit import ImageSpec
import imagekit
from imagekit.models import ImageSpecField
from pilkit import processors
import pyexiv2 import pyexiv2
from utils import COUNTRIES, OverwriteStorage from utils import OverwriteStorage
from kasu import image_models
CHOICES_HORIZONTAL = (
(0.00000001, _('left')),
(0.5, _('center')),
(1, _('right'))
)
CHOICES_VERTICAL = (
(0.00000001, _('top')),
(0.5, _('middle')),
(1, _('bottom'))
)
def get_upload_path(instance, filename): def get_upload_path(instance, filename):
@@ -42,231 +24,10 @@ def get_upload_path(instance, filename):
@type filename: String @type filename: String
""" """
extension = filename[filename.rfind('.') + 1:] extension = filename[filename.rfind('.') + 1:]
if isinstance(instance, Event): if isinstance(instance, Photo):
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):
return "events/%s/%s" % (instance.event.id, filename) 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): class PhotoManager(models.Manager):
def get_random(self, startpage=True): def get_random(self, startpage=True):
if startpage: if startpage:
@@ -279,26 +40,26 @@ class PhotoManager(models.Manager):
return Photo() return Photo()
class Photo(ImageModel): class Photo(image_models.ImageModel):
name = models.CharField(_("Name"), max_length=100, blank=True) name = models.CharField(_("Name"), max_length=100, blank=True)
image = models.ImageField(_("Image"), upload_to=get_upload_path, image = models.ImageField(_("Image"), upload_to=get_upload_path,
storage=OverwriteStorage()) storage=OverwriteStorage())
anchor_horizontal = models.FloatField( anchor_horizontal = models.FloatField(
_('horizontal Anchorpoint'), _('horizontal Anchorpoint'),
choices=CHOICES_HORIZONTAL, choices=image_models.CHOICES_HORIZONTAL,
blank=True, null=True, blank=True, null=True,
help_text='Der Ankerpunkt ist der interessante Teil des Bildes,\ help_text='Der Ankerpunkt ist der interessante Teil des Bildes,\
welcher nie abgeschnitten werden darf' welcher nie abgeschnitten werden darf'
) )
anchor_vertical = models.FloatField( anchor_vertical = models.FloatField(
_('vertical Anchorpoint'), _('vertical Anchorpoint'),
choices=CHOICES_VERTICAL, choices=image_models.CHOICES_VERTICAL,
blank=True, null=True, blank=True, null=True,
help_text='Wenn kein Ankerpunkt von Hand (horizontal und vertikal)\ help_text='Wenn kein Ankerpunkt von Hand (horizontal und vertikal)\
festgelegt wird, versucht die Software diesen selbst zu erraten.' festgelegt wird, versucht die Software diesen selbst zu erraten.'
) )
event = models.ForeignKey(Event) event = models.ForeignKey('events.Event')
description = models.TextField( description = models.TextField(
_("Description"), _("Description"),
max_length=300, max_length=300,
@@ -321,10 +82,12 @@ class Photo(ImageModel):
orientation = 1 orientation = 1
class Meta: class Meta:
get_latest_by = "created_date"
ordering = ["created_date"]
db_table = 'events_photo'
verbose_name = _('Event Image') verbose_name = _('Event Image')
verbose_name_plural = _('Event Images') verbose_name_plural = _('Event Images')
ordering = ["created_date"]
get_latest_by = "created_date"
def __unicode__(self): def __unicode__(self):
return os.path.basename(self.image.name) 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 Triggers to save related Event to save. This should force an update for
the denormalized Photo count. the denormalized Photo count.
""" """
ImageModel.save(self, **kwargs) super(Photo, self).save()
self.save_metadata() 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)

View File

@@ -1,4 +1,4 @@
{% extends "base.html" %} {% extends "events/event_detail.html" %}
{% load i18n comments %} {% load i18n comments %}
{% block maincontent %} {% block maincontent %}

View File

@@ -1,4 +1,4 @@
{% extends "events/photo_list.html" %} {% extends "gallery/photo_list.html" %}
{% load i18n comments %} {% load i18n comments %}
{% block title %} {{ photo.name }} - {{ photo.event.name }} {% endblock %} {% block title %} {{ photo.name }} - {{ photo.event.name }} {% endblock %}
@@ -22,35 +22,36 @@
<a href="{{ photo.next_photo.get_absolute_url }}" class="next">Next</a> <a href="{{ photo.next_photo.get_absolute_url }}" class="next">Next</a>
{% endif %} {% endif %}
</div> </div>
<p class="grid_10 push_1">{{ photo.description }}</p>
<div class="grid_12 more_link">
<a href="https://m.google.com/app/plus/x/?v=compose&amp;content={{photo.headline|urlencode}}+-+http%3A%2F%2Fwww.kasu.at/{{photo.get_absolute_url|urlencode}}" target="_blank"><img src="{{STATIC_URL}}img/google_plus.png" alt="Google+" title="{% trans 'Share on Google+'%}" /></a>
<a href="https://twitter.com/share?url=http%3A%2F%2Fwww.kasu.at/{{photo.get_absolute_url|urlencode}}" target='_blank'><img src="{{STATIC_URL}}img/twitter.png" alt="Twitter" title="{% trans 'Share on Twitter' %}" /></a>
<a href="http://facebook.com/sharer.php?u=http%3A%2F%2Fwww.kasu.at{{photo.get_absolute_url|urlencode}}" target="_blank"><img src="{{STATIC_URL}}img/facebook.png" alt="Facebook" title="{% trans 'Share on Facebook'%}" /></a>
</div>
{% if perms.events.change_photo %} <ul class="info grid_12">
<li class="user"><strong>{% trans 'Photographer' %}: </strong>{{ photo.photographer }}</li>
<li class="date"><strong>{% trans 'on' %}</strong> {{ photo.created_date }}</li>
</ul>
{% endblock %}
{% block comment %}
{% render_comment_list for photo %}
{% render_comment_form for photo %}
{% endblock %}
{% block buttonbar %}
{% if perms.events.change_photo %}
<form method="post" enctype="multipart/form-data" class="grid_12"> <form method="post" enctype="multipart/form-data" class="grid_12">
{% csrf_token %} {% csrf_token %}
<fieldset>
{% include "form.html" %}
<p class="buttonbar"> <p class="buttonbar">
<a href="{{ photo.image.url }}" class="button" type="application/octet-stream"><img src="{{ STATIC_URL}}icons/drive_go.png" alt="{% trans 'download' %}" title="{% trans 'download' %}" /></a> <a href="{{ photo.image.url }}" class="button" type="application/octet-stream"><img src="{{ STATIC_URL}}icons/drive_go.png" alt="{% trans 'download' %}" title="{% trans 'download' %}" /></a>
<button type="submit" name="rotate" value="counter-clockwise"><img src="{{STATIC_URL}}icons/shape_rotate_anticlockwise.png" title="Gegen den Uhrzeiger drehen"></button> <button type="submit" name="rotate" value="counter-clockwise"><img src="{{STATIC_URL}}icons/shape_rotate_anticlockwise.png" title="Gegen den Uhrzeiger drehen"></button>
<button type="submit" name="rotate" value="clockwise"><img src="{{STATIC_URL}}icons/shape_rotate_clockwise.png" title="Im Uhrzeiger drehen"></button> <button type="submit" name="rotate" value="clockwise"><img src="{{STATIC_URL}}icons/shape_rotate_clockwise.png" title="Im Uhrzeiger drehen"></button>
<button type="submit"><img src="{{STATIC_URL}}icons/disk.png" alt=""> {% trans "save" %}</button> <button type="submit"><img src="{{STATIC_URL}}icons/disk.png" alt=""> {% trans "save" %}</button>
</p> </p>
</fieldset>
</form> </form>
{% else %} {% endif %}
<p class="grid_10 push_1">{{ photo.description }}</p>
<ul class="info grid_11 push_1">
<li class="user"><strong>{% trans 'Photographer' %}: </strong>{{ photo.photographer }}</li>
<li class="date"><strong>{% trans 'on' %}</strong> {{ photo.created_date }}</li>
</ul>
{% endif %}
<div class="grid_12 more_link">
<a href="https://m.google.com/app/plus/x/?v=compose&amp;content={{photo.headline|urlencode}}+-+http%3A%2F%2Fwww.kasu.at/{{photo.get_absolute_url|urlencode}}" target="_blank"><img src="{{STATIC_URL}}img/google_plus.png" alt="Google+" title="{% trans 'Share on Google+'%}" /></a>
<a href="https://twitter.com/share?url=http%3A%2F%2Fwww.kasu.at/{{photo.get_absolute_url|urlencode}}" target='_blank'><img src="{{STATIC_URL}}img/twitter.png" alt="Twitter" title="{% trans 'Share on Twitter' %}" /></a>
<a href="http://facebook.com/sharer.php?u=http%3A%2F%2Fwww.kasu.at{{photo.get_absolute_url|urlencode}}" target="_blank"><img src="{{STATIC_URL}}img/facebook.png" alt="Facebook" title="{% trans 'Share on Facebook'%}" /></a>
</div>
{% render_comment_list for photo %}
{% render_comment_form for photo %}
{% endblock %} {% endblock %}

View File

@@ -1,4 +1,4 @@
{% extends "events/photo_gallery.html" %} {% extends "events/event_detail.html" %}
{% load i18n comments %} {% load i18n comments %}
{% block maincontent %} {% block maincontent %}

View File

@@ -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<event>[\d]+)/$', EventPhotoList.as_view(),
name='event-photo-list'),
url(r'^(?P<event>[\d]+)/upload/$', EventPhotoUpload.as_view(),
name='event-photo-upload'),
url(r'^(?P<event>[\d]+)/(?P<pk>[\d]+)/$', EventPhoto.as_view(),
name='event-photo'),
url(r'^delete/(?P<pk>[\d]+)/$', DeleteEventPhoto.as_view(),
name='delete-event-photo'),
url(r'^upload/$', EventPhotoUpload.as_view(), name='event-photo-upload'),
)

View File

@@ -5,159 +5,55 @@ from datetime import timedelta
from django.contrib.auth.decorators import permission_required from django.contrib.auth.decorators import permission_required
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.http import HttpResponse, Http404 from django.http import Http404
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils import timezone from django.utils import timezone
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.views import generic from django.views import generic
from icalendar import Calendar, Event
import pyexiv2 import pyexiv2
from utils.mixins import PermissionRequiredMixin from events.models import Event
from .models import Photo
from . import models, forms from . import forms
class DeleteEventPhoto(generic.DeleteView): class DeleteEventPhoto(generic.DeleteView):
model = models.Photo model = Photo
"""
def get_object(self, queryset=None):
return models.Photo.objects.get(pk=self.kwargs['pk'])
"""
def get_success_url(self): def get_success_url(self):
return reverse('event-photo-list', args=[self.object.event.id]) 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')) @method_decorator(permission_required('events.delete_photo'))
def dispatch(self, *args, **kwargs): def dispatch(self, *args, **kwargs):
return super(DeleteEventPhoto, self).dispatch(*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): class EventGallery(generic.ListView):
template_name = 'events/photo_gallery.html' template_name = 'gallery/photo_gallery.html'
queryset = models.Event.objects.filter(start__lt=timezone.now(), photo_count__gt=0) queryset = Event.objects.filter(start__lt=timezone.now(), photo_count__gt=0)
paginate_by = 12 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): class EventPhoto(generic.UpdateView):
form_class = forms.EditPhotoForm form_class = forms.EditPhotoForm
model = models.Photo model = Photo
template_name = 'events/photo_detail.html' template_name = 'gallery/photo_detail.html'
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(EventPhoto, self).get_context_data() context = super(EventPhoto, self).get_context_data()
event = models.Event.objects.get(id=self.kwargs['event']) context['event'] = self.object.event
context['event'] = event
return context return context
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
if request.POST.get('rotate') and request.user.has_perm('events.change_photo'): if request.POST.get('rotate') and request.user.has_perm(
photo = models.Photo.objects.get(pk=kwargs['pk']) 'events.change_photo'):
photo = Photo.objects.get(pk=kwargs['pk'])
photo.rotate(request.POST['rotate']) photo.rotate(request.POST['rotate'])
# return redirect(photo.get_absolute_url()) # return redirect(photo.get_absolute_url())
return self.get(request) return self.get(request)
@@ -172,20 +68,21 @@ class EventPhotoList(generic.ListView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = generic.ListView.get_context_data(self, **kwargs) context = generic.ListView.get_context_data(self, **kwargs)
context['event'] = self.event 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 return context
def get_queryset(self): def get_queryset(self):
try: try:
self.event = models.Event.objects.get(id=self.kwargs['event']) self.event = Event.objects.get(id=self.kwargs['event'])
return models.Photo.objects.filter(event=self.event) return Photo.objects.filter(event=self.event)
except models.Event.DoesNotExist: except Event.DoesNotExist:
raise Http404(_('Event does not exist')) raise Http404(_('Event does not exist'))
class EventPhotoUpload(generic.FormView): class EventPhotoUpload(generic.FormView):
form_class = forms.PhotoUploadForm form_class = forms.PhotoUploadForm
template_name = 'events/photo_upload.html' template_name = 'gallery/photo_upload.html'
@method_decorator(permission_required('events.add_photo')) @method_decorator(permission_required('events.add_photo'))
def dispatch(self, *args, **kwargs): def dispatch(self, *args, **kwargs):
@@ -193,7 +90,7 @@ class EventPhotoUpload(generic.FormView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = generic.FormView.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 return context
def get_initial(self): def get_initial(self):
@@ -208,14 +105,16 @@ class EventPhotoUpload(generic.FormView):
""" """
""" """
self.event = models.Event.objects.get(id=self.request.REQUEST.get('event')) self.event = Event.objects.get(
photographer = self.request.POST.get('photographer', self.request.user.id) id=self.request.REQUEST.get('event'))
photographer = self.request.POST.get('photographer',
self.request.user.id)
photographer = get_user_model().objects.get(id=photographer) photographer = get_user_model().objects.get(id=photographer)
self.counter = 1 self.counter = 1
for upload in self.request.FILES.getlist('upload'): for upload in self.request.FILES.getlist('upload'):
name = upload.name name = upload.name
created_date, description = self.read_exif(upload) created_date, description = self.read_exif(upload)
photo = models.Photo( photo = Photo(
event=self.event, event=self.event,
photographer=photographer, photographer=photographer,
image=upload, image=upload,
@@ -241,7 +140,3 @@ class EventPhotoUpload(generic.FormView):
description = '' description = ''
return created_date, description return created_date, description
class UpcomingEvents(generic.ListView):
queryset = models.Event.objects.upcoming(limit=None)
paginate_by = 16

View File

@@ -299,46 +299,28 @@ ul.info li {
} }
/** PAGINATOR **/ /** PAGINATOR **/
.paginator { .pagination {
clear: both; text-align:center
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;
} }
.paginator a, .paginator .current { .pagination a, .pagination .current, .pagination .next, .pagination .previous {
display: inline-block; display: inline-block;
margin: 0px 2px; text-decoration: none;
padding: 2px; padding: 0 0.5em 0 0.5em;
min-width: 17px;
color: #2e3436;
text-decoration: none;
border-radius: 5px;
} }
.paginator .current { .pagination .next {
border: none;
color: #a40000;
background: #fff;
border-radius: 5px;
}
.paginator .next {
display: inline-block;
float: right; float: right;
background: none;
} }
.paginator .prev {
display: inline-block; .pagination .previous {
float: left; float: left;
background: none;
} }
.center { .center {
text-align: center; text-align: center;
} }

View File

@@ -136,14 +136,14 @@ ul.main_menu {padding:0px;}
width: 920px; width: 920px;
} }
#navigation { #navigation, .pagination {
clear: both; clear: both;
background: url(../img/navigation-bg.png) no-repeat left top; background: url(../img/navigation-bg.png) no-repeat left top;
height: 56px; height: 56px;
list-style: none; list-style: none;
margin: 0 auto; margin: 0 auto;
padding: 8px 0 0 30px; padding: 8px 35px 0px 25px;
width: 920px; width: 900px;
} }
#navigation a { #navigation a {
@@ -434,6 +434,23 @@ ul.tabs li.active a {
text-shadow: 1px 1px 0px #98231a; 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 { img.avatar {
border: none; border: none;
box-shadow: 2px 2px 2px #888; box-shadow: 2px 2px 2px #888;

View File

@@ -337,6 +337,12 @@ fieldset ul li {
} }
ul.tabs {margin-top:1em;} 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 {float: left; width:150px; height:150px; margin: 10px;}
.gallery h3 {font-size: 12pt;} .gallery h3 {font-size: 12pt;}

View File

@@ -1,20 +1,22 @@
{% load i18n %} {% load i18n %}
<div class="paginator grid_12"> <nav class="pagination">
{% if page_obj.has_previous %} {% if page_obj.has_previous %}
<a class="prev" href="?page={{ page_obj.previous_page_number }}"><img src="{{STATIC_URL}}icons/resultset_previous.png" alt="«" /> {% trans "Prev" %}</a> <a class="previous" href="?page={{ page_obj.previous_page_number }}"><span aria-hidden="true">&larr;</span> {% trans "Previous" %}</a></li>
{% else %} {% else %}
<span class="prev disabled"><img src="{{STATIC_URL}}icons/resultset_previous.png" alt="«" /> {% trans "Prev" %}</span> <div class="previous disabled"><span aria-hidden="true">&larr;</span> {% trans "Prev" %}</div>
{% endif %} {% endif %}
{% for page in paginator.page_range %} {% for page in paginator.page_range %}
{% ifequal page_obj.number page %} {% ifequal page_obj.number page %}
<span class="current">{{page}}</span> <div class="current">{{page}}</div>
{% else %} {% else %}
<a class="page" href="?page={{page}}">{{page}}</a> <a href="?page={{page}}">{{page}}</a>
{% endifequal %} {% endifequal %}
{% endfor %} {% endfor %}
{% if page_obj.has_next %} {% if page_obj.has_next %}
<a class="next" href="?page={{ page_obj.next_page_number }}">{% trans "Next" %} <img src="{{STATIC_URL}}icons/resultset_next.png" alt="»" /></a> <a class="next" href="?page={{ page_obj.next_page_number }}">{% trans "Next" %} <span aria-hidden="true">&rarr;</span></a></li>
{% else %} {% else %}
<span class="next disabled">{% trans "Next" %} <img src="{{STATIC_URL}}icons/resultset_next.png" alt="»" /></span> <div class="next disabled">{% trans "Next" %} <span aria-hidden="true">&rarr;</span></div>
{% endif %} {% endif %}
</div> </ul>
</nav>

View File

@@ -30,7 +30,6 @@ DAN_RANKS = (
DAN_RANKS_DICT = dict([(dan, points) for points, dan in DAN_RANKS]) DAN_RANKS_DICT = dict([(dan, points) for points, dan in DAN_RANKS])
MIN_HANCHANS_FOR_LADDER = 10 MIN_HANCHANS_FOR_LADDER = 10
logger = getLogger('kasu.mahjong_ranking') logger = getLogger('kasu.mahjong_ranking')

View File

@@ -7,9 +7,10 @@ Created on 19.09.2011
""" """
# import stuff we need from django # import stuff we need from django
from django.contrib import admin from django.contrib import admin
from django.utils.translation import ugettext as _
from . import models, set_dirty from . import models, set_dirty
from forms import PlayerFormSet from forms import PlayerFormSet
from django.utils.translation import ugettext as _
def recalculate(modeladmin, request, queryset): def recalculate(modeladmin, request, queryset):
@@ -27,7 +28,10 @@ def recalculate(modeladmin, request, queryset):
set_dirty(season=ranking_season.id) set_dirty(season=ranking_season.id)
elif isinstance(modeladmin, LadderRankingAdmin): elif isinstance(modeladmin, LadderRankingAdmin):
for ladder_ranking in queryset: 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") recalculate.short_description = _("Recalculate")
@@ -35,7 +39,7 @@ class PlayerInline(admin.TabularInline):
extra = 4 extra = 4
formset = PlayerFormSet formset = PlayerFormSet
readonly_fields = ('placement', 'kyu_points', 'dan_points', 'bonus_points', readonly_fields = ('placement', 'kyu_points', 'dan_points', 'bonus_points',
'comment',) 'comment',)
max_num = 4 max_num = 4
model = models.Player model = models.Player
@@ -43,7 +47,7 @@ class PlayerInline(admin.TabularInline):
class EventRankingAdmin(admin.ModelAdmin): class EventRankingAdmin(admin.ModelAdmin):
list_filter = ['event'] list_filter = ['event']
list_display = ('placement', 'user', 'event', 'avg_placement', 'avg_score', 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',) list_display_links = ('user',)
actions = [recalculate] actions = [recalculate]
@@ -53,7 +57,7 @@ class HanchanAdmin(admin.ModelAdmin):
date_hierarchy = 'start' date_hierarchy = 'start'
list_filter = ['season', 'event'] list_filter = ['season', 'event']
list_display = ('event', 'start', 'player_names', 'comment', list_display = ('event', 'start', 'player_names', 'comment',
'confirmed', 'valid', 'check_validity') 'confirmed', 'valid', 'check_validity')
inlines = (PlayerInline,) inlines = (PlayerInline,)
readonly_fields = ('valid', 'check_validity') readonly_fields = ('valid', 'check_validity')
@@ -66,13 +70,14 @@ class HanchanAdmin(admin.ModelAdmin):
class KyuDanAdmin(admin.ModelAdmin): class KyuDanAdmin(admin.ModelAdmin):
actions = [recalculate] actions = [recalculate]
list_display = ('user', 'kyu', 'kyu_points', 'dan', 'dan_points', list_display = ('user', 'kyu', 'kyu_points', 'dan', 'dan_points',
'hanchan_count', 'dirty') 'hanchan_count', 'dirty')
class LadderRankingAdmin(admin.ModelAdmin): class LadderRankingAdmin(admin.ModelAdmin):
actions = [recalculate] actions = [recalculate]
list_display = ('placement', 'season', 'user', 'avg_placement', 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_display_links = ('user',)
list_filter = ('season',) list_filter = ('season',)

View File

@@ -12,7 +12,6 @@ from django.utils import timezone
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from utils.html5 import forms from utils.html5 import forms
from . import models from . import models
@@ -81,7 +80,6 @@ class PlayerForm(forms.ModelForm):
class PlayerInlineFormSet(BaseInlineFormSet): class PlayerInlineFormSet(BaseInlineFormSet):
def clean(self): def clean(self):
"""Checks that no two articles have the same title.""" """Checks that no two articles have the same title."""
for form in self.forms: for form in self.forms:
@@ -102,6 +100,7 @@ class SeasonSelectForm(django.forms.Form):
season_list = season_list.values_list('season__id', 'season__name') season_list = season_list.values_list('season__id', 'season__name')
self.fields['season'] = django.forms.ChoiceField(choices=season_list) self.fields['season'] = django.forms.ChoiceField(choices=season_list)
PlayerFormSet = inlineformset_factory( PlayerFormSet = inlineformset_factory(
models.Hanchan, models.Hanchan,
models.Player, models.Player,

View File

@@ -4,13 +4,16 @@
Generate Randum Mahjong Hanchans to the the Raning System 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 import random
from datetime import timedelta 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): class Command(BaseCommand):
help = "Deletes all expired user registrations from the database" help = "Deletes all expired user registrations from the database"
@@ -23,7 +26,8 @@ class Command(BaseCommand):
player_list = list() player_list = list()
ostwind_list = list() ostwind_list = list()
for user in user_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: for player in player_list:
player.save() player.save()
@@ -33,8 +37,8 @@ class Command(BaseCommand):
ostwind = ostwind_list.pop() ostwind = ostwind_list.pop()
while not end_of_game: while not end_of_game:
score = random.randrange(1300, 8000, 100) score = random.randrange(1300, 8000, 100)
loser = player_list[random.randrange(0,4,1)] loser = player_list[random.randrange(0, 4, 1)]
winner = player_list[random.randrange(0,4,1)] winner = player_list[random.randrange(0, 4, 1)]
winner.score += score winner.score += score
print 'Ostwind: %s, Gewinner: %s, Verlierer: %s, %d Punkte' % ( print 'Ostwind: %s, Gewinner: %s, Verlierer: %s, %d Punkte' % (
@@ -73,9 +77,9 @@ class Command(BaseCommand):
print "" print ""
def create_hanchan(self, event): 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 event.name, start
print '='*80 print '=' * 80
hanchan = models.Hanchan(event=event, start=start) hanchan = models.Hanchan(event=event, start=start)
hanchan.save() hanchan.save()
self.add_players(hanchan) self.add_players(hanchan)
@@ -87,7 +91,7 @@ class Command(BaseCommand):
self.user_list = list(auth.get_user_model().objects.all()) self.user_list = list(auth.get_user_model().objects.all())
for event in Event.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) self.create_hanchan(event)

View File

@@ -6,6 +6,7 @@ Created on 23.05.2011
""" """
from django.core.cache import cache from django.core.cache import cache
from django.db import transaction from django.db import transaction
from mahjong_ranking import models from mahjong_ranking import models
from . import logger from . import logger
@@ -30,7 +31,8 @@ class DenormalizationUpdateMiddleware(object):
if len(event_ranking_queue) > 0: if len(event_ranking_queue) > 0:
while len(event_ranking_queue) > 0: while len(event_ranking_queue) > 0:
event_id, user_id = event_ranking_queue.pop() 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( ranking = models.EventRanking.objects.get_or_create(
event_id=event_id, user_id=user_id)[0] event_id=event_id, user_id=user_id)[0]
ranking.recalculate() ranking.recalculate()
@@ -57,7 +59,8 @@ class DenormalizationUpdateMiddleware(object):
user_id=user_id, season_id=season_id)[0] user_id=user_id, season_id=season_id)[0]
ranking.recalculate() ranking.recalculate()
else: 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) cache.set('ladder_ranking_queue', ladder_ranking_queue, 360)
transaction.commit() transaction.commit()

View File

@@ -1,6 +1,7 @@
# -*- encoding: utf-8 -*- # -*- encoding: utf-8 -*-
from datetime import date, timedelta from datetime import date, timedelta
from django.conf import settings from django.conf import settings
from django.core.cache import cache from django.core.cache import cache
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
@@ -9,11 +10,12 @@ from django.db import models
from django.db.models.aggregates import Sum from django.db.models.aggregates import Sum
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext as _ 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 KYU_RANKS, DAN_RANKS, DAN_RANKS_DICT, MIN_HANCHANS_FOR_LADDER
from . import logger, set_dirty from . import logger, set_dirty
kyu_dan_rankings = set() kyu_dan_rankings = set()
ladder_rankings = set() ladder_rankings = set()
ladder_seasons = set() ladder_seasons = set()
@@ -53,8 +55,10 @@ class EventRanking(models.Model):
zur neuberrechnung zu markieren. Mittlerweile wird ein lokaler zur neuberrechnung zu markieren. Mittlerweile wird ein lokaler
Cache dafür verwendet, das ist schneller. Cache dafür verwendet, das ist schneller.
""" """
logger.info(u'Recalculate EventRanking for Player %s in %s', self.user, self.event.name) # @IgnorePep8 logger.info(u'Recalculate EventRanking for Player %s in %s', self.user,
event_hanchans = Player.objects.valid_hanchans(user=self.user_id, event=self.event_id) # @IgnorePep8 self.event.name) # @IgnorePep8
event_hanchans = Player.objects.valid_hanchans(user=self.user_id,
event=self.event_id) # @IgnorePep8
aggregator = event_hanchans.aggregate( aggregator = event_hanchans.aggregate(
models.Avg('placement'), models.Avg('placement'),
models.Avg('score'), models.Avg('score'),
@@ -78,7 +82,9 @@ class Hanchan(models.Model):
Außerdem gehört jede Hanchan zu einer Veranstaltung. Außerdem gehört jede Hanchan zu einer Veranstaltung.
""" """
comment = models.TextField(_('Comment'), blank=True) 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) event = models.ForeignKey(Event)
player_names = models.CharField(max_length=127, editable=False) player_names = models.CharField(max_length=127, editable=False)
players = models.ManyToManyField( players = models.ManyToManyField(
@@ -86,8 +92,10 @@ class Hanchan(models.Model):
through='Player', through='Player',
verbose_name=_('Players') verbose_name=_('Players')
) )
season = models.ForeignKey('LadderSeason', blank=True, null=True, editable=False) # @IgnorePep8 season = models.ForeignKey('LadderSeason', blank=True, null=True,
start = models.DateTimeField(_('Start'), help_text=_('This is crucial to get the right Hanchans that scores')) # @IgnorePep8 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) valid = models.BooleanField(_('Is Valid'), default=False)
class Meta(object): class Meta(object):
@@ -96,7 +104,8 @@ class Hanchan(models.Model):
verbose_name_plural = _(u'Hanchans') verbose_name_plural = _(u'Hanchans')
def __str__(self): 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): 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 Die Gültigkeit wird geprüft und die Sasion in der die Hanchan liegt
wird aktualisert. wird aktualisert.
""" """
logger.debug("Hanchan clean() wurde getriggert!") super(Hanchan, self).clean()
# if self.pk and self.player_set.distinct().count() != 4: # if self.pk and self.player_set.distinct().count() != 4:
# raise ValidationError( # raise ValidationError(
# _('For a Hanchan exactly 4 players are needed.')) # _('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.")) raise ValidationError(_("It's not allowed to enter future games."))
elif not (self.event.start <= self.start <= self.event.end): elif not (self.event.start <= self.start <= self.event.end):
raise ValidationError(_("Only games during the event are allowed")) raise ValidationError(_("Only games during the event are allowed"))
@@ -195,7 +206,8 @@ class Hanchan(models.Model):
def save(self, **kwargs): def save(self, **kwargs):
logger.debug("Hanchan save() wurde getriggert!") 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: if self.pk:
self.check_validity() self.check_validity()
self.compute_player_placements() self.compute_player_placements()
@@ -245,7 +257,8 @@ class KyuDanRanking(models.Model):
self.wins_in_a_row = 0 self.wins_in_a_row = 0
if self.dan and self.wins_in_a_row > 2: 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_rank = self.dan + 1
new_dan_points = DAN_RANKS_DICT[new_dan_rank] + 1 new_dan_points = DAN_RANKS_DICT[new_dan_rank] + 1
bonus_points = new_dan_points - self.dan_points 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("Stats for %s:", self.user)
logger.debug("current dan_points: %d", self.dan_points) logger.debug("current dan_points: %d", self.dan_points)
logger.debug("current dan: %d", self.dan) 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) logger.debug("bonus points to add: %d", bonus_points)
hanchan.dan_points += bonus_points hanchan.dan_points += bonus_points
@@ -424,7 +438,8 @@ class LadderRanking(models.Model):
return reverse('player-ladder-score', args=[self.user.username]) return reverse('player-ladder-score', args=[self.user.username])
def recalculate(self): 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( ladder_hanchans = Player.objects.ladder_hanchans(
self.user_id, self.season_id) self.user_id, self.season_id)
aggregate = ladder_hanchans.aggregate( aggregate = ladder_hanchans.aggregate(
@@ -443,7 +458,6 @@ class LadderRanking(models.Model):
class LadderSeasonManager(models.Manager): class LadderSeasonManager(models.Manager):
def current(self): def current(self):
""" """
Returns the current season and caches the result for 12 hours Returns the current season and caches the result for 12 hours
@@ -489,6 +503,14 @@ class LadderSeason(models.Model):
def __unicode__(self): def __unicode__(self):
return self.name 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): def recalculate(self):
logger.info(u'Recalculate LadderSeason %s', self.name) logger.info(u'Recalculate LadderSeason %s', self.name)
self.ladderranking_set.update(placement=None) self.ladderranking_set.update(placement=None)
@@ -519,7 +541,8 @@ class PlayerManager(models.Manager):
queryset = queryset.filter(kyu_points__isnull=False).select_related() queryset = queryset.filter(kyu_points__isnull=False).select_related()
return queryset 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 = self.valid_hanchans(user).order_by('-hanchan__start')
queryset = queryset.select_related() queryset = queryset.select_related()
season = season or LadderSeason.objects.current() season = season or LadderSeason.objects.current()
@@ -593,7 +616,8 @@ class Player(models.Model):
ordering = ['-score'] ordering = ['-score']
def __str__(self): 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): def save(self, mark_dirty=True, season_id=None, *args, **kwargs):
season_id = season_id or self.hanchan.season_id season_id = season_id or self.hanchan.season_id
@@ -606,12 +630,15 @@ class Player(models.Model):
else: else:
return self return self
if season_id: 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) set_dirty(season=season_id, user=self.user_id)
logger.debug("Marking season no %i for recalculation.", season_id) logger.debug("Marking season no %i for recalculation.", season_id)
set_dirty(season=season_id) set_dirty(season=season_id)
if self.hanchan.event.is_tournament: 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) set_dirty(event=self.hanchan.event_id, user=self.user_id)
return self return self
@@ -622,4 +649,5 @@ def update_ranking_delete(sender, instance, **kwargs): # @UnusedVariable
if instance.season_id: if instance.season_id:
set_dirty(season=instance.season_id, user=player.user_id) set_dirty(season=instance.season_id, user=player.user_id)
models.signals.pre_delete.connect(update_ranking_delete, sender=Hanchan) models.signals.pre_delete.connect(update_ranking_delete, sender=Hanchan)

View File

@@ -1,17 +1,11 @@
{% extends "events/event_site.html" %} {% extends "events/event_detail.html" %}
{% load i18n comments%} {% load i18n comments%}
{% block title %}{% trans "Tournament Ranking" %}: {{ event.name }}{% endblock %} {% block title %}{% trans "Tournament Ranking" %}: {{ event.name }}{% endblock %}
{% block teaser %}<h1>{% trans "Tournament Ranking" %}: {{ event.name }}</h1>{% endblock %}
{% block event_content %} {% block maincontent %}
{% if event.is_tournament %}
<ul class="tabs grid_12">
<li><a href="{% url 'event-hanchan-list' event.id %}">{% trans "Tournament Hanchans" %}</a></li>
<li class="active"><a href="{% url 'event-ranking' event.id %}">{% trans "Tournament Ranking" %}</a></li>
</ul>
{% endif %}
<div class="grid_12"> <div class="grid_12">
<table> <table>
<thead> <thead>
@@ -21,13 +15,14 @@
<th rowspan="2">{% trans "Nickname" %}</th> <th rowspan="2">{% trans "Nickname" %}</th>
<th rowspan="2">{% trans "Name" %}</th> <th rowspan="2">{% trans "Name" %}</th>
<th colspan="2">{% trans 'Average' %}</th> <th colspan="2">{% trans 'Average' %}</th>
<th colspan="2">Hanchans</th> <th colspan="3">Hanchans</th>
</tr> </tr>
<tr> <tr>
<th>{% trans 'Placement' %}</th> <th>{% trans 'Placement' %}</th>
<th>{% trans "Score" %}</th> <th>{% trans "Score" %}</th>
<th>{% trans "won" %}</th> <th>{% trans "count" %}</th>
<th>{% trans "good" %}</th> <th>{% trans "good" %}</th>
<th>{% trans "won" %}</th>
</tr> </tr>
</thead> </thead>
{% for player in eventranking_list %} {% for player in eventranking_list %}
@@ -42,11 +37,12 @@
{% endif %} {% endif %}
</a></td> </a></td>
<td><a href="{{ player.user.get_absolute_url }}">{{player.user}}</a></td> <td><a href="{{ player.user.get_absolute_url }}">{{player.user}}</a></td>
<td>{{profile.last_name}} {{profile.first_name}}</td> <td>{% if user.is_authenticated %}{{profile.last_name}} {{profile.first_name}}{% else %} ---{% endif %}</td>
<td class="center">{{player.avg_placement|floatformat:2 }}</td> <td class="center">{{player.avg_placement|floatformat:2 }}</td>
<td class="right">{{player.avg_score|floatformat:0 }}</td> <td class="right">{{player.avg_score|floatformat:0 }}</td>
<td class="center">{{player.won_hanchans}}</td> <td class="right">{{player.hanchan_count}}</td>
<td class="center">{{player.good_hanchans}}</td> <td class="right">{{player.good_hanchans}}</td>
<td class="right">{{player.won_hanchans}}</td>
</tr> </tr>
{% endwith %} {% endwith %}
{% empty %} {% empty %}

View File

@@ -1,10 +1,10 @@
{% extends "base.html" %} {% extends "events/event_detail.html" %}
{% load i18n comments %} {% load i18n comments %}
{% block meta_title %}{% trans 'Delete Hanchan' %}{% endblock %} {% block meta_title %}{% trans 'Delete Hanchan' %}{% endblock %}
{% block content %} {% block maincontent %}
<form method="post"> <form method="post" class="grid_12">
{% csrf_token %} {% csrf_token %}
<fieldset> <fieldset>
<legend>{% trans "Delete Hanchan" %}</legend> <legend>{% trans "Delete Hanchan" %}</legend>

View File

@@ -1,11 +1,11 @@
{% extends "events/event_site.html" %} {% extends "events/event_detail.html" %}
{% load i18n comments fieldset_extras %} {% load i18n comments fieldset_extras %}
{% block title %} {% block title %}
{% if hanchan.id %}{% trans "Edit Hanchan" %}{% else %}{% trans "Add Hanchan" %}{% endif %} {% if hanchan.id %}{% trans "Edit Hanchan" %}{% else %}{% trans "Add Hanchan" %}{% endif %}
{% endblock %} {% endblock %}
{% block event_content %} {% block maincontent %}
{% get_fieldset "event, start" from form as event_formset %} {% get_fieldset "event, start" from form as event_formset %}
{% if perms.mahjong_ranking.delete_hanchan %} {% if perms.mahjong_ranking.delete_hanchan %}
{% get_fieldset "comment, confirmed" from form as hanchan_formset %} {% get_fieldset "comment, confirmed" from form as hanchan_formset %}

View File

@@ -1,53 +1,56 @@
{% extends "events/event_site.html" %} {% extends "events/event_detail.html" %}
{% load i18n humanize %}
{% load i18n comments %}
{% block title %}Hanchans: {{ event.name }}{% endblock %} {% block title %}Hanchans: {{ event.name }}{% endblock %}
{% block event_content %} {% block maincontent %}
<h2 class="grid_12">{% trans 'Played Hanchans' %}</h2>
{% if event.is_tournament %} <p>&nbsp;</p>
<ul class="tabs grid_12">
<li class="active"><a href="{% url 'event-hanchan-list' event.id %}">{% trans "Tournament Hanchans" %}</a></li>
<li><a href="{% url 'event-ranking' event.id %}">{% trans "Tournament Ranking" %}</a></li>
</ul>
{% endif %}
{% for hanchan in hanchan_list %} {% for hanchan in hanchan_list %}
<h3 class="grid_12 clearfix" id="{{ hanchan.pk }}">{{hanchan.start|time:'H:i'}}: {{ hanchan.player_names }}</h3> <div class="grid_12" id="{{ hanchan.pk }}"><h3>{{hanchan.start|time:'H:i'}}: {{ hanchan.player_names }}</h3></div>
{% for player in hanchan.player_set.all %} {% for player in hanchan.player_set.all %}
<div class="player" > <a class="grid_1" href="{% url 'player-ladder-score' player.user %}"><img src="{% if player.user.get_profile.thumbnail %}{{player.user.get_profile.thumbnail.url}}{% else %}{{STATIC_URL}}img/unknown_thumbnail.png{% endif %}" class="avatar" alt="{{ player.user }}" title="{{ player.user }}"/></a>
<a href="{% url 'player-ladder-score' player.user %}"><img <div class="grid_2">
src="{% if player.user.get_profile.thumbnail %}{{player.user.get_profile.thumbnail.url}}{% else %}{{STATIC_URL}}img/unknown_thumbnail.png{% endif %}" <a class="player" href="{% url 'player-ladder-score' player.user %}" title="{{ player.comment }}">{{ player.user }}</a>
class="avatar" alt="" <p><strong>{{ player.placement|ordinal }} {% trans 'Place' %}</strong><br />
title="{% if player.dan_points != None %}Dan P.: {{player.dan_points}}{% else %}Kyu P.: {{player.kyu_points}}{% endif %} - {{player.comment}}"/></a> <strong>{% trans 'Score' %}:</strong> {{ player.score|intcomma }}<br />
<h4>{{player.placement}}. - <a href="{% url 'player-ladder-score' player.user %}">{{ player.user }}</a></h4> {% if player.dan_points != None %}
<strong>{% trans 'Score' %}:</strong> {{player.score}} <strong>{% trans 'Dan Points' %}:</strong> {{ player.dan_points }}
</div> {% else %}
{% endfor %} <strong>{% trans 'Kyu Points' %}:</strong> {{ player.kyu_points|default:0 }}
{% if not hanchan.valid %} {% endif %}
<p class="grid_12 error"><strong>Ungültig:</strong> {{hanchan.check_validity}}</p> </p>
{% elif not hanchan.confirmed %} </div>
<p class="grid_12 error">Diese Hanchan wurde nicht anerkannt und wird daher nicht gezählt.</p> {% endfor %}
{% elif hanchan.comment %} {% if not hanchan.valid %}
<p class="grid_12">{{ hanchan.comment }}</p> <p class="grid_12 error"><strong>Ungültig:</strong> {{hanchan.check_validity}}</p>
{% endif %} {% elif not hanchan.confirmed %}
<p class="grid_12 more_link"> <p class="grid_12 error">Diese Hanchan wurde nicht anerkannt und wird daher nicht gezählt.</p>
{% if perms.mahjong_ranking.delete_hanchan %} {% elif hanchan.comment %}
<a href="{% url 'delete-hanchan' hanchan.pk %}" class="button"><img src="{{STATIC_URL}}icons/table_delete.png" alt="{% trans 'Delete' %}"/> {% trans 'Delete Hanchan' %}</a> <p class="grid_12">{{ hanchan.comment }}</p>
{% endif %} {% endif %}
{% if perms.mahjong_ranking.change_hanchan %} <p class="grid_12 more_link">
<a href="{% url 'edit-hanchan' hanchan.pk %}" class="button"><img src="{{STATIC_URL}}icons/table_edit.png" alt="{% trans 'Edit' %}"/> {% trans 'Edit Hanchan' %}</a> {% if perms.mahjong_ranking.delete_hanchan %}
{% endif %} <a href="{% url 'delete-hanchan' hanchan.pk %}" class="button"><img src="{{STATIC_URL}}icons/table_delete.png"
</p> alt="{% trans 'Delete' %}"/>
{% trans 'Delete Hanchan' %}</a>
{% endif %}
{% if perms.mahjong_ranking.change_hanchan %}
<a href="{% url 'edit-hanchan' hanchan.pk %}" class="button"><img src="{{STATIC_URL}}icons/table_edit.png"
alt="{% trans 'Edit' %}"/>
{% trans 'Edit Hanchan' %}</a>
{% endif %}
</p>
{% empty %} {% empty %}
<h3 class="grid_12">{% trans 'No Hanchan has been added to this event yet.'%}</h3> <h3 class="grid_12">{% trans 'No Hanchan has been added to this event yet.'%}</h3>
{% endfor %} {% endfor %}
{% endblock %} {% endblock %}
{% block buttonbar %} {% block buttonbar %}
{% if perms.mahjong_ranking.add_hanchan %} {% if perms.mahjong_ranking.add_hanchan %}
<a class="button" href="{{event.get_edit_url}}"><img src="{{STATIC_URL}}icons/calendar_edit.png" alt="{% trans 'Add' %}"/> {% trans 'Edit Event' %}</a> <a class="button" href="{{event.get_edit_url}}"><img src="{{STATIC_URL}}icons/calendar_edit.png"
<a class="button" href="{% url 'add-hanchan-form' event.id %}"><img src="{{STATIC_URL}}icons/table_add.png" alt="{% trans 'Add' %}"/> {% trans 'Add Hanchan' %}</a> alt="{% trans 'Add' %}"/> {% trans 'Edit Event' %}</a>
{% endif %} <a class="button" href="{% url 'add-hanchan-form' event.id %}"><img src="{{STATIC_URL}}icons/table_add.png"
alt="{% trans 'Add' %}"/> {% trans 'Add Hanchan' %}</a>
{% endif %}
{% endblock %} {% endblock %}

View File

@@ -1,7 +1,9 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load i18n comments%} {% load i18n comments%}
{% block teaser %} <h2>Mahjong Ranking - {{season.name}}</h2> {% endblock %} {% block teaser %}
<h2>Mahjong Ranking - {{season.name}}</h2>
{% endblock %}
{% block maincontent %} {% block maincontent %}
<main class="grid_12"> <main class="grid_12">
@@ -49,14 +51,6 @@
{% endblock %} {% endblock %}
{% block redbox %} {% block redbox %}
{% if is_archive %}
<h2>{% trans 'Ladder Archive' %}</h2>
<ul class="list">
{% for season in season_archive %}
<li class="season"><a href="{% url 'mahjong-ladder-archive' season.id %}">{{season.name}}</a></li>
{% endfor %}
</ul>
{% else %}
<h2>{% trans 'Latest Hanchans' %}</h2> <h2>{% trans 'Latest Hanchans' %}</h2>
<ul class="list"> <ul class="list">
{% for hanchan in latest_hanchan_list %} {% for hanchan in latest_hanchan_list %}
@@ -69,9 +63,17 @@
</ul> </ul>
<h3>{% trans 'Latest Events' %}</h3> <h3>{% trans 'Latest Events' %}</h3>
<ul class="list"> <ul class="list">
{% for event in latest_event_list|slice:":3" %} {% for event in latest_event_list %}
<li class="event"><a href="{% url 'event-hanchan-list' event.pk %}">{{event.name}}</a></li> <li class="event"><a href="{% url 'event-hanchan-list' event.pk %}">{{event.name}}</a></li>
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %} <h3>{% trans 'Ladder Archive' %}</h3>
<form name="season_select">
<label for="season">{% trans 'Season' %}</label>
<select id="season" name="season" size="1" onChange="window.location.href = document.season_select.season.options[document.season_select.season.selectedIndex].value;">
{% for season_link in season_list%}
<option value="{{ season_link.get_absolute_url }}" {% ifequal season.id season_link.id %}selected="selected"{% endifequal %}>{{ season_link.name }}</option>
{% endfor %}
</select>
</form>
{% endblock %} {% endblock %}

View File

@@ -2,7 +2,9 @@
{% load i18n %} {% load i18n %}
{% block title %} {% trans 'Kyu Score for' %} {{player.username}} {% endblock %} {% block title %} {% trans 'Kyu Score for' %} {{player.username}} {% endblock %}
{% block teaser %}<h2>{% trans 'Invalid hanchans with' %} {{membership.user.username}}</h2>{% endblock %} {% block teaser %}<h2>{% trans 'Invalid hanchans with' %} {{membership.user.username}}</h2>{% endblock %}
{% block score_list %} {% block score_list %}
<div class="grid_12"> <div class="grid_12">
<h2>{% trans 'Invalid hanchans with' %} {{membership.user.username}}</h2> <h2>{% trans 'Invalid hanchans with' %} {{membership.user.username}}</h2>

View File

@@ -6,49 +6,37 @@ Created on 03.10.2011
@author: christian @author: christian
""" """
from django.conf.urls import * # @UnusedWildImport from django.conf.urls import * # @UnusedWildImport
from django.views.generic import RedirectView
import views import views
urlpatterns = patterns( urlpatterns = patterns(
'', '',
url(r'^$', views.LadderRankingList.as_view(), name="mahjong-ladder"), url('^$', RedirectView.as_view(pattern_name='mahjong-ladder')),
url(r'archive/$', url(r'players/$', views.KyuDanRankingList.as_view(),
views.LadderRankingList.as_view(),
kwargs={'is_archive': True},
name="mahjong-ladder-archive"),
url(r'archive/(?P<season>[\d]+)/$',
views.LadderRankingList.as_view(),
name="mahjong-ladder-archive"),
url(r'players/$',
views.KyuDanRankingList.as_view(),
name="kyudanranking-list"), name="kyudanranking-list"),
url(r'players/(?P<order_by>[\+\-\w]+)/$', url(r'players/(?P<order_by>[\+\-\w]+)/$', views.KyuDanRankingList.as_view(),
views.KyuDanRankingList.as_view(),
name="kyudanranking-list"), name="kyudanranking-list"),
url(r'event/(?P<event>[\d]+)/$', url(r'ranking/$', views.LadderRankingList.as_view(), name="mahjong-ladder"),
views.EventHanchanList.as_view(), url(r'ranking/(?P<season>[\d]+)/$', views.LadderRankingList.as_view(),
name="mahjong-ladder"),
url(r'ranking/event/(?P<event>[\d]+)/$', views.EventHanchanList.as_view(),
name="event-hanchan-list"), name="event-hanchan-list"),
url(r'event/(?P<event>[\d]+)/ranking/$', url(r'ranking/event/(?P<event>[\d]+)/ranking/$',
views.EventRankingList.as_view(), views.EventRankingList.as_view(), name="event-ranking"),
name="event-ranking"), url(r'ranking/event/(?P<event>[\d]+)/add-hanchan/$',
url(r'event/(?P<event>[\d]+)/add-hanchan/$', views.HanchanForm.as_view(), name="add-hanchan-form"),
views.HanchanForm.as_view(), url(r'hanchan/(?P<hanchan>[\d]+)/edit/$', views.HanchanForm.as_view(),
name="add-hanchan-form"),
url(r'hanchan/(?P<hanchan>[\d]+)/edit/$',
views.HanchanForm.as_view(),
name="edit-hanchan"), name="edit-hanchan"),
url(r'hanchan/(?P<hanchan>[\d]+)/delete/$', url(r'hanchan/(?P<hanchan>[\d]+)/delete/$', views.DeleteHanchan.as_view(),
views.DeleteHanchan.as_view(),
name="delete-hanchan"), name="delete-hanchan"),
url(r'dan_score/(?P<username>[\-\.\d\w]+)/$', url(r'player/(?P<username>[\-\.\d\w]+)/dan/$',
views.PlayerDanScore.as_view(), views.PlayerDanScore.as_view(), name="player-dan-score"),
name="player-dan-score"), url(r'player/(?P<username>[\-\.\d\w]+)/invalid/$',
url(r'invalid_score/(?P<username>[\-\.\d\w]+)/$', views.PlayerInvalidScore.as_view(), name="player-invalid-score"),
views.PlayerInvalidScore.as_view(), url(r'player/(?P<username>[\-\.\d\w]+)/kyu/$',
name="player-invalid-score"), views.PlayerKyuScore.as_view(), name="player-kyu-score"),
url(r'kyu_score/(?P<username>[\-\.\d\w]+)/$', url(r'player/(?P<username>[\-\.\d\w]+)/ladder/$',
views.PlayerKyuScore.as_view(), views.PlayerLadderScore.as_view(), name="player-ladder-score"),
name="player-kyu-score"),
url(r'ladder_score/(?P<username>[\-\.\d\w]+)/$',
views.PlayerLadderScore.as_view(),
name="player-ladder-score"),
) )

View File

@@ -11,6 +11,7 @@ from django.views import generic
import xlwt import xlwt
from events.models import Event from events.models import Event
from events.views import EventDetailMixin
from . import forms, models from . import forms, models
from membership.models import Membership from membership.models import Membership
from utils.mixins import LoginRequiredMixin, PermissionRequiredMixin 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. Fragt zuerst nach, ob die Hanchan wirklich gelöscht werden soll.
Wir die Frage mit "Ja" beantwortet, wird die die Hanchan gelöscht. 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): def get_success_url(self):
return reverse('event-hanchan-list', 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 Ein Formular um eine neue Hanchan anzulegen, bzw. eine bestehende zu
bearbeitsen bearbeitsen
@@ -130,7 +131,7 @@ class HanchanForm(PermissionRequiredMixin, generic.UpdateView):
return self.form_invalid(form, formset) 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. Auflistung aller Hanchan die während der Veranstaltung gespielt wurden.
""" """
@@ -146,13 +147,8 @@ class EventHanchanList(generic.ListView):
except models.Event.DoesNotExist: except models.Event.DoesNotExist:
raise django.http.Http404(_('Event does not exist')) 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(EventDetailMixin, generic.ListView):
class EventRankingList(generic.ListView):
""" """
Anzeige des Eventrankings, daß erstellt wurde falls der Termin als internes Anzeige des Eventrankings, daß erstellt wurde falls der Termin als internes
Turnier markiert wurde. Turnier markiert wurde.
@@ -168,11 +164,6 @@ class EventRankingList(generic.ListView):
except models.Event.DoesNotExist: except models.Event.DoesNotExist:
raise django.http.Http404(_('Event does not exist')) 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): class KyuDanRankingList(generic.ListView):
""" """
@@ -183,7 +174,8 @@ class KyuDanRankingList(generic.ListView):
paginate_by = 25 paginate_by = 25
def dispatch(self, request, *args, **kwargs): 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) return generic.ListView.dispatch(self, request, *args, **kwargs)
def get_queryset(self): def get_queryset(self):
@@ -202,7 +194,8 @@ class LadderRankingList(generic.ListView):
def get_queryset(self): def get_queryset(self):
try: try:
if self.kwargs.get('season'): 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 self.is_archive = True
elif self.kwargs.get('is_archive'): elif self.kwargs.get('is_archive'):
self.season = models.LadderSeason.objects.order_by('-pk')[1] self.season = models.LadderSeason.objects.order_by('-pk')[1]
@@ -211,16 +204,18 @@ class LadderRankingList(generic.ListView):
self.season = models.LadderSeason.objects.current() self.season = models.LadderSeason.objects.current()
except models.LadderSeason.DoesNotExist: except models.LadderSeason.DoesNotExist:
raise django.http.Http404(_('Season does not exist')) 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 return queryset
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = generic.ListView.get_context_data(self, **kwargs) context = generic.ListView.get_context_data(self, **kwargs)
context['is_archive'] = self.is_archive context['is_archive'] = self.is_archive
context['season'] = self.season context['season'] = self.season
context['season_archive'] = models.LadderSeason.objects.all() context['season_list'] = models.LadderSeason.objects.all()
context['latest_hanchan_list'] = models.Hanchan.objects.filter(valid=True)[:5] context['latest_hanchan_list'] = models.Hanchan.objects.filter(
context['latest_event_list'] = Event.objects.archive()[:5] valid=True)[:3]
context['latest_event_list'] = Event.objects.archive()[:3]
return context return context
@@ -238,11 +233,13 @@ class LadderRankingExcel(generic.View):
response = django.http.HttpResponse(mimetype=u'application/msexcel') response = django.http.HttpResponse(mimetype=u'application/msexcel')
filename = urllib.quote(self.filename.encode('utf-8')) 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", field_names = [u"Login", u"Name", u"E-Mail", u"Telefon", u"Handy",
u"T-Shirt", u"Teams", u"Gr.", u"Kg", u"Notfall Adresse", u"Geburtstag",
u"Notfall Nummer", u"Notizen", ] 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) # 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 = workbook.add_sheet('Mitglieder', cell_overwrite_ok=False)
sheet.set_panes_frozen(True) sheet.set_panes_frozen(True)
sheet.set_horz_split_pos(1) # in general, freeze after last heading row 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)): for column in range(0, len(field_names)):
sheet.write(0, column, field_names[column], style=header) sheet.write(0, column, field_names[column], style=header)
@@ -267,13 +265,17 @@ class LadderRankingExcel(generic.View):
profile = user.get_profile() profile = user.get_profile()
self.set_col(sheet, current_row, 3, profile.telephone or None) 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, 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, 5, profile.birthday or None,
self.set_col(sheet, current_row, 6, profile.shirt_size or None, style=self.center) 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, 7, self.get_other_teams(user))
self.set_col(sheet, current_row, 8, profile.height or None) 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, 9, profile.weight or None)
self.set_col(sheet, current_row, 10, profile.emergency_contact or None) self.set_col(sheet, current_row, 10,
self.set_col(sheet, current_row, 11, profile.emergency_phone or None) profile.emergency_contact or None)
self.set_col(sheet, current_row, 11,
profile.emergency_phone or None)
except Membership.DoesNotExist: except Membership.DoesNotExist:
pass pass
current_row += 1 current_row += 1
@@ -290,17 +292,22 @@ class PlayerScore(LoginRequiredMixin, generic.ListView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
try: try:
self.user = auth.get_user_model().objects.get(username=self.kwargs.get('username')) self.user = auth.get_user_model().objects.get(
self.membership = Membership.objects.get_or_create(user=self.user)[0] username=self.kwargs.get('username'))
self.membership = Membership.objects.get_or_create(user=self.user)[
0]
except auth.get_user_model().DoesNotExist: 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) return generic.ListView.get(self, request, *args, **kwargs)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = generic.ListView.get_context_data(self, **kwargs) context = generic.ListView.get_context_data(self, **kwargs)
context['membership'] = self.membership context['membership'] = self.membership
try: 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: except models.KyuDanRanking.DoesNotExist:
context['ranking'] = None context['ranking'] = None
try: try:
@@ -312,7 +319,6 @@ class PlayerScore(LoginRequiredMixin, generic.ListView):
return context return context
class PlayerDanScore(PlayerScore): class PlayerDanScore(PlayerScore):
template_name = 'mahjong_ranking/player_dan_score.html' template_name = 'mahjong_ranking/player_dan_score.html'
@@ -339,16 +345,20 @@ class PlayerLadderScore(PlayerScore):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = PlayerScore.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') season_list = season_list.values_list('id', 'season__name')
context['season'] = self.season context['season'] = self.season
context['seasons_select_form'] = forms.SeasonSelectForm(user=self.user) 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 return context
def get_queryset(self, **kwargs): def get_queryset(self, **kwargs):
if self.request.GET.get('season'): 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: else:
self.season = models.LadderSeason.objects.current() 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)

View File

@@ -3,6 +3,6 @@ import os
import sys import sys
if __name__ == "__main__": if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "kasu.settings")
from django.core.management import execute_from_command_line from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv) execute_from_command_line(sys.argv)

View File

@@ -5,10 +5,11 @@ Created on 19.09.2011
""" """
# import stuff we need from django # import stuff we need from django
from django.contrib import admin from django.contrib import admin
from membership.models import Membership, ActivationRequest
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from imagekit.admin import AdminThumbnail from imagekit.admin import AdminThumbnail
from membership.models import Membership, ActivationRequest
def activate_user(modeladmin, request, queryset): def activate_user(modeladmin, request, queryset):
for activation in queryset: for activation in queryset:
@@ -45,7 +46,8 @@ class MembershipAdmin(admin.ModelAdmin):
list_display_links = ('nickname',) list_display_links = ('nickname',)
fieldsets = ( fieldsets = (
(None, { (None, {
'fields': ('gender', ('first_name', 'last_name'), ('email', 'website')) 'fields': (
'gender', ('first_name', 'last_name'), ('email', 'website'))
}), }),
(_('Membership'), { (_('Membership'), {
'classes': ('collapse',), 'classes': ('collapse',),

View File

@@ -3,11 +3,12 @@ Created on 03.10.2011
@author: Christian @author: Christian
""" """
from . import models
from django.conf import settings from django.conf import settings
from django.contrib import auth from django.contrib import auth
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from . import models
from utils.html5 import forms from utils.html5 import forms
from utils.massmailer import MassMailer from utils.massmailer import MassMailer
@@ -26,25 +27,29 @@ class MembershipForm(forms.ModelForm):
) )
def clean_birthday(self): 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. \ raise forms.ValidationError(_('For your membership, we need this. \
Please fill out this field yet.')) Please fill out this field yet.'))
return self.cleaned_data['birthday'] return self.cleaned_data['birthday']
def clean_telephone(self): 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. \ raise forms.ValidationError(_('For your membership, we need this. \
Please fill out this field yet.')) Please fill out this field yet.'))
return self.cleaned_data['telephone'] return self.cleaned_data['telephone']
def clean_street_name(self): 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. \ raise forms.ValidationError(_('For your membership, we need this. \
Please fill out this field yet.')) Please fill out this field yet.'))
return self.cleaned_data['street_name'] return self.cleaned_data['street_name']
def clean_post_code(self): 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. \ raise forms.ValidationError(_('For your membership, we need this. \
Please fill out this field yet.')) Please fill out this field yet.'))
return self.cleaned_data['post_code'] 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. 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 \ raise forms.ValidationError(_(u'This email address is already in \
use. Please supply a different email address.')) use. Please supply a different email address.'))
return self.cleaned_data['email'] return self.cleaned_data['email']
@@ -139,6 +145,7 @@ class RegistrationForm(forms.ModelForm):
user.is_active = False user.is_active = False
if commit: if commit:
user.save() user.save()
activation = models.ActivationRequest.objects.create_pending_registration(user) activation = models.ActivationRequest.objects.create_pending_registration(
user)
self.send_email(activation) self.send_email(activation)
return user return user

View File

@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from membership.models import ActivationRequest from membership.models import ActivationRequest

View File

@@ -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. tell them you have fixed the problem.
""" """
from optparse import make_option
from django.conf import settings from django.conf import settings
from django.contrib import auth from django.contrib import auth
from django.contrib.sessions.models import Session from django.contrib.sessions.models import Session
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from optparse import make_option
class Command(BaseCommand): class Command(BaseCommand):
@@ -45,7 +46,8 @@ class Command(BaseCommand):
self.stderr.write('Session "%s" does not exist' % session_key) self.stderr.write('Session "%s" does not exist' % session_key)
continue continue
except settings.AUTH_USER_MODEL.DoesNotExist: 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 continue
if options['delete']: if options['delete']:
self.stdout.write('deleting %s' % user.username) self.stdout.write('deleting %s' % user.username)

View File

@@ -1,7 +1,10 @@
# -*- encoding: utf-8 -*- # -*- encoding: utf-8 -*-
from . import PAID_MEMBERSHIP_GROUP
from datetime import timedelta from datetime import timedelta
from os import path
import random
import hashlib
from django.utils import timezone from django.utils import timezone
from django.conf import settings from django.conf import settings
from django.contrib.auth import get_user_model 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 django.utils.translation import ugettext as _
from imagekit.models import ImageSpecField from imagekit.models import ImageSpecField
from imagekit.processors import SmartResize from imagekit.processors import SmartResize
from os import path
from . import PAID_MEMBERSHIP_GROUP
from utils import OverwriteStorage from utils import OverwriteStorage
import random
import hashlib
GENDER_CHOICES = ( GENDER_CHOICES = (
('m', _('Male')), ('m', _('Male')),
@@ -150,7 +153,8 @@ class MembershipManager(models.Manager):
if user: if user:
return super(MembershipManager, self).get(user=user) return super(MembershipManager, self).get(user=user)
elif username: elif username:
return super(MembershipManager, self).get(user__username=username) return super(MembershipManager, self).get(
user__username=username)
except Membership.DoesNotExist: except Membership.DoesNotExist:
if username: if username:
user = get_user_model().objects.get(username=username) user = get_user_model().objects.get(username=username)

View File

@@ -6,14 +6,13 @@
{% block teaser %}<h2>{% trans 'profile for' %} {{membership.user.username|title}}</h2>{% endblock %} {% block teaser %}<h2>{% trans 'profile for' %} {{membership.user.username|title}}</h2>{% endblock %}
{% block navigation %} {% block navigation %}
{% if kyu_dan_ranking %}
<ul id="navigation"> <ul id="navigation">
<li><a href="{% url 'player-ladder-score' membership.user.username %}">{% trans "Ladder Hanchans" %}</a></li> <li><a href="{% url 'player-ladder-score' membership.user.username %}">{% trans "Ladder Hanchans" %}</a></li>
<li><a href="{% url 'player-kyu-score' membership.user.username %}">{% trans "Kyu Hanchans" %}</a></li> <li><a href="{% url 'player-kyu-score' membership.user.username %}">{% trans "Kyu Hanchans" %}</a></li>
<li><a href="{% url 'player-dan-score' membership.user.username %}">{% trans "Dan Hanchans" %}</a></li> <li><a href="{% url 'player-dan-score' membership.user.username %}">{% trans "Dan Hanchans" %}</a></li>
<li><a href="{% url 'player-invalid-score' membership.user.username %}">{% trans "Invalid Hanchans" %}</a></li> <li><a href="{% url 'player-invalid-score' membership.user.username %}">{% trans "Invalid Hanchans" %}</a></li>
<li><a href="{% url 'maistar-player-games' membership.user.username %}">{% trans "Mai-Star Games" %}</a></li>
</ul> </ul>
{% endif %}
{% endblock %} {% endblock %}
{% block maincontent %} {% block maincontent %}

View File

@@ -1,28 +1,39 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load i18n %} {% load i18n fieldset_extras %}
{% load url from future %} {% load url from future %}
{% block title %}{% trans "Registration"%}{% endblock %} {% block title %}{% trans "Registration"%}{% endblock %}
{% block teaser%}
<h1>{% trans "Registration"%}</h1>
<div id="teaser_text">
</div>
{% endblock %}
{% block maincontent %} {% block maincontent %}
<div class="grid_5"> <form method="post" action="{% url 'membership-register' %}">
<h2>{% trans "Registration" %}</h2> {% csrf_token %}
<p>{% blocktrans %} <fieldset class="grid_5">
After you've provided your account data, you'll receive an email asking you to verify your email address. <legend>{% trans "Name"%}</legend>
You have to click on the link in this verification email to confirm your email address, otherwise your can't login. {% get_fieldset "first_name, last_name, username" from form as form1 %}
{% endblocktrans %}</p> {% with form1 as form %}{% include "form.html" %}{% endwith %}
</div> </fieldset>
<fieldset class="grid_7">
<legend>{% trans "Security"%}</legend>
{% get_fieldset "email, password1, password2, recaptcha" from form as form2 %}
{% with form2 as form %}{% include "form.html" %}{% endwith %}
</fieldset>
<form method="post" action="{% url 'membership-register' %}" class="grid_7"> <div class="grid_12">
{% csrf_token %} <p>{% blocktrans %}After you've provided your account data, you'll
<fieldset> receive an email asking you to verify your email address.
<legend>{% trans "Registration"%}</legend> You have to click on the link in this verification email to
{% include "form.html" %} confirm your email address, otherwise your can't login.
<p class="buttonbar"> {% endblocktrans %}</p>
<button type="reset"><img src="{{STATIC_URL}}icons/arrow_undo.png" alt="{% trans 'reset' %}" /> {% trans 'reset' %}</button> <p class="buttonbar">
<button type="submit"><img src="{{STATIC_URL}}icons/user_add.png" alt="{% trans 'register' %}" /> {% trans 'register' %}</button> <button type="reset"><img src="{{STATIC_URL}}icons/arrow_undo.png" alt="{% trans 'reset' %}" /> {% trans 'reset' %}</button>
</p> <button type="submit"><img src="{{STATIC_URL}}icons/user_add.png" alt="{% trans 'register' %}" /> {% trans 'register' %}</button>
</fieldset> </p>
</div>
</form> </form>

View File

@@ -28,20 +28,3 @@ urlpatterns = patterns(
views.EditMembership.as_view(), views.EditMembership.as_view(),
name="membership-edit") name="membership-edit")
) )
"""
urlpatterns += patterns('social_auth.views',
url(r'^login/(?P<backend>[^/]+)/$', 'auth',
name='socialauth_begin'),
url(r'^complete/(?P<backend>[^/]+)/$', 'complete',
name='socialauth_complete'),
url(r'^associate/(?P<backend>[^/]+)/$', 'auth',
name='socialauth_associate_begin'),
url(r'^associate/complete/(?P<backend>[^/]+)/$', 'complete',
name='socialauth_associate_complete'),
url(r'^disconnect/(?P<backend>[^/]+)/$', 'disconnect',
name='socialauth_disconnect'),
url(r'^disconnect/(?P<backend>[^/]+)/(?P<association_id>[^/]+)/$',
'disconnect',
name='socialauth_disconnect_individual'),
)
"""

View File

@@ -9,7 +9,6 @@ from django.contrib.auth import get_user_model
from mahjong_ranking.models import KyuDanRanking, LadderRanking, LadderSeason from mahjong_ranking.models import KyuDanRanking, LadderRanking, LadderSeason
from utils import mixins from utils import mixins
from . import forms, models from . import forms, models
@@ -49,7 +48,8 @@ class ActivateRegistration(generic.DetailView):
def login(self, user): def login(self, user):
backend = auth.get_backends()[0] 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) auth.login(self.request, user)
messages.success(self.request, _('Activation successful. \ messages.success(self.request, _('Activation successful. \
You can now login anytime with you username and password.')) 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): def get_object(self, queryset=None):
if self.kwargs.get('username'): 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] return models.Membership.objects.get_or_create(user=user)[0]
elif self.request.user.is_authenticated(): elif self.request.user.is_authenticated():
return models.Membership.objects.get(user=self.request.user) return models.Membership.objects.get(user=self.request.user)

View File

@@ -1,29 +0,0 @@
{% extends "base.html" %}
{% block title %}404 - Seite nicht gefunden{% endblock %}
{% block maincontent %}
<h1 class="grid_12">404 - Nōten!</h1>
<p class="grid_12">Unter der Adresse <em>{{request.path}}</em> wohnt zur Zeit kein Inhalt.<br />
Unsere Empfehlung: Gehe zurück zum <a href="/">Start</a>.</p>
<div class="grid_6">
<h2>Ursachen</h2>
<p>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.</p>
<p>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:</p>
<ul>
<li>Die Datei, auf die die URL verweist, ist verschoben, umbenannt oder gelöscht worden.</li>
<li>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.</li>
<li>Die gesuchte Domain ist neu bei einem Registrar vergeben worden und die Website selber noch ohne jeden Inhalt.</li>
<li>Der Webserver ist nicht (mehr) erreichbar, beispielsweise wegen Netzproblemen oder weil der Rechner abgeschaltet ist.</li>
<li>Der Host- bzw. Domainname der URL existiert nicht (mehr) oder kann nicht im DNS aufgelöst werden.</li>
</ul>
</div>
<div class="grid_6">
<h2>Lösungsmöglichkeiten</h2>
<p>Eine Möglichkeit, die allerdings eher die Symptome der Dead Links bekämpft, ist die <a href="http://de.wikipedia.org/wiki/Internet_Archive">Wayback Machine</a> des Internetarchivs. Durch chronologische Kopien von Webseiten kann Zugriff auf teilweise längst nicht mehr im Original vorhandene Webseiten gewährt werden.</p>
<p>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.</p>
</div>
{% endblock %}

View File

@@ -1,205 +0,0 @@
{% load i18n %}
<!doctype html>
<html>
<head>
<title>Kasu - {% block title %}{{ current_top_page.menu_name|default:"traditionelle asiatische Spielkultur"}}{% endblock %}</title>
<meta name="keywords" content="{% block keywords %}{% endblock %}"/>
<meta name="description" content="{% block description %}{% endblock %}"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="shortcut icon" href="{{STATIC_URL}}img/favicon.ico">
<link rel="stylesheet" media="all" href="{{STATIC_URL}}css/common.css" type="text/css">
<link rel="stylesheet" media="print" href="{{STATIC_URL}}css/print.css" type="text/css">
<link rel="stylesheet" media="screen and (min-width: 701px)" href="{{STATIC_URL}}css/desktop.css" type="text/css">
<link rel="stylesheet" media="screen and (max-width: 700px)" href="{{STATIC_URL}}css/mobile.css" type="text/css">
<!--[if lt IE 9]>
<link rel="stylesheet" media="screen" href="{{STATIC_URL}}css/desktop.css" type="text/css">
<script type="text/javascript">
document.createElement('header');
document.createElement('nav');
document.createElement('section');
document.createElement('article');
document.createElement('aside');
document.createElement('footer');
document.createElement('hgroup');
</script>
<![endif]-->
<link rel="alternate" type="application/rss+xml" title="{% trans 'Current News' %}"
href="{% url 'feed-latest-news' %}"/>
<link rel="alternate" type="application/rss+xml" title="{% trans 'Recent Comments' %}"
href="{% url 'feed-latest-comments' %}"/>
{% block opengraph %}
<meta property="og:type" content="website"/>
<meta property="og:title" content="Kasu - Verein Japanische Spielekultur"/>
<meta property="og:url" content="http://www.kasu.at{{ request.path_info }}"/>
<meta property="og:image" content="http://www.kasu.at/static/img/logo.png"/>
{% endblock %}
{% block extra_head %}{% endblock %}
</head>
<body {% block itemscope %}{% endblock %}>
<div id="header_bg"></div>
<header id="siteheader">
<h1 id="sitelogo"><a href="/index.html">Kasu - traditionelle asiatische Spielkultur</a></h1>
<nav id="mainnav">
<input type="checkbox" id="toggle"/>
<label for="toggle" class="toggle" onclick>{% trans "Menu" %}</label>
<ul class="main_menu">
{% for item in top_menu_items %}
<li><a href="{{item.get_absolute_url}}" title="{{ item.title }}"
class="{%if item.active %}active{% endif %}">{{item.menu_name}}</a></li>
{% endfor %}
</ul>
</nav>
</header>
<section id="jumbotron"
style="background-image: url('{% block jumbotron_background %}{{STATIC_URL}}img/teaser/{{current_top_page.slug}}.jpg{% endblock %}')">
{% block teaser %}
<h2>{{page.title}} {{title}}</h2>
{% endblock %}
<aside id="redbox">
{% block redbox %}
{% if current_event %}
<h2>{% trans "Current Event" %}</h2>
<h3>{{ current_event.name}}</h3>
<p><img src="{{ STATIC_URL }}icons/date.png"/> {% trans "since" %}
<time datetime="{{current_event.start|date:'c'}}">{{current_event.start|timesince}}</time>
</p>
<ul class="list">
<li class="event"><strong>{% trans "Start" %}:</strong> {{current_event.start|date:'DATETIME_FORMAT'}}</li>
<li class="location"><strong>{% trans "Location" %}:</strong> {{ current_event.location }}</li>
</ul>
<div style="text-align:right"><a class="button" href="{{current_event.get_absolute_url}}">{% trans "More Details" %}
<img src="{{ STATIC_URL }}icons/date_go.png" alt="&raquo;" width="16" height="16"/></a></div>
{% else %}
<h2>{% trans "Next Event" %}</h2>
<h3>{{ next_event.name}}</h3>
<p><img src="{{ STATIC_URL }}icons/date.png" alt="" width="16" height="16"/> {% trans "in" %}
<time datetime="{{next_event.start|date:'c'}}">{{next_event.start|timeuntil}}</time>
</p>
<ul class="list">
<li class="event"><strong>{% trans "Start" %}:</strong> {{next_event.start|date:'DATETIME_FORMAT' }}</li>
<li class="location"><strong>{% trans "Location" %}:</strong> {{ next_event.location }}</li>
</ul>
<div style="text-align:right"><a class="button" href="{{next_event.get_absolute_url}}">{% trans "More Details" %}
<img src="{{ STATIC_URL }}icons/date_go.png" alt="&raquo;" width="16" height="16"/></a></div>
{% endif %}
<h3 class="clearfix">{% trans "Upcoming events" %} <a href="{% url 'events-ical' %}"><img
src="{{STATIC_URL}}img/ical_feed.gif" alt="iCal Feed" title="iCal Feed" width="16" height="16"/></a>
</h3>
<ul class="list">
{% for event in upcoming_events %}
<li class="event">{{event.start|date:'d. M:'}} <a href="{{ event.get_absolute_url}}">{{event.name}}</a></li>
{% endfor %}
</ul>
{% endblock %}
</aside>
</section>
{% block navigation %}
{% if current_top_page.subpages.count %}
<ul id="navigation">
<li><a href="{{current_top_page.get_absolute_url}}"
class="{% ifequal current_page current_top_page %}{% endifequal %}">{{current_top_page.menu_name}}</a></li>
{% for subpage in current_top_page.subpages.all %}
<li><a href="{{subpage.get_absolute_url}}" class="{% ifequal subpage current_page %}active{% endifequal %}">{{subpage.menu_name}}</a>
</li>
{% endfor %}
{% block additional_nav_elements %}{% endblock %}
</ul>
{% endif %}
{% endblock %}
{% block messages %}
{% if messages %}
<ul id="messages">
{% for message in messages %}
<li class="{{ message.tags }}">{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endblock %}
<div id="maincontent">
{% block maincontent %}
<div id="content">{% block content %}{% endblock %}</div>
<aside id="sidebar">{% block sidebar %}{% endblock %}</aside>
{% endblock %}
{% block paginator %}
{% if page_obj.has_other_pages %}{% include 'paginator.html' %}{% endif %}
{% endblock %}
{% block comments %}{% endblock %}
<br class="clear" />
<p id="bottom_buttonbar" class="buttonbar">
{% block buttonbar %}
{% if current_page and perms.content.change_page %}<a href="{% url 'edit-page' current_page.path %}" class="button"><img
src="{{ STATIC_URL }}icons/page_edit.png" alt=""/> {% trans "Edit Page" %}</a>{% endif %}
{% if current_page and perms.content.add_page %}<a href="{% url 'add-page' current_page.path %}" class="button"><img
src="{{ STATIC_URL }}icons/page_add.png" alt=""/> {% trans "Add Subpage" %}</a>{% endif %}
{% block additional_buttonbar %}{% endblock %}
{% endblock %}
</p>
</div>
<div id="footer_bg">&nbsp;</div>
<footer id="footer">
<p><strong>Herausgeber:</strong> Verein Kasu - traditionelle asiatische Spielkultur (<a
href="/verein/impressum.html">{% trans "imprint" %}</a> &ndash; <a
href='ma&#105;&#108;to&#58;ve&#37;72e&#37;6&#57;n&#64;%6&#66;%61su&#46;a%7&#52;'>{% trans "contact" %}</a>)
</p>
<form action="/i18n/setlang/" method="post" style="text-align:right;">
{% csrf_token %}
<label for="language">{% trans "Language" %}:</label>
<select name="language" id="language">
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{language.code}}" {% ifequal language.code LANGUAGE_CODE %}
selected="selected" {% endifequal %}>{{ language.name_local }} ({{ language.code }})
</option>
{% endfor %}
</select>
<button type="submit">{% trans "Go" %}</button>
</form>
</footer>
<nav id="usernav">
{% if user.is_authenticated %}
{% trans "Logged in as" %}:
<a rel="nofollow" href="{% url 'membership-details' user.username %}">{{user.username}}</a> -
{% if user.is_staff %}<a href="/admin">{% trans "Admin" %}</a>{% endif %}
<a rel="nofollow" href="{% url 'logout' %}?next={{ request.path_info }}">{% trans "Logout" %}</a>
{% else %}
{% trans "no user logged in" %} -
<a rel="nofollow" href="{% url 'membership-register' %}">{% trans "register" %}</a>
<a rel="nofollow" href="{% url 'login' %}?next={{ request.path_info }}">{% trans "login" %}</a>
<a rel="nofollow" href="{% url 'social:begin' 'facebook' %}"><img src="{{STATIC_URL}}img/facebook.png"
alt="Facebook Login" title="Login with Facebook"
width="26" height="26"/></a>
<a rel="nofollow" href="{% url 'social:begin' 'twitter' %}"><img src="{{STATIC_URL}}img/twitter.png"
alt="Twitter Login" title="Login with Twitter"
width="26" height="26"/></a>
<a rel="nofollow" href="{% url 'social:begin' 'google-oauth2' %}"><img src="{{STATIC_URL}}img/google.png"
alt="Google Login" title="Login with Google"
width="26" height="26"/></a>
{% endif %}
</nav>
<script type="text/javascript">
{% block javascript %}{% endblock %}
var pkBaseURL = (("https:" == document.location.protocol) ? "https://admin.animanga.at/tools/piwik/" : "http://admin.animanga.at/tools/piwik/");
document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
try {
var piwikTracker = Piwik.getTracker(pkBaseURL + "piwik.php", 5);
piwikTracker.trackPageView();
piwikTracker.enableLinkTracking();
} catch (err) {
}
</script>
<noscript><p><img src="http://admin.animanga.at/tools/piwik/piwik.php?idsite=5" style="border:0" alt=""/></p></noscript>
</body>
</html>

View File

@@ -1,51 +0,0 @@
{% load comments i18n %}
<form action="{% comment_form_target %}" method="post" id='comment_form' class="grid_12">
{% csrf_token %}
<fieldset class="comment">
<legend>{% trans "New Comment" %}</legend>
{% if user.is_authenticated %}
<p style="display:none">
{{form.honeypot}} {{form.honeypot.label}}
{% for field in form.hidden_fields %}{{ field }}{% endfor %}
<input type="hidden" name="next" value="{{ next|default:request.path_info }}"/>
</p>
<div class="comment">
<div class="comment_picture"><img class="avatar"
src="{% if user.get_profile.thumbnail %}{{user.get_profile.thumbnail.url}}{% else %}{{STATIC_URL}}img/unknown_thumbnail.png{% endif %}"
alt=""/></div>
<header class="comment_header">
<h3><a href="{{ user.get_profile.get_absolute_url }}" class="user">{{user}}</a></h3>
<p class="submit_date">{% trans 'now' %}</p>
</header>
<div class="comment_text">{{form.comment}}</div>
</div>
<p class="buttonbar">
<button type="submit" name="preview"><img src="{{ STATIC_URL }}icons/comment_edit.png"
alt="{% trans 'Preview' %}"/> {% trans "Preview" %}
</button>
<button type="submit" name="submit"><img src="{{ STATIC_URL }}icons/comment_add.png"
alt="{% trans 'Post' %}"/> {% trans "Post" %}
</button>
</p>
{% else %}
<div class="comment">
<div class="comment_picture"><img class="avatar"
src="{{STATIC_URL}}img/unknown_thumbnail.png"
alt=""/></div>
<header class="comment_header">
<h3>{% trans "not logged in" %}</h3>
</header>
<div class="comment_text">
<textarea disabled="disabled" cols="40" rows="10">
{% blocktrans %}Register now, or Login to leave a comment here.{% endblocktrans %}
</textarea>
</div>
</div>
<p class="buttonbar">
<a href="{% url 'membership-register' %}" class="button"><img src="{{STATIC_URL}}icons/user_add.png" alt=""/> {% trans 'register' %}</a>
<a href="{% url 'login' %}?next={{ request.path_info|urlencode }}" class="button"><img src="{{STATIC_URL}}icons/lock_break.png" alt=""/> {% trans 'login' %}</a>
</p>
{% endif %}
</fieldset>
</form>

View File

@@ -1,18 +0,0 @@
{% load i18n django_markdown %}
<h2 class="grid_12" id="comments">{% trans 'Comments' %}</h2>
{% for comment in comment_list %}
<article id="c{{ comment.id }}" class="comment">
<div class="comment_picture">
<img class="avatar" src="{% if comment.user.get_profile.thumbnail %}
{{comment.user.get_profile.thumbnail.url}}
{% else %}
{{STATIC_URL}}img/unknown_thumbnail.png
{% endif %}" alt=""/>
</div>
<header class="comment_header">
<h3><a href="{{ comment.user.get_profile.get_absolute_url }}" class="user">{{comment.user}}</a></h3>
<time datetime="{{comment.submit_date|date:'Y-m-d'}}" class="submit_date">{{comment.submit_date|timesince}}</time>
</header>
<div class="comment_text">{{comment.comment|markdown_safe}}</div>
</article>
{% endfor %}

View File

@@ -1,8 +0,0 @@
{% extends "base.html" %}
{% load i18n %}
{% block title %}{% trans "Thank you for your comment" %}{% endblock %}
{% block content %}
<h1>{% trans "Thank you for your comment" %}!</h1>
{% endblock %}

View File

@@ -1,29 +0,0 @@
{% extends "base.html" %}
{% load i18n django_markdown %}
{% block title %}{% trans "Preview your comment" %}{% endblock %}
{% block maincontent %}
{% if form.errors %}
<h2 class="grid_12">{% blocktrans count form.errors|length as counter %}Please correct the error below{% plural %}Please correct the errors below{% endblocktrans %}</h2>
{% else %}
<h2 class="grid_12">{% trans "Preview your comment" %}</h2>
<article id="c{{ comment.id }}" class="comment">
<div class="comment_picture">
<img class="avatar" src="{% if user.get_profile.thumbnail %}
{{user.get_profile.thumbnail.url}}
{% else %}
{{STATIC_URL}}img/unknown_thumbnail.png
{% endif %}" alt=""/>
</div>
<header class="comment_header">
<a href="{{ user.get_profile.get_absolute_url }}" class="user">{{comment.user}}</a>
<div class="submit_date"><time time="{% now 'c' %}">{% now 'DATETIME_FORMAT' %}</time></div>
</header>
<div class="comment_text">{{comment|markdown_safe}}</div>
</article>
{% endif %}
{% include "comments/form.html" %}
{% endblock %}

View File

@@ -1,9 +0,0 @@
{% for field in form.visible_fields %}
<div>
<label for="id_{{ field.html_name}}" class="field_name {{ field.css_classes }}">{{ field.label }}</label>
{{ field }}
{%if field.help_text %}<p class="help_text">{{field.help_text}}</p>{% endif %}
{%if field.errors %}{{ field.errors }}{% endif %}
</div>
{% endfor %}
{% for hidden in form.hidden_fields %}{{ hidden }}{% endfor %}

View File

@@ -1 +0,0 @@
google-site-verification: google25dabc1a49a9ef03.html

View File

@@ -1,115 +0,0 @@
{% extends "base.html" %}
{% load i18n comments%}
{% block jumbotron_background %}{{ random_photo.url }}{% endblock %}
{% block teaser %}
<h2>{{title}}</h2>
<div id="teaser_text">{{content}}</div>
{% endblock %}
{% block redbox %}
{% if current_event %}
<h2>{% trans "Current Event" %}</h2>
<h3>{{ current_event.name}}</h3>
<p><img src="{{ STATIC_URL }}icons/date.png"/> {% trans "since" %}
<time datetime="{{current_event.start|date:'Y-m-d H:i'}}">{{current_event.start|timesince}}</time>
</p>
<ul class="list">
<li class="event"><strong>{% trans "Start" %}:</strong> {{current_event.start|date:'DATETIME_FORMAT'}}</li>
<li class="location"><strong>{% trans "Location" %}:</strong> {{ current_event.location }}</li>
</ul>
<div style="text-align:right"><a class="button" href="{{current_event.get_absolute_url}}">{% trans "More Details" %}
<img src="{{ STATIC_URL }}icons/date_go.png" alt="&raquo;" width="16" height="16"/></a></div>
{% else %}
<h2>{% trans "Next Event" %}</h2>
<h3>{{ next_event.name}}</h3>
<p><img src="{{ STATIC_URL }}icons/date.png" alt="" width="16" height="16"/> {% trans "in" %}
<time datetime="{{next_event.start|date:'Y-m-d H:i'}}">{{next_event.start|timeuntil}}</time>
</p>
<ul class="list">
<li class="event"><strong>{% trans "Start" %}:</strong> {{next_event.start|date:'DATETIME_FORMAT' }}</li>
<li class="location"><strong>{% trans "Location" %}:</strong> {{ next_event.location }}</li>
</ul>
<div style="text-align:right"><a class="button" href="{{next_event.get_absolute_url}}">{% trans "More Details" %}
<img src="{{ STATIC_URL }}icons/date_go.png" alt="&raquo;" width="16" height="16"/></a></div>
{% endif %}
<h3 class="clearfix">{% trans "Upcoming events" %} <a href="{% url 'events-ical' %}"><img
src="{{STATIC_URL}}img/ical_feed.gif" alt="iCal Feed" title="iCal Feed" width="16" height="16"/></a></h3>
<ul class="list">
{% for event in upcoming_events %}
<li class="event">{{event.start|date:'d. M:'}} <a href="{{ event.get_absolute_url}}">{{event.name}}</a></li>
{% endfor %}
</ul>
{% endblock %}
{% block maincontent %}
<div class="grid_8">
{% for article in recent_article_list %}{% get_comment_count for article as comment_count %}
<article class="article">
<header>
<h2><a href="{{article.get_absolute_url}}">{{article.headline}}</a></h2>
<ul class="info">
<li><img src="{{STATIC_URL}}icons/date.png" width="16" height="16" alt="{% trans 'Created on' %}"
title="{% trans 'Created on' %}"/>
<time datetime="{{article.date_created|date:'Y-m-d H:i'}}">{{ article.date_created|date:'DATE_FORMAT' }}</time>
</li>
<li><img src="{{STATIC_URL}}icons/user_red.png" width="16" height="16" alt="{% trans 'Author' %}"
title="{% trans 'Author' %}"/> {{ article.author }}
</li>
<li><img src="{{STATIC_URL}}icons/comments.png" alt="{% trans 'comments' %}:"
title="{% trans 'comments' %}"/> <a href="{{article.get_absolute_url}}#comments">{{comment_count}}
{% trans "comments" %}</a></li>
</ul>
</header>
<a href="{{article.get_absolute_url}}"><img src="{{article.posting_image.url}}" alt="{{article.category}}:"
class="posting_image"/></a>
{{article.content|truncatewords_html:50}}
<footer class="more_link"><a href="{{article.get_absolute_url}}" class="button">{% trans "Read More"%} <img
src="{{STATIC_URL}}icons/page_go.png" alt="&raquo;" width="16" height="16"/></a></footer>
</article>
{% endfor %}
</div>
<aside class="grid_4">
<section>
<h2>{% trans "Recent Comments" %} <a href="{% url 'feed-latest-comments' %}"><img
src="{{ STATIC_URL }}img/rss_feed.gif" alt="RSS Feed" title="RSS Feed" width="16" height="16"/></a></h2>
<ul class="comment_list">
{% for comment in recent_comment_list %}
{% url 'membership-details' comment.user.username as user_link%}
<li>
{% blocktrans with comment.user as author and comment.submit_date|timesince as since and comment.submit_date|date:'c' as submit_date and comment.content_object as object and comment.get_absolute_url as comment_link%}
From <a href="{{user_link}}">{{author}}</a> in
<a href="{{comment_link}}">&ldquo;{{object}}&rdquo;</a>
since
<time datetime="{{submit_date}}">{{since}}</time>
{% endblocktrans %}
</li>
{% endfor %}
</ul>
</section>
<section>
<h2>{% trans 'Kasu in the social network' %}</h2>
<p style="text-align: center">
<a href="https://www.facebook.com/Kasu.at"><img src="{{STATIC_URL}}img/facebook.png" alt="Facebook"
title="{% trans 'Visit us on' %} Facebook"/></a>
<a href="https://twitter.com/KasuAustria"><img src="{{STATIC_URL}}img/twitter.png" alt="Twitter"
title="{% trans 'Visit us on' %} Twitter"/></a>
<a href="https://plus.google.com/u/0/114092233962732014973/"><img src="{{STATIC_URL}}img/google_plus.png"
alt="Google+"
title="{% trans 'Visit us on' %} Google+"/></a>
</p>
</section>
</aside>
{% endblock %}
{% if perms.content.add_article %}{% block addidional_buttonbar %}
<a href="{% url 'add-article' %}" class="button"><img src="{{ STATIC_URL }}icons/note_add.png" alt="" width="16"
height="16"/>{% trans "Add Article" %}</a>
{% endblock %}{% endif %}

View File

@@ -1,20 +0,0 @@
{% load i18n %}
<div class="paginator grid_12">
{% if page_obj.has_previous %}
<a class="prev" href="?page={{ page_obj.previous_page_number }}"><img src="{{STATIC_URL}}icons/resultset_previous.png" alt="«" /> {% trans "Prev" %}</a>
{% else %}
<span class="prev disabled"><img src="{{STATIC_URL}}icons/resultset_previous.png" alt="«" /> {% trans "Prev" %}</span>
{% endif %}
{% for page in paginator.page_range %}
{% ifequal page_obj.number page %}
<span class="current">{{page}}</span>
{% else %}
<a class="page" href="?page={{page}}">{{page}}</a>
{% endifequal %}
{% endfor %}
{% if page_obj.has_next %}
<a class="next" href="?page={{ page_obj.next_page_number }}">{% trans "Next" %} <img src="{{STATIC_URL}}icons/resultset_next.png" alt="»" /></a>
{% else %}
<span class="next disabled">{% trans "Next" %} <img src="{{STATIC_URL}}icons/resultset_next.png" alt="»" /></span>
{% endif %}
</div>

View File

@@ -1,64 +0,0 @@
{% extends "base.html" %}
{% load url from future %}
{% load i18n %}
{% block title %}{% trans 'login' %}{% endblock %}
{% block teaser %}<h2>{% trans 'login' %}</h2>{% endblock %}
{% block maincontent %}
<form method="post" action="{% url 'django.contrib.auth.views.login' %}">
<h2 class="grid_12">Auf der Seite Anmelden</h2>
<div class="grid_7">
<h2>{% trans "Have you already registered?" %}</h2>
{% blocktrans %}
<p>As a registered member you can:</p>
<ul>
<li>leave comments on this page.</li>
<li>subscribe to our Newsletter</li>
<li>apply to a membership to our club</li>
<li>club-members have access to our ranking-system</li>
</ul>
{% endblocktrans %}
{% blocktrans %}
<p>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.</p>
{% endblocktrans %}
<p class="more_link">
<a href="{% url 'membership-register' %}" class="button">
<img src="{{STATIC_URL}}icons/user_add.png" alt="{%trans 'register' %}"/>
{%trans "register"%}</a></p>
</div>
{% csrf_token %}
<fieldset class="grid_5">
<legend>{% trans 'login' %}</legend>
{% csrf_token %}
{% include 'form.html' %}
{% if form.errors %}
<p>{% blocktrans %}Your username and password didn't match. Please try again.{% endblocktrans %}</p>
{% endif %}
<input type="hidden" name="next" value="{{next}}" />
<p><a href="{% url 'password_reset' %}">{% trans 'Forgot your Password?'%}</a></p>
<div class="buttonbar">
<button type="submit">
<img src="{{STATIC_URL}}icons/lock_break.png" alt="{% trans 'Login' %}" /> {% trans 'Login' %}
</button></div>
</fieldset>
<div class="grid_5" style="text-align: center;">
<h2>{% trans "or login with an existing Account" %}</h2>
<a rel="nofollow" href="{% url 'social:begin' 'facebook' %}"><img src="{{STATIC_URL}}/img/facebook.png" alt="{% trans 'Login with Facebook' %}" title="{% trans 'Login with Facebook' %}"/></a>
<a rel="nofollow" href="{% url 'social:begin' 'twitter' %}"><img src="{{STATIC_URL}}/img/twitter.png" alt="{% trans 'Login with twitter' %}" title="{% trans 'Login with Twitter' %}"/></a>
<a rel="nofollow" href="{% url 'social:begin' 'google-oauth2' %}"><img src="{{STATIC_URL}}/img/google.png" width="78" height="78" alt="{% trans 'Login with Google' %}" title="{% trans 'Login with Google' %}"/></a>
</div>
</form>
{% endblock %}

View File

@@ -1,9 +0,0 @@
{% extends "base.html" %}
{% load i18n %}
{% block title %}{% trans 'Password change successful' %}{% endblock %}
{% block content %}
<h2>{% trans 'Password change successful' %}</h2>
<p class="info">{% trans 'Your password was changed.' %}</p>
{% endblock %}

View File

@@ -1,28 +0,0 @@
{% extends "base.html" %}
{% load i18n %}
{% block title %}{% trans 'Password change' %}{% endblock %}
{% block callout %}
<div id="callout">
<h1>{% trans 'Password change' %}</h1>
<p>{% 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." %}</p>
</div>
{% endblock %}
{% block content %}
<fieldset>
<legend>Passwort ändern:</legend>
<form method="post" action="" class="cmxform">
{%csrf_token%}
{% if form.errors %}<p class="error"> Es sind Fehler beim ändern des Passwortes aufgetreten</p>{% endif %}
{% include 'form.html' %}
<div class="buttonbar">
<button type="submit">
<img src="{{STATIC_URL}}icons/lock_break.png" alt="{% trans 'Login' %}" /> {% trans "Change Password" %}
</button>
</div>
</form>
</fieldset>
</div>
{% endblock %}

View File

@@ -1,10 +0,0 @@
{% extends "base.html" %}
{% load i18n %}
{% block title %}{% trans 'Password reset complete' %}{% endblock %}
{% block content %}
<h2>{% trans 'Password reset complete' %}</h2>
<p>{% trans "Your password has been set. You may go ahead and log in now." %}</p>
<p class="more"><a href="{{ login_url }}">{% trans 'Log in' %}</a></p>
{% endblock %}

View File

@@ -1,32 +0,0 @@
{% extends "base.html" %}
{% load i18n %}
{% block title %}{% trans 'Password reset' %}{% endblock %}
{% block maincontent %}
{% if validlink %}
<h2 class="grid_12">{% trans 'Enter new password' %}</h2>
<p class="grid_6">{% trans "Please enter your new password twice so we can verify you typed it in correctly." %}</p>
<form action="" method="post" class="grid_5">
{% csrf_token %}
<fieldset style="margin: -12px 0 0 0">
<legend>{% trans 'Change my password' %}</legend>
<ul>
{%for element in form %}
<p class="required">{{element.label_tag}} {{element}}
{%if element.help_text %} <img src="{{STATIC_URL}}icons/information.png" title="{{element.help_text}}"> {% endif %}
{%if element.errors %}{{element.errors }} {% endif %}
</li>
{% endfor %}
</ul>
<p class="buttonbar"><button type="submit"><img src="{{STATIC_URL}}icons/key.png" /> {% trans 'Change my password' %}</button></p>
</fieldset>
</form>
{% else %}
<h2>{% trans 'Password reset unsuccessful' %}</h2>
<p class="error">{% trans "The password reset link was invalid, possibly because it has already been used. Please request a new password reset." %}</p>
{% endif %}
{% endblock %}

View File

@@ -1,30 +0,0 @@
{% extends "base.html" %}
{% load i18n %}
{% block title %}{% trans 'Password reset successful' %}{% endblock %}
{% block maincontent %}
<div class="grid_12">
<h2>{% trans 'Password reset successful' %}</h2>
<p>Wir haben dir eine E-Mail mit Anweisungen zum Zurücksetzen deines Passwort an die angegebene E-Mail-Adresse geschickt.<br />
Du solltest diese in Kürze erhalten.</p>
</div>
<h3 class="grid_12">E-Mail nicht angekommen?</h3>
<div class="grid_4">
<h4>Etwas Warten...</h4>
<p>Einige Anti-Spam Techniken <strong>verzögern</strong> den <strong>Empfang</strong> von E-Mails.
Bei solchen Postfächern kann der Empfang einzelner Mails <strong>bis zu 30 Minuten</strong> dauern.</p>
</div>
<div class="grid_4">
<h4>Junk Mails prüfen</h4>
<p>Bitte überprüfe den <em>"Junk"</em> bzw. <em>"SPAM"</em> Ordner deines Postfaches.
Automatisch generierte E-Mails werden leider sehr oft <strong>falsch</strong> von <strong>SPAM-Filtern</strong> geschluckt</p>
</div>
<div class="grid_4">
<h4>Vorbei schauen</h4>
<p>Bitte Überprüfe die Richigkeit deiner angegebenen <strong>E-Mail Adresse</strong>. Wenn deine angegebne <strong>E-Mail</strong> Adresse <strong>nicht</strong> mehr <strong>aktuell</strong> ist, trete mit uns bitte in <strong>persönlichen Kontakt</strong></p>
</div>
{% endblock %}

View File

@@ -1,34 +0,0 @@
{% extends "base.html" %}
{% load i18n %}
{% block title %}{% trans "Password reset" %}{% endblock %}
{% block maincontent %}
<h2 class="grid_12">{% trans "Password reset" %}</h2>
<div class="grid_5">
<p>Du hast dein Passwort vergessen?</p>
<p>Macht nichts!<br/>
Solange die E-Mail Adresse von dir noch gültig ist, kannst du dein Passwort jederzeit wieder ändern.</p>
</div>
<form action="" method="post" class="grid_5">
{% csrf_token %}
<fieldset style="margin:-12px 0 0 0;">
<legend>E-Mail zusenden</legend>
{% for element in form %}
<p>
<label class="required" for="id_{{element.html_name}}">{%if element.help_text %}<img src="{{STATIC_URL}}icons/information.png" title="{{element.help_text}}" /> {% endif %}{{element.label}}</label>
{{element}}
{%if element.errors %} {{element.errors }} {% endif %}
</p>
{% endfor %}
<br />
<p class="buttonbar"><button type="submit"><img src="{{STATIC_URL}}icons/email_go.png" alt="submit"/> Zusenden</button></p>
</fieldset>
</form>
<p class="grid_12">Einfach deine E-Mail-Adresse eingeben und wir senden dir die Anweisungen zum Zurücksetzen deines Passworts.</p>
{% endblock %}

View File

@@ -1,4 +0,0 @@
User-agent: *
Disallow: /cgi-bin/
Disallow: /admin/
Disallow: /users/

View File

@@ -3,11 +3,13 @@ Created on 28.09.2011
@author: christian @author: christian
""" """
from django.core.files.storage import FileSystemStorage
from django.utils.translation import ugettext as _
from .countries import COUNTRIES from .countries import COUNTRIES
from .html_cleaner import HtmlCleaner from .html_cleaner import HtmlCleaner
from .massmailer import MassMailer 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_REJECTED, STATUS_WAITING, STATUS_PUBLISHED = -1, 0, 1
STATUS_CHOICES = ( STATUS_CHOICES = (
@@ -22,6 +24,7 @@ class OverwriteStorage(FileSystemStorage):
""" """
Returns same name for existing file and deletes existing file on save. Returns same name for existing file and deletes existing file on save.
""" """
def _save(self, name, content): def _save(self, name, content):
if self.exists(name): if self.exists(name):
self.delete(name) self.delete(name)

View File

@@ -3,9 +3,10 @@ Created on 24.11.2011
@author: christian @author: christian
""" """
from django import forms
import datetime import datetime
from django import forms
class DateInput(forms.widgets.DateInput): class DateInput(forms.widgets.DateInput):
input_type = 'date' input_type = 'date'
@@ -13,9 +14,9 @@ class DateInput(forms.widgets.DateInput):
def __init__(self, attrs=None, **kwargs): def __init__(self, attrs=None, **kwargs):
forms.widgets.DateInput.__init__(self, forms.widgets.DateInput.__init__(self,
attrs=attrs, attrs=attrs,
format='%Y-%m-%d', format='%Y-%m-%d',
**kwargs) **kwargs)
class NumberInput(forms.widgets.Input): class NumberInput(forms.widgets.Input):
@@ -23,8 +24,7 @@ class NumberInput(forms.widgets.Input):
class TimeInput(forms.widgets.Select): class TimeInput(forms.widgets.Select):
def __init__(self, attrs=None, ):
def __init__(self, attrs=None,):
timeset = datetime.datetime(2000, 1, 1, 0, 0) timeset = datetime.datetime(2000, 1, 1, 0, 0)
choices = [('', '-------')] choices = [('', '-------')]
while timeset < datetime.datetime(2000, 1, 2, 0, 0): 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=()): def render(self, name, value, attrs=None, choices=()):
return forms.widgets.Select.render(self, name, value, attrs=attrs, return forms.widgets.Select.render(self, name, value, attrs=attrs,
choices=choices) choices=choices)
class SplitDateTimeWidget(forms.widgets.MultiWidget): class SplitDateTimeWidget(forms.widgets.MultiWidget):

View File

@@ -1,15 +1,18 @@
import re import re
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.core.serializers.json import DjangoJSONEncoder from django.core.serializers.json import DjangoJSONEncoder
from django.http import HttpResponse from django.http import HttpResponse
from django.utils.encoding import smart_unicode, force_unicode from django.utils.encoding import smart_unicode, force_unicode
try: try:
import json import json
except ImportError: except ImportError:
from django.utils import simplejson as json from django.utils import simplejson as json
class LookupBase(object):
class LookupBase(object):
@classmethod @classmethod
def name(cls): def name(cls):
app_name = cls.__module__.split('.')[-2].lower() app_name = cls.__module__.split('.')[-2].lower()
@@ -69,7 +72,6 @@ class LookupInvalid(Exception):
class LookupRegistry(object): class LookupRegistry(object):
def __init__(self): def __init__(self):
self._registry = {} self._registry = {}
@@ -82,8 +84,8 @@ class LookupRegistry(object):
self.validate(lookup) self.validate(lookup)
name = force_unicode(lookup.name()) name = force_unicode(lookup.name())
if name in self._registry: if name in self._registry:
raise LookupAlreadyRegistered(u'The name %s is already registered'\ raise LookupAlreadyRegistered(u'The name %s is already registered' \
% name) % name)
self._registry[name] = lookup self._registry[name] = lookup
def unregister(self, lookup): def unregister(self, lookup):

View File

@@ -48,7 +48,7 @@ class AutoCompleteSelectField(Html5Mixin, django.forms.Field):
self.allow_new = kwargs.pop('allow_new', False) self.allow_new = kwargs.pop('allow_new', False)
if not kwargs['widget']: if not kwargs['widget']:
kwargs['widget'] = self.widget(lookup_class, kwargs['widget'] = self.widget(lookup_class,
allow_new=self.allow_new) allow_new=self.allow_new)
super(AutoCompleteSelectField, self).__init__(*args, **kwargs) super(AutoCompleteSelectField, self).__init__(*args, **kwargs)
def to_python(self, value): def to_python(self, value):
@@ -172,9 +172,9 @@ class PhoneField(Html5Mixin, django.forms.CharField):
widget = widgets.PhoneInput widget = widgets.PhoneInput
def __init__(self, regex=None, max_length=None, min_length=None, 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, super(PhoneField, self).__init__(max_length, min_length,
*args, **kwargs) *args, **kwargs)
self._set_regex(u'^[0-9+-/ ]+$') self._set_regex(u'^[0-9+-/ ]+$')
def _get_regex(self): def _get_regex(self):
@@ -184,7 +184,7 @@ class PhoneField(Html5Mixin, django.forms.CharField):
regex = re.compile(regex, re.UNICODE) regex = re.compile(regex, re.UNICODE)
self._regex = regex self._regex = regex
if hasattr(self, '_regex_validator') \ 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.validators.remove(self._regex_validator)
self._regex_validator = validators.RegexValidator(regex=regex) self._regex_validator = validators.RegexValidator(regex=regex)
self.validators.append(self._regex_validator) self.validators.append(self._regex_validator)
@@ -193,68 +193,68 @@ class PhoneField(Html5Mixin, django.forms.CharField):
class ReCaptchaField(django.forms.fields.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): def _check_recaptcha(self, challenge_value, response_value, remote_ip):
self.widget = widgets.ReCaptchaInput """
self.required = True Submits a reCAPTCHA request for verification.
super(ReCaptchaField, self).__init__(*args, **kwargs) Returns RecaptchaResponse for the request
def _check_recaptcha(self, challenge_value, response_value, remote_ip): @param challenge_value: value of recaptcha_challenge_field
""" @param response_value: value of recaptcha_response_field
Submits a reCAPTCHA request for verification. @param remoteip -- the user's ip address
Returns RecaptchaResponse for the request
@param challenge_value: value of recaptcha_challenge_field """
@param response_value: value of recaptcha_response_field import urllib
@param remoteip -- the user's ip address import urllib2
""" private_key = settings.RECAPTCHA_PRIVATE_KEY
import urllib challenge_value = challenge_value.encode('utf-8')
import urllib2 response_value = response_value.encode('utf-8')
private_key = settings.RECAPTCHA_PRIVATE_KEY params = urllib.urlencode({
challenge_value = challenge_value.encode('utf-8') 'privatekey': private_key,
response_value = response_value.encode('utf-8') 'remoteip': remote_ip,
params = urllib.urlencode({ 'challenge': challenge_value,
'privatekey': private_key, 'response': response_value,
'remoteip': remote_ip, })
'challenge': challenge_value,
'response': response_value,
})
request = urllib2.Request( request = urllib2.Request(
url="http://www.google.com/recaptcha/api/verify", url="http://www.google.com/recaptcha/api/verify",
data=params, data=params,
headers={ headers={
"Content-type": "application/x-www-form-urlencoded", "Content-type": "application/x-www-form-urlencoded",
"User-agent": "reCAPTCHA Python" "User-agent": "reCAPTCHA Python"
} }
) )
httpresp = urllib2.urlopen(request) httpresp = urllib2.urlopen(request)
return_values = httpresp.read().splitlines() return_values = httpresp.read().splitlines()
httpresp.close() httpresp.close()
return_code = return_values[0] return_code = return_values[0]
if (return_code == "true"): if (return_code == "true"):
return True return True
else: else:
return False return False
def clean(self, values): def clean(self, values):
challenge_value = values[0] challenge_value = values[0]
response_value = values[1] response_value = values[1]
super(ReCaptchaField, self).clean(response_value) super(ReCaptchaField, self).clean(response_value)
if not challenge_value: if not challenge_value:
raise util.ValidationError( raise util.ValidationError(
_(u'The CAPTCHA challenge is missing.')) _(u'The CAPTCHA challenge is missing.'))
elif not response_value: elif not response_value:
raise util.ValidationError( raise util.ValidationError(
_(u'The CAPTCHA solution is missing.')) _(u'The CAPTCHA solution is missing.'))
elif self._check_recaptcha(challenge_value, response_value): elif self._check_recaptcha(challenge_value, response_value):
return challenge_value return challenge_value
else: else:
raise util.ValidationError( raise util.ValidationError(
_(u'The CAPTCHA solution was incorrect.')) _(u'The CAPTCHA solution was incorrect.'))
class RegexField(Html5Mixin, django.forms.RegexField): class RegexField(Html5Mixin, django.forms.RegexField):

View File

@@ -4,15 +4,13 @@ Created on 08.05.2011
@author: christian @author: christian
""" """
from django.db import models from django.db import models
from django.db.models import ForeignKey, Model, SET_NULL # @UnusedImport from django.db.models import ForeignKey # @UnusedImport
from django.db.models import SET_DEFAULT, ManyToManyField # @UnusedImport
from django.utils import six from django.utils import six
from . import forms, widgets from . import forms, widgets
class BooleanField(models.BooleanField): class BooleanField(models.BooleanField):
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'form_class': forms.BooleanField} defaults = {'form_class': forms.BooleanField}
defaults.update(kwargs) defaults.update(kwargs)
@@ -20,7 +18,6 @@ class BooleanField(models.BooleanField):
class CharField(models.CharField): class CharField(models.CharField):
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'form_class': forms.CharField} defaults = {'form_class': forms.CharField}
defaults.update(kwargs) defaults.update(kwargs)
@@ -28,7 +25,6 @@ class CharField(models.CharField):
class DateField(models.DateField): class DateField(models.DateField):
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = { defaults = {
'form_class': forms.DateField} 'form_class': forms.DateField}
@@ -37,7 +33,6 @@ class DateField(models.DateField):
class DateTimeField(models.DateTimeField): class DateTimeField(models.DateTimeField):
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'form_class': forms.DateTimeField} defaults = {'form_class': forms.DateTimeField}
defaults.update(kwargs) defaults.update(kwargs)
@@ -52,7 +47,6 @@ class EmailField(models.EmailField):
class FileField(models.FileField): class FileField(models.FileField):
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'form_class': forms.FileField} defaults = {'form_class': forms.FileField}
defaults.update(kwargs) defaults.update(kwargs)
@@ -60,7 +54,6 @@ class FileField(models.FileField):
class ForeignKey(models.ForeignKey): class ForeignKey(models.ForeignKey):
def formfield(self, **kwargs): def formfield(self, **kwargs):
db = kwargs.pop('using', None) db = kwargs.pop('using', None)
if isinstance(self.rel.to, six.string_types): if isinstance(self.rel.to, six.string_types):
@@ -83,7 +76,6 @@ class ImageField(models.ImageField):
class IntegerField(models.IntegerField): class IntegerField(models.IntegerField):
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'form_class': forms.IntegerField} defaults = {'form_class': forms.IntegerField}
defaults.update(kwargs) defaults.update(kwargs)
@@ -91,7 +83,6 @@ class IntegerField(models.IntegerField):
class NullBooleanField(models.NullBooleanField): class NullBooleanField(models.NullBooleanField):
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'form_class': forms.BooleanField} defaults = {'form_class': forms.BooleanField}
defaults.update(kwargs) defaults.update(kwargs)
@@ -99,7 +90,6 @@ class NullBooleanField(models.NullBooleanField):
class PositiveSmallIntegerField(models.PositiveSmallIntegerField): class PositiveSmallIntegerField(models.PositiveSmallIntegerField):
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = { defaults = {
'form_class': forms.IntegerField, 'form_class': forms.IntegerField,
@@ -111,7 +101,6 @@ class PositiveSmallIntegerField(models.PositiveSmallIntegerField):
class PositiveIntegerField(models.IntegerField): class PositiveIntegerField(models.IntegerField):
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = { defaults = {
'form_class': forms.IntegerField, 'form_class': forms.IntegerField,
@@ -122,7 +111,6 @@ class PositiveIntegerField(models.IntegerField):
class SlugField(models.SlugField): class SlugField(models.SlugField):
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'form_class': forms.SlugField} defaults = {'form_class': forms.SlugField}
defaults.update(kwargs) defaults.update(kwargs)
@@ -130,9 +118,7 @@ class SlugField(models.SlugField):
class TextField(models.TextField): class TextField(models.TextField):
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = { defaults = {
'form_class': forms.CharField, 'form_class': forms.CharField,
'widget': widgets.Textarea 'widget': widgets.Textarea
@@ -142,7 +128,6 @@ class TextField(models.TextField):
class URLField(models.URLField): class URLField(models.URLField):
def formfield(self, **kwargs): def formfield(self, **kwargs):
defaults = {'form_class': forms.URLField} defaults = {'form_class': forms.URLField}
defaults.update(kwargs) defaults.update(kwargs)

View File

@@ -4,6 +4,7 @@ Created on 05.08.2011
@author: christian @author: christian
""" """
from django.http import Http404 from django.http import Http404
from . import registry from . import registry

View File

@@ -14,7 +14,6 @@ from django.utils.safestring import mark_safe
class AutoCompleteWidget(widgets.TextInput): class AutoCompleteWidget(widgets.TextInput):
def __init__(self, lookup_class, attrs=None, *args, **kwargs): def __init__(self, lookup_class, attrs=None, *args, **kwargs):
self.lookup_class = lookup_class self.lookup_class = lookup_class
self.allow_new = kwargs.pop('allow_new', False) self.allow_new = kwargs.pop('allow_new', False)
@@ -29,7 +28,8 @@ class AutoCompleteWidget(widgets.TextInput):
self.qs.update(qs_dict) self.qs.update(qs_dict)
def build_attrs(self, extra_attrs=None, **kwargs): 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() url = self.lookup_class.url()
if self.qs: if self.qs:
url = '%s?%s' % (url, urlencode(self.qs)) url = '%s?%s' % (url, urlencode(self.qs))
@@ -40,9 +40,9 @@ class AutoCompleteWidget(widgets.TextInput):
class AutoComboboxWidget(AutoCompleteWidget): class AutoComboboxWidget(AutoCompleteWidget):
def build_attrs(self, extra_attrs=None, **kwargs): 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' attrs[u'data-selectable-type'] = 'combobox'
return attrs return attrs
@@ -66,7 +66,8 @@ class DateTimeInput(widgets.MultiWidget):
A Widget that splits datetime input into two <input type="text"> boxes. A Widget that splits datetime input into two <input type="text"> 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 = ( widgets = (
DateInput(attrs=attrs, date_format=date_format), DateInput(attrs=attrs, date_format=date_format),
TimeInput(attrs=attrs, time_format=time_format) TimeInput(attrs=attrs, time_format=time_format)
@@ -92,7 +93,8 @@ class CheckboxInput(widgets.CheckboxInput):
result = False result = False
if result: if result:
final_attrs['checked'] = 'checked' 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. # Only add the 'value' attribute if a value is non-empty.
final_attrs['value'] = force_unicode(value) 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"> src="https://www.google.com/recaptcha/api/challenge?k=%(public_key)s">
</script><noscript><iframe </script><noscript><iframe
src="https://www.google.com/recaptcha/api/noscript?k=%(public_key)s" src="https://www.google.com/recaptcha/api/noscript?k=%(public_key)s"
height="300" width="500" frameborder="0"></iframe><br /><textarea height="130" width="500"></iframe><br /><textarea
name="recaptcha_challenge_field" rows="3" cols="40"></textarea><input name="recaptcha_challenge_field" rows="3" cols="40"></textarea><input
type="hidden" name="recaptcha_response_field" value="manual_challenge"> type="hidden" name="recaptcha_response_field" value="manual_challenge">
</noscript>""" </noscript>"""
return mark_safe(javascript % {'public_key': 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): def value_from_datadict(self, data, files, name):
return [data.get(self.recaptcha_challenge_name, None), return [data.get(self.recaptcha_challenge_name, None),
@@ -145,13 +148,11 @@ class ReCaptchaInput(widgets.Widget):
class SelectableMultiWidget(widgets.MultiWidget): class SelectableMultiWidget(widgets.MultiWidget):
def update_query_parameters(self, qs_dict): def update_query_parameters(self, qs_dict):
self.widgets[0].update_query_parameters(qs_dict) self.widgets[0].update_query_parameters(qs_dict)
class Textarea(widgets.Widget): class Textarea(widgets.Widget):
def __init__(self, attrs=None): def __init__(self, attrs=None):
# The 'rows' and 'cols' attributes are required for HTML correctness. # The 'rows' and 'cols' attributes are required for HTML correctness.
default_attrs = {'cols': '40', 'rows': '10'} default_attrs = {'cols': '40', 'rows': '10'}
@@ -163,7 +164,9 @@ class Textarea(widgets.Widget):
value = '' if value is None else value value = '' if value is None else value
final_attrs = self.build_attrs(attrs, name=name) final_attrs = self.build_attrs(attrs, name=name)
return mark_safe(u'<textarea%s>%s</textarea>' % (flatatt(final_attrs), return mark_safe(u'<textarea%s>%s</textarea>' % (flatatt(final_attrs),
conditional_escape(force_unicode(value)))) conditional_escape(
force_unicode(
value))))
class TextInput(widgets.TextInput): class TextInput(widgets.TextInput):
@@ -192,7 +195,6 @@ class URLInput(widgets.Input):
class LookupMultipleHiddenInput(widgets.MultipleHiddenInput): class LookupMultipleHiddenInput(widgets.MultipleHiddenInput):
def __init__(self, lookup_class, *args, **kwargs): def __init__(self, lookup_class, *args, **kwargs):
self.lookup_class = lookup_class self.lookup_class = lookup_class
super(LookupMultipleHiddenInput, self).__init__(*args, **kwargs) super(LookupMultipleHiddenInput, self).__init__(*args, **kwargs)
@@ -221,21 +223,22 @@ class LookupMultipleHiddenInput(widgets.MultipleHiddenInput):
return mark_safe(u'\n'.join(inputs)) return mark_safe(u'\n'.join(inputs))
def build_attrs(self, extra_attrs=None, **kwargs): 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' attrs[u'data-selectable-type'] = 'hidden-multiple'
return attrs return attrs
class AutoCompleteSelectMultipleWidget(SelectableMultiWidget): class AutoCompleteSelectMultipleWidget(SelectableMultiWidget):
def __init__(self, lookup_class, *args, **kwargs): def __init__(self, lookup_class, *args, **kwargs):
self.lookup_class = lookup_class self.lookup_class = lookup_class
widgets = [ widgets = [
AutoCompleteWidget(lookup_class, allow_new=False, AutoCompleteWidget(lookup_class, allow_new=False,
attrs={u'data-selectable-multiple': 'true'}), attrs={u'data-selectable-multiple': 'true'}),
LookupMultipleHiddenInput(lookup_class) 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): def value_from_datadict(self, data, files, name):
return self.widgets[1].value_from_datadict(data, files, name + '_1') 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__'): if value and not hasattr(value, '__iter__'):
value = [value] value = [value]
value = [u'', 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): class AutoComboboxSelectMultipleWidget(SelectableMultiWidget):
def __init__(self, lookup_class, *args, **kwargs): def __init__(self, lookup_class, *args, **kwargs):
self.lookup_class = lookup_class self.lookup_class = lookup_class
widgets = [ widgets = [
AutoComboboxWidget(lookup_class, allow_new=False, AutoComboboxWidget(lookup_class, allow_new=False,
attrs={u'data-selectable-multiple': 'true'}), attrs={u'data-selectable-multiple': 'true'}),
LookupMultipleHiddenInput(lookup_class) 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): def value_from_datadict(self, data, files, name):
return self.widgets[1].value_from_datadict(data, files, name + '_1') 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__'): if value and not hasattr(value, '__iter__'):
value = [value] value = [value]
value = [u'', 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): class AutoCompleteSelectWidget(SelectableMultiWidget):
def __init__(self, lookup_class, *args, **kwargs): def __init__(self, lookup_class, *args, **kwargs):
self.lookup_class = lookup_class self.lookup_class = lookup_class
self.allow_new = kwargs.pop('allow_new', False) self.allow_new = kwargs.pop('allow_new', False)
@@ -277,7 +281,8 @@ class AutoCompleteSelectWidget(SelectableMultiWidget):
AutoCompleteWidget(lookup_class, allow_new=self.allow_new), AutoCompleteWidget(lookup_class, allow_new=self.allow_new),
widgets.HiddenInput(attrs={u'data-selectable-type': 'hidden'}) 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): def decompress(self, value):
if value: if value:
@@ -294,7 +299,6 @@ class AutoCompleteSelectWidget(SelectableMultiWidget):
class AutoComboboxSelectWidget(SelectableMultiWidget): class AutoComboboxSelectWidget(SelectableMultiWidget):
def __init__(self, lookup_class, *args, **kwargs): def __init__(self, lookup_class, *args, **kwargs):
self.lookup_class = lookup_class self.lookup_class = lookup_class
self.allow_new = kwargs.pop('allow_new', False) self.allow_new = kwargs.pop('allow_new', False)
@@ -302,7 +306,8 @@ class AutoComboboxSelectWidget(SelectableMultiWidget):
AutoComboboxWidget(lookup_class, allow_new=self.allow_new), AutoComboboxWidget(lookup_class, allow_new=self.allow_new),
widgets.HiddenInput(attrs={u'data-selectable-type': 'hidden'}) 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): def decompress(self, value):
if value: if value:

View File

@@ -8,13 +8,19 @@ from BeautifulSoup import BeautifulSoup
class HtmlCleaner(object): class HtmlCleaner(object):
ACCEPTABLE_ELEMENTS = ['a', 'abbr', 'acronym', 'address', 'area', 'b', ACCEPTABLE_ELEMENTS = ['a', 'abbr', 'acronym', 'address', 'area', 'b',
'big', 'blockquote', 'br', 'button', 'caption', 'center', 'cite', 'big', 'blockquote', 'br', 'button', 'caption',
'code', 'col', 'colgroup', 'dd', 'del', 'dfn', 'dir', 'div', 'dl', 'center', 'cite',
'dt', 'em', 'font', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'code', 'col', 'colgroup', 'dd', 'del', 'dfn', 'dir',
'img', 'ins', 'kbd', 'label', 'legend', 'li', 'map', 'menu', 'ol', 'div', 'dl',
'p', 'pre', 'q', 's', 'samp', 'small', 'span', 'strike', 'dt', 'em', 'font', 'h1', 'h2', 'h3', 'h4', 'h5',
'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'tfoot', 'th', 'h6', 'hr', 'i',
'thead', 'tr', 'tt', 'u', 'ul', 'var'] '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 = [ ACCEPTABELE_ATTRIBUTES = [
'abbr', 'accept', 'accept-charset', 'accesskey', 'abbr', 'accept', 'accept-charset', 'accesskey',

View File

@@ -22,10 +22,10 @@ class Command(BaseCommand):
help = _("Reads raw CSS from stdin, and writes compressed CSS to stdout.") help = _("Reads raw CSS from stdin, and writes compressed CSS to stdout.")
option_list = BaseCommand.option_list + ( option_list = BaseCommand.option_list + (
make_option('-w', '--wrap', make_option('-w', '--wrap',
type='int', type='int',
default=None, default=None,
metavar='N', metavar='N',
help="Wrap output to approximately N chars per line."), help="Wrap output to approximately N chars per line."),
) )
def remove_comments(self, css): def remove_comments(self, css):
@@ -65,7 +65,6 @@ class Command(BaseCommand):
"""Remove unnecessary whitespace characters.""" """Remove unnecessary whitespace characters."""
def pseudoclasscolon(css): def pseudoclasscolon(css):
""" """
Prevents 'p :link' from becoming 'p:link'. Prevents 'p :link' from becoming 'p:link'.
@@ -157,13 +156,15 @@ class Command(BaseCommand):
def condense_hex_colors(self, css): def condense_hex_colors(self, css):
"""Shorten colors from #AABBCC to #ABC where possible.""" """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) match = regex.search(css)
while match: while match:
first = match.group(3) + match.group(5) + match.group(7) first = match.group(3) + match.group(5) + match.group(7)
second = match.group(4) + match.group(6) + match.group(8) second = match.group(4) + match.group(6) + match.group(8)
if first.lower() == second.lower(): 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) match = regex.search(css, match.end() - 3)
else: else:
match = regex.search(css, match.end()) match = regex.search(css, match.end())
@@ -235,7 +236,8 @@ class Command(BaseCommand):
css = '' css = ''
"""Read each .css file in the css_input directory, """Read each .css file in the css_input directory,
and append their content""" 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 print ' Adding: %s' % file_name
with open(os.path.join(css_input, file_name), 'r') as css_file: with open(os.path.join(css_input, file_name), 'r') as css_file:
css += css_file.read() css += css_file.read()

View File

@@ -3,13 +3,13 @@ Created on 06.06.2011
@author: christian @author: christian
""" """
import os
import fnmatch
from django.conf import settings 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.core.management.base import BaseCommand
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from optparse import make_option
import os, re, fnmatch
from scss import parser
class Command(BaseCommand): class Command(BaseCommand):
@@ -36,11 +36,12 @@ class Command(BaseCommand):
css = '' css = ''
"""Read each .css file in the css_input directory, """Read each .css file in the css_input directory,
and append their content""" 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 print ' Adding: %s' % file_name
with open(os.path.join(css_input, file_name), 'r') as css_file: with open(os.path.join(css_input, file_name), 'r') as css_file:
css += css_file.read() css += css_file.read()
with open(css_output, 'w') as css_file: with open(css_output, 'w') as css_file:
css_file.write(self.compress(css)) css_file.write(self.compress(css))
#file.write(css) # file.write(css)

View File

@@ -1,4 +1,5 @@
import logging import logging
from django.core import mail from django.core import mail
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
@@ -66,7 +67,7 @@ class MassMailer(object):
for recipient in self.recipients: for recipient in self.recipients:
mail_context['recipient'] = recipient mail_context['recipient'] = recipient
mail_to = "%s %s <%s>" % (recipient.first_name, mail_to = "%s %s <%s>" % (recipient.first_name,
recipient.last_name, recipient.email) recipient.last_name, recipient.email)
message = mail.EmailMultiAlternatives( message = mail.EmailMultiAlternatives(
subject=self.subject, subject=self.subject,
body=self.txt_template.render(mail_context), body=self.txt_template.render(mail_context),
@@ -92,7 +93,7 @@ class MassMailer(object):
return True return True
else: else:
self.log.info('Sending eMail "%s" to %d people', self.subject, 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.log.debug(self.recipients)
self.open_smtp_connection() self.open_smtp_connection()

View File

@@ -20,13 +20,16 @@ class LoginRequiredMixin(object):
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated(): 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 elif self.raise_exception: # if an exception was desired
return http.HttpResponseForbidden() # return a forbidden response. return http.HttpResponseForbidden() # return a forbidden response.
else: else:
messages.error(request, _("You need to be logged in")) messages.error(request, _("You need to be logged in"))
path = urlquote(request.get_full_path()) 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): class PermissionRequiredMixin(object):
""" """
@@ -60,18 +63,23 @@ class PermissionRequiredMixin(object):
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
# Verify class settings # Verify class settings
if self.permission_required is None or len(self.permission_required.split(".")) != 2: if self.permission_required is None or len(
raise ImproperlyConfigured("'PermissionRequiredMixin' requires 'permission_required' attribute to be set.") self.permission_required.split(".")) != 2:
raise ImproperlyConfigured(
"'PermissionRequiredMixin' requires 'permission_required' attribute to be set.")
has_permission = request.user.has_perm(self.permission_required) has_permission = request.user.has_perm(self.permission_required)
if has_permission: if has_permission:
return super(PermissionRequiredMixin, self).dispatch(request, *args, **kwargs) return super(PermissionRequiredMixin, self).dispatch(request, *args,
**kwargs)
elif self.raise_exception: elif self.raise_exception:
return http.HttpResponseForbidden() return http.HttpResponseForbidden()
else: else:
messages.warning(request, self.permission_failed_message) messages.warning(request, self.permission_failed_message)
path = urlquote(request.get_full_path()) 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): class SuperuserRequiredMixin(object):
""" """
@@ -83,10 +91,13 @@ class SuperuserRequiredMixin(object):
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
if request.user.is_superuser: # If the user is a standard user, 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 elif self.raise_exception: # *and* if an exception was desired
return http.HttpResponseForbidden() # return a forbidden response. return http.HttpResponseForbidden() # return a forbidden response.
else: 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()) 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))

View File

@@ -12,6 +12,7 @@ import markdown
register = template.Library() register = template.Library()
@register.filter(name='markdown', is_safe=True) @register.filter(name='markdown', is_safe=True)
def markdown_filter(value, arg=''): def markdown_filter(value, arg=''):
""" """
@@ -41,7 +42,8 @@ def markdown_filter(value, arg=''):
if extensions and extensions[0] == "safe": if extensions and extensions[0] == "safe":
extensions = extensions[1:] extensions = extensions[1:]
return mark_safe(markdown.markdown( 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: else:
return mark_safe(markdown.markdown( return mark_safe(markdown.markdown(
force_text(value), extensions, safe_mode=False)) force_text(value), extensions, safe_mode=False))