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
htdocs/media/
htdocs/
static/
media/
.idea
.gitignore

4
.idea/encodings.xml generated
View File

@@ -1,4 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>

View File

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

View File

@@ -1,4 +1,5 @@
import django.contrib.syndication.views
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)
"""
from aggregator.models import Feed
from django.core.management.base import BaseCommand
from aggregator.models import Feed
class Command(BaseCommand):
help = "Updates all RSS Feeds"

View File

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

View File

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

View File

@@ -1,9 +1,9 @@
from django import template
from models import Feed
class FeedListNode(template.Node):
def __init__(self, varname):
self.varname = varname
@@ -26,5 +26,6 @@ def do_get_feed_list(parser, token):
"First argument to '%s' tag must be 'as'" % bits[0]
return FeedListNode(bits[2])
register = template.Library()
register.tag('get_feed_list', do_get_feed_list)

View File

@@ -1,12 +1,23 @@
#!/bin/sh
echo "aktualisiere Übersetzungen..."
cd src
./manage.py makemessages -l de
./manange.py compilemessages -a
unset DJANGO_SETTINGS_MODULE
for dir in *
do
if [ -d $dir/locale ]
then
echo -n "$dir: "
cd $dir
django-admin.py makemessages -l de
cd ..
fi
done
sleep 5s
export DJANGO_SETTINGS_MODULE="kasu.settings.production"
./manage.py compilemessages
echo "lösche den Python Compiler Cache..."
find . -name "*.pyc" -exec rm -rf {} \;
touch kasu.wsgi
./manage.py collectstatic --noinput
./manage.py generateimages
touch kasu/wsgi.py

View File

@@ -3,11 +3,13 @@ Created on 03.10.2011
@author: christian
"""
from . import models
from django import forms
from django.utils.translation import ugettext as _
from django.contrib.auth import get_user_model
from utils.html5.widgets import DateTimeInput
from . import models
from events.models import Event
user_query = get_user_model().objects.all()
@@ -15,8 +17,8 @@ user_query = get_user_model().objects.all()
class PhotoUploadForm(forms.Form):
error_css_class = 'error'
required_css_class = 'required'
photographer = forms.ModelChoiceField(user_query, required=True,)
event = forms.ModelChoiceField(models.Event.objects.all(), required=True,)
photographer = forms.ModelChoiceField(user_query, required=True, )
event = forms.ModelChoiceField(Event.objects.all(), required=True, )
upload = forms.FileField(
label=_('Images'),
required=True,
@@ -38,20 +40,3 @@ class EditPhotoForm(forms.ModelForm):
fields = ('event', 'name', 'description', 'photographer',
'anchor_horizontal', 'anchor_vertical',
'created_date', 'on_startpage')
class EventForm(forms.ModelForm):
error_css_class = 'error'
required_css_class = 'required'
start = forms.DateTimeField(
label=_('start'), required=True,
widget=DateTimeInput() # widget=SplitDateTimeWidget()
)
end = forms.DateTimeField(
label=_('end'), required=False,
widget=DateTimeInput() # widget=SplitDateTimeWidget()
)
class Meta(object):
model = models.Event

View File

@@ -5,29 +5,11 @@ import os
from django.conf import settings
from django.core.urlresolvers import reverse
from django.db import models
from django.template.defaultfilters import slugify
from django.utils.timezone import now
from django.utils.translation import ugettext as _
from imagekit import ImageSpec
import imagekit
from imagekit.models import ImageSpecField
from pilkit import processors
import pyexiv2
from utils import COUNTRIES, OverwriteStorage
CHOICES_HORIZONTAL = (
(0.00000001, _('left')),
(0.5, _('center')),
(1, _('right'))
)
CHOICES_VERTICAL = (
(0.00000001, _('top')),
(0.5, _('middle')),
(1, _('bottom'))
)
from utils import OverwriteStorage
from kasu import image_models
def get_upload_path(instance, filename):
@@ -42,231 +24,10 @@ def get_upload_path(instance, filename):
@type filename: String
"""
extension = filename[filename.rfind('.') + 1:]
if isinstance(instance, Event):
if instance.id:
return "events/%s.%s" % (instance.id, extension)
else:
return "events/%s.%s" % (slugify(instance.name), extension)
elif isinstance(instance, Location):
if instance.id:
return "events/location/%s.%s" % (instance.id, extension)
else:
return "events/location/%s.%s" % (instance.id, extension)
elif isinstance(instance, Photo):
if isinstance(instance, Photo):
return "events/%s/%s" % (instance.event.id, filename)
def post_save_image(sender, instance=None, created=False, raw=False, **kwargs):
"""
Reganerate the images.
"""
os.remove(instance.display.path)
os.remove(instance.callout.path)
os.remove(instance.thumbnail.path)
"""
instance.callout.generate(force=True)
instance.display.generate(force=True)
instance.thumbnail.generate(force=True)
"""
class CalloutImage(ImageSpec):
format = 'PNG'
width = 940
height = 300
@property
def processors(self):
model, field_name = imagekit.utils.get_field_info(self.source) # @UnusedVariable @IgnorePep8
anchor = model.get_anchor()
if anchor:
return [processors.Transpose(), processors.ResizeToFill(
width=self.width,
height=self.height, anchor=anchor
)]
else:
return [processors.Transpose(), processors.SmartResize(
width=self.width,
height=self.height
)]
class DisplayImage(ImageSpec):
format = 'PNG'
processors = [processors.Transpose(),
processors.ResizeToFit(width=940, height=940, upscale=False)]
class ThumbnailImage(CalloutImage):
format = 'PNG'
width = 140
height = 140
imagekit.register.generator('kasu:image:callout', CalloutImage)
imagekit.register.generator('kasu:image:display', DisplayImage)
imagekit.register.generator('kasu:image:thumbnail', ThumbnailImage)
class ImageModel(models.Model):
callout = ImageSpecField(source='image', id='kasu:image:callout')
display = ImageSpecField(source='image', id='kasu:image:display')
thumbnail = ImageSpecField(source='image', id='kasu:image:thumbnail')
def get_anchor(self):
try:
anchor_horizontal = getattr(self, 'anchor_horizontal')
anchor_vertical = getattr(self, 'anchor_vertical')
except AttributeError:
return None
if anchor_horizontal and anchor_vertical:
return self.anchor_horizontal, self.anchor_vertical
else:
return None
class Meta:
abstract = True
class EventManager(models.Manager):
def current_event(self):
try:
current = self.filter(start__lte=now())
current = current.filter(end__gte=now())
return current.order_by('start', 'end')[0]
except:
return None
def next_event(self):
try:
return self.filter(start__gt=now()).order_by('start', 'end')[0]
except:
return None
def archive(self):
return self.filter(start__lt=now())
def upcoming(self, limit=3):
result = self.filter(start__gt=now()).order_by('start', 'end')
if limit:
return result[1:(limit + 1)]
else:
return result
class Event(ImageModel):
name = models.CharField(_('Name'), max_length=255)
description = models.TextField(_("Description"), blank=True)
location = models.ForeignKey('Location')
start = models.DateTimeField(_('Start'))
end = models.DateTimeField(_('End'), blank=True, null=True)
url = models.URLField(_('Homepage'), blank=True)
image = models.ImageField(_("Image"), upload_to=get_upload_path,
storage=OverwriteStorage(), blank=True, null=True)
is_tournament = models.BooleanField(_('Tournament'), default=False,
help_text=_(u'This event is a tournament, different rules apply for \
the kyu ranking.'))
photo_count = models.PositiveIntegerField(default=0, editable=False)
event_series = models.ForeignKey('Event', blank=True, null=True,
on_delete=models.SET_NULL, editable=False,
verbose_name=_('Event Series'),
help_text=_(u'Wenn dieser Event zu einer Veranstaltungsreihe gehört \
werden Ort, Beschreibung, Bild und Homepage von dem hier angegebenen \
Event übernommen.'))
objects = EventManager()
class Meta(object):
verbose_name = _('Event')
verbose_name_plural = _('Events')
ordering = ('-start', '-end',)
def __unicode__(self):
try:
return "%(name)s (%(date)s)" % {'name': self.name,
'date': self.start.date()}
except:
return "New Event Model"
def get_absolute_url(self):
kwargs = {
'pk': self.id,
'year': self.start.strftime('%Y'),
'month': self.start.strftime('%m')
}
return reverse('event-detail', kwargs=kwargs)
def get_edit_url(self):
kwargs = {
'pk': self.id,
'year': self.start.strftime('%Y'),
'month': self.start.strftime('%m')
}
return reverse('event-form', kwargs=kwargs)
def get_callout(self):
if self.image:
return self.callout
elif self.photo_set.count():
return self.photo_set.all().order_by('?')[0].callout
elif self.location.image:
return self.location.callout
else:
return None
def get_thumbnail(self):
if self.image:
return self.thumbnail
elif self.photo_set.count():
return self.photo_set.all().order_by('?')[0].thumbnail
elif self.location.image:
return self.location.thumbnail
else:
return None
def save(self, **kwargs):
if self.event_series:
master_event = self.event_series
self.description = master_event.description
self.location = master_event.location
self.url = master_event.url
self.image = master_event.image
self.photo_count = self.photo_set.count()
models.Model.save(self, **kwargs)
# Update the rest of the event series:
for sub_event in Event.objects.filter(event_series=self):
sub_event.save()
# Update the Hanchans if necesery:
for hanchan in self.hanchan_set.all():
hanchan.save()
class Location(ImageModel):
name = models.CharField(_("Name"), max_length=200)
description = models.TextField(_("Description"), blank=True)
image = models.ImageField(_("Image"), upload_to=get_upload_path,
storage=OverwriteStorage(), blank=True, null=True)
url = models.URLField(_('Homepage'), blank=True)
postal_code = models.CharField(_('Postal Code'), max_length=6)
street_address = models.CharField(_('Street Address'), max_length=127)
locality = models.CharField(_('Locality'), max_length=127)
country = models.CharField(_('Country'), max_length=2, choices=COUNTRIES)
class Meta(object):
verbose_name = _('Venue')
verbose_name_plural = _('Venues')
def __unicode__(self):
return self.name
@property
def address(self):
address = (self.street_address, self.locality, self.country,)
return ','.join(address)
class PhotoManager(models.Manager):
def get_random(self, startpage=True):
if startpage:
@@ -279,26 +40,26 @@ class PhotoManager(models.Manager):
return Photo()
class Photo(ImageModel):
class Photo(image_models.ImageModel):
name = models.CharField(_("Name"), max_length=100, blank=True)
image = models.ImageField(_("Image"), upload_to=get_upload_path,
storage=OverwriteStorage())
anchor_horizontal = models.FloatField(
_('horizontal Anchorpoint'),
choices=CHOICES_HORIZONTAL,
choices=image_models.CHOICES_HORIZONTAL,
blank=True, null=True,
help_text='Der Ankerpunkt ist der interessante Teil des Bildes,\
welcher nie abgeschnitten werden darf'
)
anchor_vertical = models.FloatField(
_('vertical Anchorpoint'),
choices=CHOICES_VERTICAL,
choices=image_models.CHOICES_VERTICAL,
blank=True, null=True,
help_text='Wenn kein Ankerpunkt von Hand (horizontal und vertikal)\
festgelegt wird, versucht die Software diesen selbst zu erraten.'
)
event = models.ForeignKey(Event)
event = models.ForeignKey('events.Event')
description = models.TextField(
_("Description"),
max_length=300,
@@ -321,10 +82,12 @@ class Photo(ImageModel):
orientation = 1
class Meta:
get_latest_by = "created_date"
ordering = ["created_date"]
db_table = 'events_photo'
verbose_name = _('Event Image')
verbose_name_plural = _('Event Images')
ordering = ["created_date"]
get_latest_by = "created_date"
def __unicode__(self):
return os.path.basename(self.image.name)
@@ -395,9 +158,14 @@ class Photo(ImageModel):
Triggers to save related Event to save. This should force an update for
the denormalized Photo count.
"""
ImageModel.save(self, **kwargs)
super(Photo, self).save()
self.save_metadata()
self.event.save()
models.signals.post_save.connect(post_save_image, sender=Photo)
def update_event(sender, instance=None, created=False, raw=False, **kwargs):
image_models.regenerate_image_cache(sender, instance=instance)
instance.event.save()
models.signals.post_save.connect(update_event, sender=Photo)
models.signals.post_delete.connect(update_event, sender=Photo)

View File

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

View File

@@ -1,4 +1,4 @@
{% extends "events/photo_list.html" %}
{% extends "gallery/photo_list.html" %}
{% load i18n comments %}
{% block title %} {{ photo.name }} - {{ photo.event.name }} {% endblock %}
@@ -22,35 +22,36 @@
<a href="{{ photo.next_photo.get_absolute_url }}" class="next">Next</a>
{% endif %}
</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">
{% csrf_token %}
<fieldset>
{% include "form.html" %}
<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>
<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"><img src="{{STATIC_URL}}icons/disk.png" alt=""> {% trans "save" %}</button>
</p>
</fieldset>
</form>
{% else %}
<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 %}
{% endif %}
{% endblock %}

View File

@@ -1,4 +1,4 @@
{% extends "events/photo_gallery.html" %}
{% extends "events/event_detail.html" %}
{% load i18n comments %}
{% 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 import get_user_model
from django.core.urlresolvers import reverse
from django.http import HttpResponse, Http404
from django.http import Http404
from django.shortcuts import redirect
from django.utils import timezone
from django.utils.decorators import method_decorator
from django.utils.translation import ugettext as _
from django.views import generic
from icalendar import Calendar, Event
import pyexiv2
from utils.mixins import PermissionRequiredMixin
from . import models, forms
from events.models import Event
from .models import Photo
from . import forms
class DeleteEventPhoto(generic.DeleteView):
model = models.Photo
"""
def get_object(self, queryset=None):
return models.Photo.objects.get(pk=self.kwargs['pk'])
"""
model = Photo
def get_success_url(self):
return reverse('event-photo-list', args=[self.object.event.id])
def get_context_data(self, **kwargs):
context = super(DeleteEventPhoto, self).get_context_data()
context['event'] = self.object.event
return context
@method_decorator(permission_required('events.delete_photo'))
def dispatch(self, *args, **kwargs):
return super(DeleteEventPhoto, self).dispatch(*args, **kwargs)
class EventArchiveIndex(generic.ArchiveIndexView):
allow_empty = True
context_object_name = 'event_list'
date_field = 'start'
model = models.Event
queryset = model.objects.all()
paginate_by = 15
def get_context_data(self, **kwargs):
context = generic.ArchiveIndexView.get_context_data(self, **kwargs)
context['is_archive'] = True
return context
class EventArchiveMonth(generic.MonthArchiveView):
date_field = 'start'
make_object_list = True
model = models.Event
month_format = '%m'
paginate_by = 15
template_name = 'events/event_archive.html'
def get_context_data(self, **kwargs):
context = generic.MonthArchiveView.get_context_data(self, **kwargs)
context['is_archive'] = True
return context
class EventArchiveYear(generic.YearArchiveView):
date_field = 'start'
make_object_list = True
model = models.Event
paginate_by = 15
template_name = 'events/event_archive.html'
year_format = '%Y'
def get_context_data(self, **kwargs):
context = generic.YearArchiveView.get_context_data(self, **kwargs)
context['is_archive'] = True
return context
class EventDetail(generic.DetailView):
model = models.Event
def get_context_data(self, **kwargs):
context = generic.DetailView.get_context_data(self, **kwargs)
context['form'] = forms.PhotoUploadForm(initial={'event': self.object, 'photographer': self.request.user})
return context
class EventForm(PermissionRequiredMixin, generic.UpdateView):
form_class = forms.EventForm
permission_required = 'events.add_event'
def get_object(self, queryset=None):
"""
If an id has been submitted, try return the existing Event for an update,
else creates a new one.
@param queryset:
"""
if self.kwargs.get('pk'):
event = models.Event.objects.get(pk=self.kwargs['pk'])
if event.event_series:
return event.event_series
else:
return event
else:
return models.Event()
class EventGallery(generic.ListView):
template_name = 'events/photo_gallery.html'
queryset = models.Event.objects.filter(start__lt=timezone.now(), photo_count__gt=0)
template_name = 'gallery/photo_gallery.html'
queryset = Event.objects.filter(start__lt=timezone.now(), photo_count__gt=0)
paginate_by = 12
class EventListIcal(generic.View):
"""
Generates an returns an iCal File with all upcoming events.
"""
def add_event(self, event):
ics_event = Event()
dtstart = timezone.localtime(event.start)
dtend = timezone.localtime(event.end)
ics_event.add('DTSTART', dtstart)
ics_event.add('SUMMARY', event.name)
ics_event.add('DESCRIPTION', event.description)
ics_event.add('LOCATION', event.location.address)
ics_event.add('URL', 'http://www.kasu.at' + event.get_absolute_url())
ics_event['UID'] = 'event-%d@www.kasu.at' % event.pk
ics_event.add('PRIORITY', 5)
if event.end:
ics_event.add('DTEND', dtend)
self.calendar.add_component(ics_event)
def get(self, request, *args, **kwargs):
response = HttpResponse(mimetype="text/calendar; charset=UTF-8")
self.calendar = Calendar()
self.calendar.add('prodid', 'http://www.kasu.at/')
self.calendar.add('version', '2.0')
for event in models.Event.objects.upcoming(limit=None):
self.add_event(event)
response.write(self.calendar.to_ical())
return response
class EventPhoto(generic.UpdateView):
form_class = forms.EditPhotoForm
model = models.Photo
template_name = 'events/photo_detail.html'
model = Photo
template_name = 'gallery/photo_detail.html'
def get_context_data(self, **kwargs):
context = super(EventPhoto, self).get_context_data()
event = models.Event.objects.get(id=self.kwargs['event'])
context['event'] = event
context['event'] = self.object.event
return context
def post(self, request, *args, **kwargs):
if request.POST.get('rotate') and request.user.has_perm('events.change_photo'):
photo = models.Photo.objects.get(pk=kwargs['pk'])
if request.POST.get('rotate') and request.user.has_perm(
'events.change_photo'):
photo = Photo.objects.get(pk=kwargs['pk'])
photo.rotate(request.POST['rotate'])
# return redirect(photo.get_absolute_url())
return self.get(request)
@@ -172,20 +68,21 @@ class EventPhotoList(generic.ListView):
def get_context_data(self, **kwargs):
context = generic.ListView.get_context_data(self, **kwargs)
context['event'] = self.event
context['form'] = forms.PhotoUploadForm(initial={'event': self.event, 'photographer': self.request.user})
context['form'] = forms.PhotoUploadForm(
initial={'event': self.event, 'photographer': self.request.user})
return context
def get_queryset(self):
try:
self.event = models.Event.objects.get(id=self.kwargs['event'])
return models.Photo.objects.filter(event=self.event)
except models.Event.DoesNotExist:
self.event = Event.objects.get(id=self.kwargs['event'])
return Photo.objects.filter(event=self.event)
except Event.DoesNotExist:
raise Http404(_('Event does not exist'))
class EventPhotoUpload(generic.FormView):
form_class = forms.PhotoUploadForm
template_name = 'events/photo_upload.html'
template_name = 'gallery/photo_upload.html'
@method_decorator(permission_required('events.add_photo'))
def dispatch(self, *args, **kwargs):
@@ -193,7 +90,7 @@ class EventPhotoUpload(generic.FormView):
def get_context_data(self, **kwargs):
context = generic.FormView.get_context_data(self, **kwargs)
context['event_list'] = models.Event.objects.archive()[:12]
context['event_list'] = Event.objects.archive()[:12]
return context
def get_initial(self):
@@ -208,14 +105,16 @@ class EventPhotoUpload(generic.FormView):
"""
"""
self.event = models.Event.objects.get(id=self.request.REQUEST.get('event'))
photographer = self.request.POST.get('photographer', self.request.user.id)
self.event = Event.objects.get(
id=self.request.REQUEST.get('event'))
photographer = self.request.POST.get('photographer',
self.request.user.id)
photographer = get_user_model().objects.get(id=photographer)
self.counter = 1
for upload in self.request.FILES.getlist('upload'):
name = upload.name
created_date, description = self.read_exif(upload)
photo = models.Photo(
photo = Photo(
event=self.event,
photographer=photographer,
image=upload,
@@ -241,7 +140,3 @@ class EventPhotoUpload(generic.FormView):
description = ''
return created_date, description
class UpcomingEvents(generic.ListView):
queryset = models.Event.objects.upcoming(limit=None)
paginate_by = 16

View File

@@ -299,46 +299,28 @@ ul.info li {
}
/** PAGINATOR **/
.paginator {
clear: both;
border: 1px solid #d3d7cf;
border-radius: 10px;
text-align: center;
background-color: #f9f9f9;
box-shadow: inset 0px 1px 0px 0px #ffffff;
background: -webkit-gradient(linear, left top, left bottom, color-stop(0.05, #f9f9f9
), color-stop(1, #e9e9e9) );
background: -moz-linear-gradient(center top, #f9f9f9 5%, #e9e9e9 100%);
padding: 4px 10px 2px 10px;
.pagination {
text-align:center
}
.paginator a, .paginator .current {
.pagination a, .pagination .current, .pagination .next, .pagination .previous {
display: inline-block;
margin: 0px 2px;
padding: 2px;
min-width: 17px;
color: #2e3436;
text-decoration: none;
border-radius: 5px;
text-decoration: none;
padding: 0 0.5em 0 0.5em;
}
.paginator .current {
border: none;
color: #a40000;
background: #fff;
border-radius: 5px;
}
.paginator .next {
display: inline-block;
.pagination .next {
float: right;
background: none;
}
.paginator .prev {
display: inline-block;
.pagination .previous {
float: left;
background: none;
}
.center {
text-align: center;
}
@@ -403,4 +385,4 @@ ul.tabs li.active a {border-bottom: 3px solid #bc0a19; color: #bc0a19}
}
fieldset.comment {padding: 0}
fieldset.comment legend {margin-left: 15px}
fieldset.comment .buttonbar {margin: 0; width: 100%}
fieldset.comment .buttonbar {margin: 0; width: 100%}

View File

@@ -136,14 +136,14 @@ ul.main_menu {padding:0px;}
width: 920px;
}
#navigation {
#navigation, .pagination {
clear: both;
background: url(../img/navigation-bg.png) no-repeat left top;
height: 56px;
list-style: none;
margin: 0 auto;
padding: 8px 0 0 30px;
width: 920px;
padding: 8px 35px 0px 25px;
width: 900px;
}
#navigation a {
@@ -434,6 +434,23 @@ ul.tabs li.active a {
text-shadow: 1px 1px 0px #98231a;
}
.pagination a, .pagination .current, .pagination .next, .pagination .previous {
display: inline-block;
padding: 2px;
color: #FFF;
font-weight: bold;
height: 33px;
text-decoration: none;
padding: 17px 0.5em 0 0.5em;
}
.pagination .current {
color: #a40000;
}
.pagination .disabled {color: #ccc}
img.avatar {
border: none;
box-shadow: 2px 2px 2px #888;

View File

@@ -337,6 +337,12 @@ fieldset ul li {
}
ul.tabs {margin-top:1em;}
.paginator {clear:both;}
.pagination {clear:both;}
.pagination a, .pagination .current, .pagination .next, .pagination .previous {
display: inline-block;
text-decoration: none;
padding: 0 0.5em 0 0.5em;
}
.gallery {float: left; width:150px; height:150px; margin: 10px;}
.gallery h3 {font-size: 12pt;}
.gallery h3 {font-size: 12pt;}

View File

@@ -1,20 +1,22 @@
{% 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>
<nav class="pagination">
{% if page_obj.has_previous %}
<a class="previous" href="?page={{ page_obj.previous_page_number }}"><span aria-hidden="true">&larr;</span> {% trans "Previous" %}</a></li>
{% else %}
<div class="previous disabled"><span aria-hidden="true">&larr;</span> {% trans "Prev" %}</div>
{% endif %}
{% for page in paginator.page_range %}
{% ifequal page_obj.number page %}
<div class="current">{{page}}</div>
{% else %}
<a href="?page={{page}}">{{page}}</a>
{% endifequal %}
{% endfor %}
{% if page_obj.has_next %}
<a class="next" href="?page={{ page_obj.next_page_number }}">{% trans "Next" %} <span aria-hidden="true">&rarr;</span></a></li>
{% else %}
<div class="next disabled">{% trans "Next" %} <span aria-hidden="true">&rarr;</span></div>
{% endif %}
</ul>
</nav>

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,6 +6,7 @@ Created on 23.05.2011
"""
from django.core.cache import cache
from django.db import transaction
from mahjong_ranking import models
from . import logger
@@ -30,7 +31,8 @@ class DenormalizationUpdateMiddleware(object):
if len(event_ranking_queue) > 0:
while len(event_ranking_queue) > 0:
event_id, user_id = event_ranking_queue.pop()
logger.info("recalculate %d tournament Ranking in %s", user_id, event_id)
logger.info("recalculate %d tournament Ranking in %s", user_id,
event_id)
ranking = models.EventRanking.objects.get_or_create(
event_id=event_id, user_id=user_id)[0]
ranking.recalculate()
@@ -57,7 +59,8 @@ class DenormalizationUpdateMiddleware(object):
user_id=user_id, season_id=season_id)[0]
ranking.recalculate()
else:
logger.error('Season: %i; Benutzer Nr. %i - existiert nicht!', season_id, user_id)
logger.error('Season: %i; Benutzer Nr. %i - existiert nicht!',
season_id, user_id)
cache.set('ladder_ranking_queue', ladder_ranking_queue, 360)
transaction.commit()

View File

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

View File

@@ -1,17 +1,11 @@
{% extends "events/event_site.html" %}
{% extends "events/event_detail.html" %}
{% load i18n comments%}
{% block title %}{% trans "Tournament Ranking" %}: {{ event.name }}{% endblock %}
{% block teaser %}<h1>{% trans "Tournament Ranking" %}: {{ event.name }}</h1>{% endblock %}
{% block event_content %}
{% 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 %}
{% block maincontent %}
<div class="grid_12">
<table>
<thead>
@@ -21,13 +15,14 @@
<th rowspan="2">{% trans "Nickname" %}</th>
<th rowspan="2">{% trans "Name" %}</th>
<th colspan="2">{% trans 'Average' %}</th>
<th colspan="2">Hanchans</th>
<th colspan="3">Hanchans</th>
</tr>
<tr>
<th>{% trans 'Placement' %}</th>
<th>{% trans "Score" %}</th>
<th>{% trans "won" %}</th>
<th>{% trans "good" %}</th>
<th>{% trans 'Placement' %}</th>
<th>{% trans "Score" %}</th>
<th>{% trans "count" %}</th>
<th>{% trans "good" %}</th>
<th>{% trans "won" %}</th>
</tr>
</thead>
{% for player in eventranking_list %}
@@ -42,11 +37,12 @@
{% endif %}
</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="right">{{player.avg_score|floatformat:0 }}</td>
<td class="center">{{player.won_hanchans}}</td>
<td class="center">{{player.good_hanchans}}</td>
<td class="right">{{player.hanchan_count}}</td>
<td class="right">{{player.good_hanchans}}</td>
<td class="right">{{player.won_hanchans}}</td>
</tr>
{% endwith %}
{% empty %}

View File

@@ -1,10 +1,10 @@
{% extends "base.html" %}
{% extends "events/event_detail.html" %}
{% load i18n comments %}
{% block meta_title %}{% trans 'Delete Hanchan' %}{% endblock %}
{% block content %}
<form method="post">
{% block maincontent %}
<form method="post" class="grid_12">
{% csrf_token %}
<fieldset>
<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 %}
{% block title %}
{% if hanchan.id %}{% trans "Edit Hanchan" %}{% else %}{% trans "Add Hanchan" %}{% endif %}
{% endblock %}
{% block event_content %}
{% block maincontent %}
{% get_fieldset "event, start" from form as event_formset %}
{% if perms.mahjong_ranking.delete_hanchan %}
{% get_fieldset "comment, confirmed" from form as hanchan_formset %}

View File

@@ -1,53 +1,56 @@
{% extends "events/event_site.html" %}
{% load i18n comments %}
{% extends "events/event_detail.html" %}
{% load i18n humanize %}
{% block title %}Hanchans: {{ event.name }}{% endblock %}
{% block event_content %}
{% if event.is_tournament %}
<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 %}
{% block maincontent %}
<h2 class="grid_12">{% trans 'Played Hanchans' %}</h2>
<p>&nbsp;</p>
{% for hanchan in hanchan_list %}
<h3 class="grid_12 clearfix" id="{{ hanchan.pk }}">{{hanchan.start|time:'H:i'}}: {{ hanchan.player_names }}</h3>
{% for player in hanchan.player_set.all %}
<div class="player" >
<a 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=""
title="{% if player.dan_points != None %}Dan P.: {{player.dan_points}}{% else %}Kyu P.: {{player.kyu_points}}{% endif %} - {{player.comment}}"/></a>
<h4>{{player.placement}}. - <a href="{% url 'player-ladder-score' player.user %}">{{ player.user }}</a></h4>
<strong>{% trans 'Score' %}:</strong> {{player.score}}
</div>
{% endfor %}
{% if not hanchan.valid %}
<p class="grid_12 error"><strong>Ungültig:</strong> {{hanchan.check_validity}}</p>
{% elif not hanchan.confirmed %}
<p class="grid_12 error">Diese Hanchan wurde nicht anerkannt und wird daher nicht gezählt.</p>
{% elif hanchan.comment %}
<p class="grid_12">{{ hanchan.comment }}</p>
{% endif %}
<p class="grid_12 more_link">
{% if perms.mahjong_ranking.delete_hanchan %}
<a href="{% url 'delete-hanchan' hanchan.pk %}" class="button"><img src="{{STATIC_URL}}icons/table_delete.png" 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>
<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 %}
<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>
<div class="grid_2">
<a class="player" href="{% url 'player-ladder-score' player.user %}" title="{{ player.comment }}">{{ player.user }}</a>
<p><strong>{{ player.placement|ordinal }} {% trans 'Place' %}</strong><br />
<strong>{% trans 'Score' %}:</strong> {{ player.score|intcomma }}<br />
{% if player.dan_points != None %}
<strong>{% trans 'Dan Points' %}:</strong> {{ player.dan_points }}
{% else %}
<strong>{% trans 'Kyu Points' %}:</strong> {{ player.kyu_points|default:0 }}
{% endif %}
</p>
</div>
{% endfor %}
{% if not hanchan.valid %}
<p class="grid_12 error"><strong>Ungültig:</strong> {{hanchan.check_validity}}</p>
{% elif not hanchan.confirmed %}
<p class="grid_12 error">Diese Hanchan wurde nicht anerkannt und wird daher nicht gezählt.</p>
{% elif hanchan.comment %}
<p class="grid_12">{{ hanchan.comment }}</p>
{% endif %}
<p class="grid_12 more_link">
{% if perms.mahjong_ranking.delete_hanchan %}
<a href="{% url 'delete-hanchan' hanchan.pk %}" class="button"><img src="{{STATIC_URL}}icons/table_delete.png"
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 %}
<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 %}
{% endblock %}
{% block buttonbar %}
{% 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="{% url 'add-hanchan-form' event.id %}"><img src="{{STATIC_URL}}icons/table_add.png" alt="{% trans 'Add' %}"/> {% trans 'Add Hanchan' %}</a>
{% endif %}
{% 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="{% url 'add-hanchan-form' event.id %}"><img src="{{STATIC_URL}}icons/table_add.png"
alt="{% trans 'Add' %}"/> {% trans 'Add Hanchan' %}</a>
{% endif %}
{% endblock %}

View File

@@ -1,7 +1,9 @@
{% extends "base.html" %}
{% load i18n comments%}
{% block teaser %} <h2>Mahjong Ranking - {{season.name}}</h2> {% endblock %}
{% block teaser %}
<h2>Mahjong Ranking - {{season.name}}</h2>
{% endblock %}
{% block maincontent %}
<main class="grid_12">
@@ -49,14 +51,6 @@
{% endblock %}
{% 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>
<ul class="list">
{% for hanchan in latest_hanchan_list %}
@@ -69,9 +63,17 @@
</ul>
<h3>{% trans 'Latest Events' %}</h3>
<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>
{% endfor %}
</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 %}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
from django.core.management.base import BaseCommand
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.
"""
from optparse import make_option
from django.conf import settings
from django.contrib import auth
from django.contrib.sessions.models import Session
from django.core.management.base import BaseCommand
from optparse import make_option
class Command(BaseCommand):
@@ -45,7 +46,8 @@ class Command(BaseCommand):
self.stderr.write('Session "%s" does not exist' % session_key)
continue
except settings.AUTH_USER_MODEL.DoesNotExist:
self.stderr.write('Session "%s" has no registed User' % session_key)
self.stderr.write(
'Session "%s" has no registed User' % session_key)
continue
if options['delete']:
self.stdout.write('deleting %s' % user.username)

View File

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

View File

@@ -6,14 +6,13 @@
{% block teaser %}<h2>{% trans 'profile for' %} {{membership.user.username|title}}</h2>{% endblock %}
{% block navigation %}
{% if kyu_dan_ranking %}
<ul id="navigation">
<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-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 'maistar-player-games' membership.user.username %}">{% trans "Mai-Star Games" %}</a></li>
</ul>
{% endif %}
{% endblock %}
{% block maincontent %}

View File

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

View File

@@ -27,21 +27,4 @@ urlpatterns = patterns(
url(r'^(?P<username>[\-\.\d\w]+)/edit/$',
views.EditMembership.as_view(),
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 utils import mixins
from . import forms, models
@@ -49,7 +48,8 @@ class ActivateRegistration(generic.DetailView):
def login(self, user):
backend = auth.get_backends()[0]
user.backend = "%s.%s" % (backend.__module__, backend.__class__.__name__) # @IgnorePep8
user.backend = "%s.%s" % (
backend.__module__, backend.__class__.__name__) # @IgnorePep8
auth.login(self.request, user)
messages.success(self.request, _('Activation successful. \
You can now login anytime with you username and password.'))
@@ -81,7 +81,8 @@ class MembershipDetail(mixins.LoginRequiredMixin, generic.DetailView):
def get_object(self, queryset=None):
if self.kwargs.get('username'):
user = get_object_or_404(get_user_model(), username=self.kwargs['username'])
user = get_object_or_404(get_user_model(),
username=self.kwargs['username'])
return models.Membership.objects.get_or_create(user=user)[0]
elif self.request.user.is_authenticated():
return models.Membership.objects.get(user=self.request.user)

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,13 +3,13 @@ Created on 06.06.2011
@author: christian
"""
import os
import fnmatch
from django.conf import settings
from django.contrib.sites.models import Site
from django.contrib.sites.models import Site
from django.core.management.base import BaseCommand
from django.utils.translation import ugettext as _
from optparse import make_option
import os, re, fnmatch
from scss import parser
class Command(BaseCommand):
@@ -22,13 +22,13 @@ class Command(BaseCommand):
def handle(self, *args, **options):
CSS_ROOT = os.path.join(settings.STATICFILES_DIRS[0], 'css')
for site in Site.objects.all():
css_input = os.path.join(CSS_ROOT, site.domain)
css_input = os.path.join(CSS_ROOT, site.domain)
css_output = '%s/%s.css' % (CSS_ROOT, site.domain.replace('.', '_'))
print _("Compressing CSS for %s") % site.name
print "Input Dir: %s" % css_input
print "Output File: %s" % css_output
try:
os.makedirs(css_input)
except OSError:
@@ -36,11 +36,12 @@ class Command(BaseCommand):
css = ''
"""Read each .css file in the css_input directory,
and append their content"""
for file_name in fnmatch.filter(sorted(os.listdir(css_input)), '*.css'):
for file_name in fnmatch.filter(sorted(os.listdir(css_input)),
'*.css'):
print ' Adding: %s' % file_name
with open(os.path.join(css_input, file_name), 'r') as css_file:
css += css_file.read()
with open(css_output, 'w') as css_file:
css_file.write(self.compress(css))
#file.write(css)
# file.write(css)

View File

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

View File

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

View File

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