Fehler bei Vergabe von Bonuspunkte korrigiert.

Kommentare für Bonuspunkte werden jetzt als Kommentar beim Spieler hinterlassen, nicht als Kommentar in der Hanchan.
FIXED: 3_in_a_row counter wurde nicht zurückgesetzt wenn Bonuspunkte vergeben wurden.
FIXED: Durchschnittliche Platzierung während eines Events wurde nur als Ganzzahl berechnet. Wird nun als Fießkomma berechnet und gesichert.
This commit is contained in:
Christian Berg
2016-01-09 22:55:26 +01:00
parent 088efe2f39
commit b1586efbab
155 changed files with 2571 additions and 2835 deletions

1
.gitignore vendored
View File

@@ -10,6 +10,7 @@ __pycache__/
.Python
env/
build/
upload/
develop-eggs/
dist/
downloads/

View File

@@ -1 +0,0 @@

View File

@@ -1,21 +0,0 @@
from django.contrib import admin
from models import Feed, FeedItem
admin.site.register(
Feed,
list_display=["title", "public_url", "last_update", 'is_functional'],
list_filter=["is_functional"],
ordering=["title"],
search_fields=["title", "public_url"],
list_per_page=500,
)
admin.site.register(
FeedItem,
list_display=['title', 'feed', 'date_modified'],
list_filter=['feed'],
search_fields=['feed__title', 'feed__public_url', 'title'],
date_heirarchy=['date_modified'],
)

View File

@@ -1,25 +0,0 @@
import django.contrib.syndication.views
from .models import FeedItem
# noinspection PyMethodMayBeStatic
class LatestFeedItems(django.contrib.syndication.views.Feed):
link = "http://aol.animanga.at/"
description = "Aktuelle Nachrichten aus der Austrian Otaku League"
title = "AOL - Newsfeed"
def items(self):
return FeedItem.objects.get_recent_items()
def item_title(self, item):
return "%s: %s" % (item.feed.title, item.title)
def item_description(self, item):
return item.summary
def item_author_name(self, item):
return item.feed.title
def item_pubdate(self, item):
return item.date_modified

View File

@@ -1 +0,0 @@
# -

View File

@@ -1 +0,0 @@
#

View File

@@ -1,21 +0,0 @@
"""
Update feeds for Django community page. Requires Mark Pilgrim's excellent
Universal Feed Parser (http://feedparser.org)
"""
from django.core.management.base import BaseCommand
from aggregator.models import Feed
class Command(BaseCommand):
help = "Updates all RSS Feeds"
def handle(self, *args, **options):
verbose = int(options['verbosity']) > 0
for feed in Feed.objects.filter(is_functional=True):
if verbose:
print
print "%s - URL: %s" % (feed.title, feed.feed_url)
print '=' * 80
feed.parse()

View File

@@ -1,45 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import utils.html5.models
class Migration(migrations.Migration):
dependencies = [
('sites', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Feed',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('title', utils.html5.models.CharField(max_length=500)),
('feed_url', utils.html5.models.URLField(unique=True, max_length=255)),
('public_url', utils.html5.models.URLField(max_length=255)),
('last_update', utils.html5.models.DateTimeField(null=True, blank=True)),
('is_functional', utils.html5.models.BooleanField(default=True)),
('site', utils.html5.models.ForeignKey(to='sites.Site')),
],
options={
'ordering': ('title',),
},
),
migrations.CreateModel(
name='FeedItem',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('title', utils.html5.models.CharField(max_length=500)),
('link', utils.html5.models.URLField(max_length=500)),
('guid', utils.html5.models.CharField(unique=True, max_length=255, db_index=True)),
('summary', utils.html5.models.TextField(blank=True)),
('date_modified', utils.html5.models.DateTimeField()),
('feed', utils.html5.models.ForeignKey(related_name='feed_items', to='aggregator.Feed')),
],
options={
'ordering': ('-date_modified',),
},
),
]

View File

@@ -1,114 +0,0 @@
"""
Created on 05.02.2011
@author: christian
"""
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
import django.db.models
import feedparser
from utils.html5 import models
class FeedManager(django.db.models.Manager):
def active(self):
site = settings.SITE_ID
feeds = self.filter(is_functional=True, site=site)
for feed in feeds:
if feed.last_update:
feed_age = timezone.now() - feed.last_update
if feed_age > timedelta(hours=12):
feed.parse()
else:
feed.parse()
return feeds
class FeedItemManager(django.db.models.Manager):
def recent_items(self, max_items=10, site=None):
site = site or settings.SITE_ID
return self.select_related().filter(feed__site=site)[:max_items]
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)
public_url = models.URLField(max_length=255)
last_update = models.DateTimeField(blank=True, null=True)
is_functional = models.BooleanField(default=True)
objects = FeedManager()
def __unicode__(self):
return self.title
def parse(self):
parsed_feed = feedparser.parse(self.feed_url)
html_parser = HTMLParser.HTMLParser()
if parsed_feed.bozo and type(
parsed_feed.bozo_exception) == urllib2.URLError:
self.is_functional = False
return self.save()
for feed_entry in parsed_feed.entries:
title = html_parser.unescape(feed_entry.title)
if not title:
continue
link = feed_entry.link
guid = feed_entry.get("id", link)
summary = html_parser.unescape(
feed_entry.get("summary", feed_entry.get(
"description",
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())
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()
class Meta:
ordering = ("title",)
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)
guid = models.CharField(max_length=255, unique=True, db_index=True)
summary = models.TextField(blank=True)
date_modified = models.DateTimeField()
objects = FeedItemManager()
class Meta:
ordering = ("-date_modified",)
def __unicode__(self):
return self.title
def get_absolute_url(self):
return self.link

View File

@@ -1,16 +0,0 @@
from django.contrib.sitemaps import Sitemap
from models import FeedItem
# noinspection PyMethodMayBeStatic
class FeedItemSitemap(Sitemap):
changefreq = "never"
priority = 0.5
def items(self):
return FeedItem.objects.get_recent_items()
def lastmod(self, obj):
return obj.date_modified

View File

@@ -1,31 +0,0 @@
from django import template
from models import Feed
class FeedListNode(template.Node):
def __init__(self, varname):
self.varname = varname
def render(self, context):
context[self.varname] = Feed.objects.filter(is_defunct=False)
return ''
# noinspection PyUnusedLocal
def do_get_feed_list(parser, token):
"""
{% get_feed_list as feed_list %}
"""
bits = token.contents.split()
if len(bits) != 3:
raise template.TemplateSyntaxError, \
"'%s' tag takes two arguments" % bits[0]
if bits[1] != "as":
raise template.TemplateSyntaxError, \
"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

@@ -15,12 +15,12 @@ def content_menus(request):
current_path = request.path_info[1:request.path_info.rfind('.')]
# erzeuge das Top-Level Menü
top_menu_items = []
top_level_pages = cache.get('top_level_pages')
if top_level_pages is None:
top_level_pages = models.Page.objects.filter(parent=None)
top_level_pages = top_level_pages.exclude(slug='index')
top_level_pages = top_level_pages.order_by('position')
top_level_pages = top_level_pages.prefetch_related('subpages')
cache.set('top_level_pages', top_level_pages, 360)
for item in top_level_pages:
if current_path.startswith(item.path):
@@ -28,7 +28,6 @@ def content_menus(request):
current_top_page = item
else:
item.active = False
top_menu_items.append(item)
# Entdecke die aktuell geöffnete Seite
all_pages = cache.get('all_pages')
@@ -43,7 +42,7 @@ def content_menus(request):
break
current_path = current_path[0:current_path.rfind('.')]
return {'top_menu_items': top_menu_items,
return {'top_menu_items': top_level_pages,
'current_top_page': current_top_page,
'current_path': current_path,
'current_page': current_page

View File

@@ -9,8 +9,6 @@ from django.utils.feedgenerator import Rss201rev2Feed
from models import Article
# noinspection PyMethodMayBeStatic
class LatestNews(Feed):
link = "http://www.kasu.at/"
description = _("Current news from Kasu")

View File

@@ -12,7 +12,6 @@ import json
class Command(BaseCommand):
help = "Synchornisiert den Facenbook Feed für die Anzeige auf der Homepage"
def handle(self, *args, **options):
#graph_api = facebook.GraphAPI(settings.FACEBOOK_ACCESS_TOKEN)
#facebook_page = graph_api.get_object(settings.FACEBOOK_APP_ID+'/feed/')

View File

@@ -7,7 +7,6 @@ from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
@@ -16,17 +15,36 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='Article',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('headline_de', models.CharField(max_length=255, verbose_name='Schlagzeile')),
('headline_en', models.CharField(max_length=255, verbose_name=b'Headline', blank=True)),
('id', models.AutoField(
verbose_name='ID',
serialize=False, auto_created=True,
primary_key=True)),
('headline_de', models.CharField(
max_length=255, verbose_name='Schlagzeile')),
('headline_en', models.CharField(
max_length=255, verbose_name=b'Headline', blank=True)),
('content_de', models.TextField(verbose_name='Inhalt')),
('content_en', models.TextField(verbose_name=b'Content', blank=True)),
('image', models.ImageField(upload_to=b'news/', null=True, verbose_name='Bild', blank=True)),
('slug', models.SlugField(unique_for_month=b'date_created', verbose_name='Slug')),
('status', models.SmallIntegerField(default=1, verbose_name='Status', choices=[(-1, 'Zur\xfcckgewiesen'), (0, 'Wartend...'), (1, 'Ver\xf6ffentlicht')])),
('date_created', models.DateTimeField(verbose_name='Erstellt', blank=True)),
('date_modified', models.DateTimeField(auto_now=True, verbose_name='Bearbeitet')),
('author', models.ForeignKey(verbose_name='Autor', to=settings.AUTH_USER_MODEL)),
('content_en', models.TextField(
verbose_name=b'Content', blank=True)),
('image', models.ImageField(
upload_to=b'news/',
null=True, verbose_name='Bild',
blank=True)),
('slug', models.SlugField(
unique_for_month=b'date_created', verbose_name='Slug')),
('status',
models.SmallIntegerField(
default=1, verbose_name='Status',
choices=[
(-1, 'Zur\xfcckgewiesen'),
(0, 'Wartend...'),
(1, 'Ver\xf6ffentlicht')])),
('date_created', models.DateTimeField(
verbose_name='Erstellt', blank=True)),
('date_modified', models.DateTimeField(
auto_now=True, verbose_name='Bearbeitet')),
('author', models.ForeignKey(
verbose_name='Autor', to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ('-date_created',),
@@ -37,12 +55,22 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='Category',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name_de', models.CharField(max_length=80, verbose_name='Name')),
('name_en', models.CharField(max_length=80, verbose_name='Name', blank=True)),
('description_de', models.TextField(verbose_name='Beschreibung')),
('description_en', models.TextField(verbose_name='Beschreibung', blank=True)),
('image', models.ImageField(upload_to=b'news/categories/', null=True, verbose_name='Bild', blank=True)),
('id', models.AutoField(
verbose_name='ID',
serialize=False, auto_created=True,
primary_key=True)),
('name_de',
models.CharField(max_length=80, verbose_name='Name')),
('name_en', models.CharField(
max_length=80, verbose_name='Name', blank=True)),
('description_de',
models.TextField(verbose_name='Beschreibung')),
('description_en', models.TextField(
verbose_name='Beschreibung', blank=True)),
('image', models.ImageField(
upload_to=b'news/categories/',
null=True, verbose_name='Bild',
blank=True)),
('slug', models.SlugField(unique=True, verbose_name='Slug')),
],
options={
@@ -54,23 +82,57 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='Page',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('menu_name_de', models.CharField(help_text='Ein kurzer Name f\xfcr den Men\xfceintrag', max_length=255, verbose_name=b'Men\xc3\xbc Name')),
('menu_name_en', models.CharField(help_text='Ein kurzer Name f\xfcr den Men\xfceintrag', max_length=255, verbose_name=b'Menu Name', blank=True)),
('title_de', models.CharField(help_text='Der Titel erscheint im HTML Header', max_length=255, verbose_name=b'Titel')),
('title_en', models.CharField(help_text='Der Titel erscheint im HTML Header', max_length=255, verbose_name=b'Title', blank=True)),
('id', models.AutoField(
verbose_name='ID',
serialize=False, auto_created=True,
primary_key=True)),
('menu_name_de', models.CharField(
help_text='Ein kurzer Name f\xfcr den Men\xfceintrag',
max_length=255, verbose_name=b'Men\xc3\xbc Name')),
('menu_name_en', models.CharField(
help_text='Ein kurzer Name f\xfcr den Men\xfceintrag',
max_length=255, verbose_name=b'Menu Name', blank=True)),
('title_de', models.CharField(
help_text='Der Titel erscheint im HTML Header',
max_length=255, verbose_name=b'Titel')),
('title_en', models.CharField(
help_text='Der Titel erscheint im HTML Header',
max_length=255, verbose_name=b'Title', blank=True)),
('slug', models.SlugField(verbose_name='Slug')),
('path', models.CharField(verbose_name='Pfad', unique=True, max_length=100, editable=False, db_index=True)),
('position', models.PositiveSmallIntegerField(null=True, verbose_name='Position', blank=True)),
('status', models.SmallIntegerField(default=0, verbose_name='Status', choices=[(-1, 'Zur\xfcckgewiesen'), (0, 'Wartend...'), (1, 'Ver\xf6ffentlicht')])),
('content_type', models.IntegerField(choices=[(0, 'Django View'), (1, 'HTML'), (2, 'PDF')])),
('content_de', models.TextField(verbose_name=b'Inhalt', blank=True)),
('content_en', models.TextField(verbose_name=b'Content', blank=True)),
('enable_comments', models.BooleanField(default=True, verbose_name='Kommentare m\xf6glich')),
('template', models.CharField(default=b'content/page.html', max_length=100, verbose_name='Vorlage')),
('pdf_de', models.FileField(null=True, upload_to=b'pdf/de/', blank=True)),
('pdf_en', models.FileField(null=True, upload_to=b'pdf/en/', blank=True)),
('parent', models.ForeignKey(related_name='subpages', on_delete=django.db.models.deletion.SET_NULL, blank=True, to='content.Page', null=True)),
('path', models.CharField(
verbose_name='Pfad', unique=True,
max_length=100, editable=False,
db_index=True)),
('position', models.PositiveSmallIntegerField(
null=True, verbose_name='Position', blank=True)),
('status',
models.SmallIntegerField(
default=0, verbose_name='Status',
choices=[
(-1, 'Zur\xfcckgewiesen'),
(0, 'Wartend...'),
(1, 'Ver\xf6ffentlicht')])),
('content_type', models.IntegerField(choices=[
(0, 'Django View'), (1, 'HTML'), (2, 'PDF')])),
('content_de',
models.TextField(verbose_name=b'Inhalt', blank=True)),
('content_en', models.TextField(
verbose_name=b'Content', blank=True)),
('enable_comments', models.BooleanField(
default=True, verbose_name='Kommentare m\xf6glich')),
('template', models.CharField(
default=b'content/page.html',
max_length=100,
verbose_name='Vorlage')),
('pdf_de', models.FileField(
null=True, upload_to=b'pdf/de/', blank=True)),
('pdf_en', models.FileField(
null=True, upload_to=b'pdf/en/', blank=True)),
('parent', models.ForeignKey(
related_name='subpages',
on_delete=django.db.models.deletion.SET_NULL,
blank=True, to='content.Page',
null=True)),
],
options={
'ordering': ['parent__id', 'position'],
@@ -81,7 +143,8 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='article',
name='category',
field=models.ForeignKey(verbose_name='Kategorie', to='content.Category'),
field=models.ForeignKey(
verbose_name='Kategorie', to='content.Category'),
),
migrations.AlterUniqueTogether(
name='page',

View File

@@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import ckeditor.fields
class Migration(migrations.Migration):
dependencies = [
('content', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='article',
name='content_de',
field=ckeditor.fields.RichTextField(verbose_name='Inhalt'),
),
migrations.AlterField(
model_name='article',
name='content_en',
field=ckeditor.fields.RichTextField(
verbose_name=b'Content', blank=True),
),
migrations.AlterField(
model_name='page',
name='content_de',
field=ckeditor.fields.RichTextField(
verbose_name=b'Inhalt', blank=True),
),
migrations.AlterField(
model_name='page',
name='content_en',
field=ckeditor.fields.RichTextField(
verbose_name=b'Content', blank=True),
),
]

View File

@@ -11,9 +11,6 @@ from django.utils.safestring import mark_safe
from django.utils.translation import get_language, ugettext as _
from django.core.exceptions import ValidationError
from ckeditor.fields import RichTextField
from kasu.image_models import ImageModel
from utils import STATUS_CHOICES, STATUS_WAITING, STATUS_PUBLISHED, \
cleaner
@@ -42,11 +39,15 @@ def get_upload_path(instance, filename):
class ArticleManager(models.Manager):
def get_queryset(self):
return super(ArticleManager, self).get_queryset().select_related('author', 'category')
def published(self):
return self.filter(status=STATUS_PUBLISHED, date_created__lte=now())
class Article(ImageModel):
class Article(models.Model):
headline_de = models.CharField(_('Headline'), max_length=255)
headline_en = models.CharField('Headline', max_length=255, blank=True)
content_de = RichTextField(_('Content'))
@@ -80,11 +81,11 @@ class Article(ImageModel):
return self.headline
@property
def posting_image(self):
def get_image(self):
if self.image:
return self.article
return self.image
else:
return self.category.article
return self.category.image
def get_absolute_url(self):
kwargs = {
@@ -219,7 +220,7 @@ class Page(models.Model):
verbose_name_plural = _('Pages')
class Category(ImageModel):
class Category(models.Model):
name_de = models.CharField(_('Name'), max_length=80)
name_en = models.CharField(_('Name'), max_length=80, blank=True)
description_de = models.TextField(_('Description'))

View File

@@ -1,21 +1,22 @@
{% extends "base.html" %}
{% load i18n comments %}
{% load i18n comments thumbnail %}
{% block title %}
{% trans 'Article Archive' %}
{% if active_category %} - {{active_category.name}}{% endif %}
{% if month %}{{ month|date:'F Y' }}</h2>{% elif year %}{{year}}{% endif %}
{% if month %}{{ month|date:'F Y' }}{% elif year %}{{year}}{% endif %}
{% endblock %}
{% block meta_title %}
{% trans 'Article Archive' %}
{% if active_category %} - {{active_category.name}}{% endif %}
{% if month %}{{ month|date:'F Y' }}</h2>{% elif year %}{{year}}{% endif %}
{% endblock %}
{% block jumbotron_background %}{% spaceless %}
{% if active_category %}
{{ active_category.image.url }}
{% else %}
{{STATIC_URL}}img/teaser/{{current_top_page.slug}}.jpg
{% endif %}
{% endspaceless %}{% endblock %}
{% block jumbotron_background %}{% if active_category %}{{ active_category.image.url }}{% else %}{{STATIC_URL}}img/teaser/{{current_top_page.slug}}.jpg{% endif %}{% endblock %}
{% block teaser %}<h1>
{% block teaser %}
<h1>
{% trans 'Article Archive' %}
{% if active_category %} - {{active_category.name}}{% endif %}
{% if month %}{{ month|date:'F Y' }}{% elif year %}{{year}}{% endif %}
@@ -67,7 +68,7 @@
<li><span class="fa fa-user" title="{% trans 'by' %}"></span> {{ article.author }}</li>
<li><span class="fa fa-comments" title="{% trans 'comments' %}"></span> <a href="{{article.get_absolute_url}}#comments" >{{comment_count}} {% trans "comments" %}</a></li>
</ul>
<a href="{{article.get_absolute_url}}"><img src="{{article.posting_image.url}}" alt="{{article.category}}:" class="posting_image" width="200" height="120"/></a>
<a href="{{article.get_absolute_url}}"><img src="{{article.get_image|thumbnail_url:'article'}}" alt="{{article.category}}:" class="posting_image" width="200" height="120"/></a>
{{article.content|truncatewords_html:50}}
<p class="more_link"><a href="{{article.get_absolute_url}}" class="button">{% trans "Read More"%} <span class="fa fa-arrow-right"></span></a></p>
</article>

View File

@@ -1,5 +1,5 @@
{% extends "base.html" %}
{% load i18n comments %}
{% load i18n comments thumbnail %}
{% block title %}{{ article.headline }}{% endblock %}
@@ -9,9 +9,9 @@
<meta property="og:type" content="article" />
<meta property="og:title" content="{{ article.headline|force_escape }}" />
<meta property="og:url" content="http://www.kasu.at{{ article.get_absolute_url }}" />
<meta property="og:image" content="http://www.kasu.at{{article.posting_image.url}}" />
<meta property="og:image" content="http://www.kasu.at{{article.get_image|thumbnail_url:'article'}}" />
<meta property="og:description" content="{{article.content|striptags|truncatewords:25|force_escape}}" />
<link rel="image_src" type="image/jpeg" href="{{article.posting_image.url}}" />
<link rel="image_src" type="image/jpeg" href="{{article.get_image|thumbnail_url:'article'}}" />
{% endblock %}
{% block itemscope %}itemscope itemtype="http://schema.org/Article"{% endblock %}
@@ -21,7 +21,7 @@
<div id="teaser_text">
<ul class="info">
<li><span class="fa fa-user"></span> <strong>{% trans 'Author' %}:</strong> <a href="{% url 'membership-details' article.author %}" itemprop="author">{{article.author}}</a></li>
<li><span class="fa fa-calendar-o"></span> <strong>{% trans 'Created on' %}: </strong><time datetime="{{article.date_created|date:'Y-m-d H:i'}}">{{ article.date_created|date }}</time></li>
<li><span class="fa fa-calendar-o"></span> <strong>{% trans 'Created on' %}: </strong><time datetime="{{article.date_created|date:'Y-m-d H:i'}}">{{ article.date_created|date:'DATE_FORMAT' }}</time></li>
<li><span class="fa fa-tag"></span> <strong>{% trans "Category"%}: </strong><a href="{{ article.category.get_absolute_url }}" itemprop="articleSection">{{article.category.name}}</a></li>
</ul>
</div>
@@ -29,7 +29,7 @@
{% block maincontent %}
<div itemprop="articleBody" class="grid_12">
<img alt="{{article.category.name}}" src="{{article.posting_image.url}}" class="posting_image" itemprop="image"/>
<img alt="{{article.category.name}}" src="{{article.get_image|thumbnail_url:'article'}}" class="posting_image" itemprop="image"/>
{{ article.content }}
</div>
<p class="right">

View File

@@ -13,6 +13,7 @@ register = template.Library()
class FieldSetNode(template.Node):
def __init__(self, form_variable, variable_name, fields):
self.fields = fields
self.variable_name = variable_name

View File

@@ -9,6 +9,7 @@ from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.

View File

@@ -8,15 +8,16 @@ from django.utils.translation import ugettext as _
from django.views import generic
from . import models, forms
from aggregator.models import Feed
from events.models import Photo
from utils.mixins import PermissionRequiredMixin
class ArticleArchiveMixin(object):
def get_category(self, queryset):
try:
self.category = models.Category.objects.get(slug=self.kwargs['category'])
self.category = models.Category.objects.get(
slug=self.kwargs['category'])
return queryset.filter(category=self.category)
except models.Category.DoesNotExist:
raise Http404(_("This Category does not exist."))
@@ -28,7 +29,6 @@ class ArticleArchiveMixin(object):
context = super(ArticleArchiveMixin, self).get_context_data(**kwargs)
context['categories'] = models.Category.objects.all()
context['active_category'] = self.category
context['feeds'] = Feed.objects.active()
return context
@@ -99,6 +99,7 @@ class ArticleForm(PermissionRequiredMixin, generic.UpdateView):
class ImageList(generic.View):
# noinspection PyMethodMayBeStatic
def get(self, kwargs):
image_list = []
response = HttpResponse(content_type='text/javascript')
@@ -146,6 +147,7 @@ class PageEditForm(PermissionRequiredMixin, generic.UpdateView):
class PageHtml(generic.DetailView):
def get_object(self, queryset=None):
try:
return models.Page.objects.get(path=self.kwargs['path'],
@@ -160,6 +162,7 @@ class PageHtml(generic.DetailView):
class PagePdf(generic.DeleteView):
def get_object(self, queryset=None):
try:
return models.Page.objects.get(path=self.kwargs['path'],
@@ -183,6 +186,7 @@ class PagePdf(generic.DeleteView):
class PageList(generic.View):
# noinspection PyMethodMayBeStatic
def get(self, kwargs):
response = HttpResponse(content_type='text/javascript')
response.write('var tinyMCELinkList = new Array(')
@@ -212,7 +216,7 @@ class StartPage(generic.TemplateView):
context = {
'title': page.title,
'content': page.content,
'random_photo': random_photo.callout,
'random_photo': random_photo,
'recent_article_list': models.Article.objects.published()[:3],
'recent_comment_list': recent_comment_list,
}

View File

@@ -5,7 +5,6 @@ Created on 19.09.2011
"""
# import stuff we need from django
from django.contrib import admin
from imagekit.admin import AdminThumbnail
from django.utils.translation import gettext as _
from events.models import Event, Photo, Location
@@ -19,7 +18,7 @@ class EventInline(admin.TabularInline):
class EventAdmin(admin.ModelAdmin):
list_display = ('name', 'start', 'end', 'location',)
list_editable = ('start', 'end', 'location',)
list_editable = ('start', 'end', 'location')
readonly_fields = ('event_series',)
date_hierarchy = 'start'
search_fields = ('name', 'description')
@@ -32,12 +31,11 @@ class LocationAdmin(admin.ModelAdmin):
class PhotoAdmin(admin.ModelAdmin):
admin_thumbnail = AdminThumbnail(image_field='thumbnail')
# admin_thumbnail = AdminThumbnail(image_field='thumbnail')
fields = ('image', 'event', 'name', 'description',
('anchor_horizontal', 'anchor_vertical'),
('photographer', 'created_date'))
list_filter = ('event', 'on_startpage',)
list_display = ('admin_thumbnail', 'image', 'name', 'event',
list_display = ('image', 'image', 'name', 'event',
'photographer', 'on_startpage')
list_display_links = ('image',)
list_editable = ('on_startpage', 'name', 'event', 'photographer')

View File

@@ -4,12 +4,30 @@ Created on 30.09.2011
@author: christian
"""
from . import models
from django.core.cache import cache
from .models import Event
def upcoming_events(request):
current_event = cache.get('current_event', False)
next_event = cache.get('next_event', False)
upcoming_events = cache.get('upcoming_events', False)
if current_event == False:
current_event = Event.objects.current_event()
cache.set('current_event', current_event, 360)
if next_event == False:
next_event = Event.objects.next_event()
cache.set('next_event', next_event, 360)
if not upcoming_events and current_event:
upcoming_events = Event.objects.upcoming(limit=3)
cache.set('upcoming_events', upcoming_events, 360)
elif not upcoming_events:
upcoming_events = Event.objects.upcoming()[1:4]
cache.set('upcoming_events', upcoming_events, 360)
return {
'current_event': models.Event.objects.current_event(),
'next_event': models.Event.objects.next_event(),
'upcoming_events': models.Event.objects.upcoming(),
'current_event': current_event,
'next_event': next_event,
'upcoming_events': upcoming_events
}

View File

@@ -38,7 +38,6 @@ class EditPhotoForm(forms.ModelForm):
class Meta(object):
model = models.Photo
fields = ('event', 'name', 'description', 'photographer',
'anchor_horizontal', 'anchor_vertical',
'created_date', 'on_startpage')
@@ -59,4 +58,5 @@ class EventForm(forms.ModelForm):
model = models.Event
exclude = ('event_count', 'event_series', )
EventSeriesFormset = forms.inlineformset_factory(models.Event, models.Event, fields=('start', 'end'), form=EventForm)
EventSeriesFormset = forms.inlineformset_factory(
models.Event, models.Event, fields=('start', 'end'), form=EventForm)

File diff suppressed because one or more lines are too long

View File

@@ -18,11 +18,13 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='event',
name='mahjong_season',
field=models.PositiveSmallIntegerField(null=True, verbose_name='Mahjong Season', blank=True),
field=models.PositiveSmallIntegerField(
null=True, verbose_name='Mahjong Season', blank=True),
),
migrations.AddField(
model_name='event',
name='mahjong_tournament',
field=models.BooleanField(default=False, help_text='Diese Veranstaltung ist ein Turnier, es gelten andere Regeln f\xfcr das Kyu Ranking.', verbose_name='Mahjong Tournament'),
field=models.BooleanField(
default=False, help_text='Diese Veranstaltung ist ein Turnier, es gelten andere Regeln f\xfcr das Kyu Ranking.', verbose_name='Mahjong Tournament'),
),
]

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('events', '0002_auto_20150818_2139'),
]
operations = [
migrations.AlterField(
model_name='event',
name='mahjong_tournament',
field=models.BooleanField(
default=False, help_text='Diese Veranstaltung ist ein Turnier, es gelten andere Regeln f\xfcr das Kyu Ranking.', verbose_name='Mahjong Turnier'),
),
]

View File

@@ -0,0 +1,91 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import ckeditor.fields
import events.models
import easy_thumbnails.fields
import django.db.models.deletion
import utils
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('events', '0003_auto_20150823_2232'),
]
operations = [
migrations.CreateModel(
name='Photo',
fields=[
('id', models.AutoField(verbose_name='ID',
serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=100,
verbose_name='Name', blank=True)),
('image', easy_thumbnails.fields.ThumbnailerImageField(
upload_to=events.models.get_upload_path, storage=utils.OverwriteStorage(), verbose_name='Bild')),
('description', models.TextField(max_length=300,
verbose_name='Beschreibung', blank=True)),
('on_startpage', models.BooleanField(default=False,
help_text='Display this Photo on the Startpage Teaser', verbose_name='Startpage')),
('created_date', models.DateTimeField(verbose_name='Published on')),
('views', models.PositiveIntegerField(default=0,
verbose_name='Number of views', editable=False)),
],
options={
'ordering': ['created_date'],
'db_table': 'events_photo',
'verbose_name': 'Veranstaltungsbild',
'verbose_name_plural': 'Event Images',
'get_latest_by': 'created_date',
},
),
migrations.AlterModelOptions(
name='event',
options={'ordering': (
'start', 'end'), 'verbose_name': 'Termin', 'verbose_name_plural': 'Termine'},
),
migrations.AlterField(
model_name='event',
name='description',
field=ckeditor.fields.RichTextField(
verbose_name='Beschreibung', blank=True),
),
migrations.AlterField(
model_name='event',
name='event_series',
field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, blank=True, to='events.Event',
help_text='Wenn dieser Termin zu einer Veranstaltungsreihe geh\xf6rt werden Ort, Beschreibung, Bild und Homepage von dem hier angegebenen Event \xfcbernommen.', null=True, verbose_name='Veranstaltungsreihen'),
),
migrations.AlterField(
model_name='event',
name='image',
field=easy_thumbnails.fields.ThumbnailerImageField(storage=utils.OverwriteStorage(
), upload_to=events.models.get_upload_path, null=True, verbose_name='Bild', blank=True),
),
migrations.AlterField(
model_name='location',
name='description',
field=ckeditor.fields.RichTextField(
verbose_name='Beschreibung', blank=True),
),
migrations.AlterField(
model_name='location',
name='image',
field=easy_thumbnails.fields.ThumbnailerImageField(storage=utils.OverwriteStorage(
), upload_to=events.models.get_upload_path, null=True, verbose_name='Bild', blank=True),
),
migrations.AddField(
model_name='photo',
name='event',
field=models.ForeignKey(to='events.Event'),
),
migrations.AddField(
model_name='photo',
name='photographer',
field=models.ForeignKey(to=settings.AUTH_USER_MODEL),
),
]

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('events', '0004_auto_20150901_2204'),
]
operations = [
migrations.AlterField(
model_name='photo',
name='on_startpage',
field=models.BooleanField(
default=False, help_text='Display this Photo on the Startpage Teaser', db_index=True, verbose_name='Startpage'),
),
]

View File

@@ -1,14 +1,17 @@
# -'- Encoding: utf-8 -*-
import os
from django.conf import settings
from django.core.urlresolvers import reverse
from django.db import models
from django.db.models import Q
from django.template.defaultfilters import slugify
from django.utils.timezone import now
from django.utils.translation import ugettext as _
from ckeditor.fields import RichTextField
from easy_thumbnails.fields import ThumbnailerImageField
from utils import COUNTRIES, OverwriteStorage
from gallery.models import Photo
from kasu import image_models
def get_upload_path(instance, filename):
@@ -22,63 +25,87 @@ def get_upload_path(instance, filename):
@param filename: The filename of the uploaded image.
@type filename: String
"""
extension = filename[filename.rfind('.') + 1:]
filename, extension = os.path.splitext(filename.lower())
if isinstance(instance, Event):
if instance.id:
return "events/%s.%s" % (instance.id, extension)
else:
return "events/%s.%s" % (slugify(instance.name), extension)
return "events/{date:%Y-%m-%d}/{name}{ext}".format(
date=instance.start,
name=slugify(instance.name),
ext=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)
return "events/locations/{name}{ext}".format(
name=slugify(instance.name),
ext=extension
)
elif isinstance(instance, Photo):
return "events/%s/%s" % (instance.event.id, filename)
return "events/{date:%Y-%m-%d}/{name}{ext}".format(
date=instance.event.start,
name=filename,
ext=extension
)
class EventManager(models.Manager):
def get_queryset(self):
return super(EventManager, self).get_queryset().select_related('location')
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:
except IndexError:
return None
def next_event(self):
try:
return self.filter(start__gt=now()).order_by('start', 'end')[0]
except:
except IndexError:
return None
def archive(self):
return self.filter(start__lt=now())
def upcoming(self, limit=3):
def latest_events(self, num=3):
return self.filter(start__lt=now()).order_by('-start', '-end')[:num]
def upcoming(self, limit=None):
result = self.filter(start__gt=now()).order_by('start', 'end')
if limit:
return result[1:(limit + 1)]
return result[0:limit]
else:
return result
class Event(image_models.ImageModel):
class Event(models.Model):
name = models.CharField(_('Name'), max_length=255)
description = models.TextField(_("Description"), blank=True)
description = RichTextField(_("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)
mahjong_tournament = models.BooleanField(_('Mahjong Tournament'), default=False,
image = ThumbnailerImageField(
_("Image"),
upload_to=get_upload_path,
storage=OverwriteStorage(),
blank=True,
null=True
)
mahjong_tournament = models.BooleanField(
_('Mahjong Tournament'),
default=False,
help_text=_(u'This event is a tournament, different rules apply for \
the kyu ranking.'))
mahjong_season = models.PositiveSmallIntegerField(_('Mahjong Season'), blank=True, null=True)
the kyu ranking.')
)
mahjong_season = models.PositiveSmallIntegerField(
_('Mahjong Season'),
blank=True,
null=True
)
photo_count = models.PositiveIntegerField(default=0, editable=False)
event_series = models.ForeignKey('Event', blank=True, null=True,
on_delete=models.SET_NULL, editable=False,
on_delete=models.SET_NULL, editable=True,
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 \
@@ -89,7 +116,7 @@ class Event(image_models.ImageModel):
class Meta(object):
verbose_name = _('Event')
verbose_name_plural = _('Events')
ordering = ('-start', '-end',)
ordering = ('start', 'end',)
def __unicode__(self):
try:
@@ -122,23 +149,13 @@ class Event(image_models.ImageModel):
}
return reverse('event-form', kwargs=kwargs)
def get_callout(self):
def get_image(self):
if self.image:
return self.callout
elif self.photo_set.count():
return self.photo_set.all().order_by('?')[0].callout
return self.image
elif self.photo_count:
return self.photo_set.all().order_by('?')[0].image
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
return self.location.image
else:
return None
@@ -159,11 +176,16 @@ class Event(image_models.ImageModel):
hanchan.save()
class Location(image_models.ImageModel):
class Location(models.Model):
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)
description = RichTextField(_("Description"), blank=True)
image = ThumbnailerImageField(
_("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)
@@ -183,7 +205,111 @@ class Location(image_models.ImageModel):
return ','.join(address)
models.signals.post_save.connect(image_models.regenerate_image_cache,
sender=Event)
models.signals.post_save.connect(image_models.regenerate_image_cache,
sender=Location)
class PhotoManager(models.Manager):
def get_random(self, startpage=True):
if startpage:
queryset = self.filter(on_startpage=True)
else:
queryset = self.all().order_by('?')[0]
try:
return queryset.order_by('?')[0]
except IndexError:
return Photo()
class Photo(models.Model):
name = models.CharField(_("Name"), max_length=100, blank=True)
image = ThumbnailerImageField(_("Image"), upload_to=get_upload_path,
storage=OverwriteStorage())
event = models.ForeignKey('events.Event')
description = models.TextField(
_("Description"),
max_length=300,
blank=True
)
photographer = models.ForeignKey(settings.AUTH_USER_MODEL)
on_startpage = models.BooleanField(
_("Startpage"),
default=False,
db_index=True,
help_text=_('Display this Photo on the Startpage Teaser')
)
created_date = models.DateTimeField(_("Published on"))
views = models.PositiveIntegerField(
_("Number of views"),
editable=False,
default=0
)
objects = PhotoManager()
metadata = None
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')
def __unicode__(self):
return os.path.basename(self.image.name)
def rotate(self, rotate):
# TODO: Eine vernüftigte Methode ohne viele Abhängigkeiten finden um
# die Bilder bei Bedarf zu drehen.
if rotate == 'clockwise':
pass
elif rotate == 'counter-clockwise':
pass
self.save()
def save(self, **kwargs):
super(Photo, self).save(**kwargs)
self.event.save()
def get_absolute_url(self):
return reverse(
'event-photo',
kwargs={'event': self.event.id, 'pk': self.id}
)
@property
def next_photo(self):
queryset = Photo.objects.filter(created_date__gt=self.created_date)
queryset = queryset.order_by('created_date')
try:
if self.event.event_series:
return queryset.filter(
Q(event=self.event) |
Q(event=self.event.event_series) |
Q(event__event_series=self.event.event_series)
)[0]
else:
return queryset.filter(
Q(event=self.event) |
Q(event__event_series=self.event)
)[0]
except IndexError:
return None
return self.get_next_by_created_date(event=self.event)
@property
def previous_photo(self):
queryset = Photo.objects.filter(created_date__lt=self.created_date)
queryset = queryset.order_by('-created_date')
try:
if self.event.event_series:
return queryset.filter(
Q(event=self.event) |
Q(event=self.event.event_series) |
Q(event__event_series=self.event.event_series)
)[0]
else:
return queryset.filter(
Q(event=self.event) |
Q(event__event_series=self.event)
)[0]
except IndexError:
return None
return self.get_previous_by_created_date(event=self.event)

View File

@@ -0,0 +1,11 @@
/* mousetrap v1.5.3 craig.is/killing/mice */
(function(C,r,g){function t(a,b,h){a.addEventListener?a.addEventListener(b,h,!1):a.attachEvent("on"+b,h)}function x(a){if("keypress"==a.type){var b=String.fromCharCode(a.which);a.shiftKey||(b=b.toLowerCase());return b}return l[a.which]?l[a.which]:p[a.which]?p[a.which]:String.fromCharCode(a.which).toLowerCase()}function D(a){var b=[];a.shiftKey&&b.push("shift");a.altKey&&b.push("alt");a.ctrlKey&&b.push("ctrl");a.metaKey&&b.push("meta");return b}function u(a){return"shift"==a||"ctrl"==a||"alt"==a||
"meta"==a}function y(a,b){var h,c,e,g=[];h=a;"+"===h?h=["+"]:(h=h.replace(/\+{2}/g,"+plus"),h=h.split("+"));for(e=0;e<h.length;++e)c=h[e],z[c]&&(c=z[c]),b&&"keypress"!=b&&A[c]&&(c=A[c],g.push("shift")),u(c)&&g.push(c);h=c;e=b;if(!e){if(!k){k={};for(var m in l)95<m&&112>m||l.hasOwnProperty(m)&&(k[l[m]]=m)}e=k[h]?"keydown":"keypress"}"keypress"==e&&g.length&&(e="keydown");return{key:c,modifiers:g,action:e}}function B(a,b){return null===a||a===r?!1:a===b?!0:B(a.parentNode,b)}function c(a){function b(a){a=
a||{};var b=!1,n;for(n in q)a[n]?b=!0:q[n]=0;b||(v=!1)}function h(a,b,n,f,c,h){var g,e,l=[],m=n.type;if(!d._callbacks[a])return[];"keyup"==m&&u(a)&&(b=[a]);for(g=0;g<d._callbacks[a].length;++g)if(e=d._callbacks[a][g],(f||!e.seq||q[e.seq]==e.level)&&m==e.action){var k;(k="keypress"==m&&!n.metaKey&&!n.ctrlKey)||(k=e.modifiers,k=b.sort().join(",")===k.sort().join(","));k&&(k=f&&e.seq==f&&e.level==h,(!f&&e.combo==c||k)&&d._callbacks[a].splice(g,1),l.push(e))}return l}function g(a,b,n,f){d.stopCallback(b,
b.target||b.srcElement,n,f)||!1!==a(b,n)||(b.preventDefault?b.preventDefault():b.returnValue=!1,b.stopPropagation?b.stopPropagation():b.cancelBubble=!0)}function e(a){"number"!==typeof a.which&&(a.which=a.keyCode);var b=x(a);b&&("keyup"==a.type&&w===b?w=!1:d.handleKey(b,D(a),a))}function l(a,c,n,f){function e(c){return function(){v=c;++q[a];clearTimeout(k);k=setTimeout(b,1E3)}}function h(c){g(n,c,a);"keyup"!==f&&(w=x(c));setTimeout(b,10)}for(var d=q[a]=0;d<c.length;++d){var p=d+1===c.length?h:e(f||
y(c[d+1]).action);m(c[d],p,f,a,d)}}function m(a,b,c,f,e){d._directMap[a+":"+c]=b;a=a.replace(/\s+/g," ");var g=a.split(" ");1<g.length?l(a,g,b,c):(c=y(a,c),d._callbacks[c.key]=d._callbacks[c.key]||[],h(c.key,c.modifiers,{type:c.action},f,a,e),d._callbacks[c.key][f?"unshift":"push"]({callback:b,modifiers:c.modifiers,action:c.action,seq:f,level:e,combo:a}))}var d=this;a=a||r;if(!(d instanceof c))return new c(a);d.target=a;d._callbacks={};d._directMap={};var q={},k,w=!1,p=!1,v=!1;d._handleKey=function(a,
c,e){var f=h(a,c,e),d;c={};var k=0,l=!1;for(d=0;d<f.length;++d)f[d].seq&&(k=Math.max(k,f[d].level));for(d=0;d<f.length;++d)f[d].seq?f[d].level==k&&(l=!0,c[f[d].seq]=1,g(f[d].callback,e,f[d].combo,f[d].seq)):l||g(f[d].callback,e,f[d].combo);f="keypress"==e.type&&p;e.type!=v||u(a)||f||b(c);p=l&&"keydown"==e.type};d._bindMultiple=function(a,b,c){for(var d=0;d<a.length;++d)m(a[d],b,c)};t(a,"keypress",e);t(a,"keydown",e);t(a,"keyup",e)}var l={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",18:"alt",
20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},p={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},A={"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},z={option:"alt",command:"meta","return":"enter",
escape:"esc",plus:"+",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},k;for(g=1;20>g;++g)l[111+g]="f"+g;for(g=0;9>=g;++g)l[g+96]=g;c.prototype.bind=function(a,b,c){a=a instanceof Array?a:[a];this._bindMultiple.call(this,a,b,c);return this};c.prototype.unbind=function(a,b){return this.bind.call(this,a,function(){},b)};c.prototype.trigger=function(a,b){if(this._directMap[a+":"+b])this._directMap[a+":"+b]({},a);return this};c.prototype.reset=function(){this._callbacks={};this._directMap=
{};return this};c.prototype.stopCallback=function(a,b){return-1<(" "+b.className+" ").indexOf(" mousetrap ")||B(b,this.target)?!1:"INPUT"==b.tagName||"SELECT"==b.tagName||"TEXTAREA"==b.tagName||b.isContentEditable};c.prototype.handleKey=function(){return this._handleKey.apply(this,arguments)};c.init=function(){var a=c(r),b;for(b in a)"_"!==b.charAt(0)&&(c[b]=function(b){return function(){return a[b].apply(a,arguments)}}(b))};c.init();C.Mousetrap=c;"undefined"!==typeof module&&module.exports&&(module.exports=
c);"function"===typeof define&&define.amd&&define(function(){return c})})(window,document);

View File

@@ -1,5 +1,5 @@
{% extends "events/page.html" %}
{% load i18n comments%}
{% load i18n comments thumbnail %}
{% block title %}
{% trans 'Event Archive' %} {% if month %}{{ month|date:'F Y' }} {% else %}{% if year %}{{year}}{% endif %}{% endif %}
@@ -32,14 +32,19 @@
<h3 class="grid_12">{{ month.grouper }}</h3>
{% for event in month.list %}
{% get_comment_count for event as comment_count %}
<a href="{{ event.get_absolute_url }}" class="grid_2"><img src="{{ event.get_thumbnail.url }}"
alt="{% trans 'Event Image' %}"
class="thumbnail"/></a>
<div class="grid_4">
<h4><a href="{{ event.get_absolute_url }}">{{ event.name }}</a></h4>
<p><span class="fa fa-calendar-o" title="{% trans 'Start' %}"></span>
{{ event.start|date }}
<div class="grid_6">
<a href="{{ event.get_absolute_url }}" class="thumbnail"><img src="{{ event.get_image|thumbnail_url:'thumbnail' }}"
alt="{% trans 'Event Image' %}" width="140" height="140"/></a>
<h4><a href="{{ event.get_absolute_url }}">{{ event.name }}</a></h4>
<p>
<span class="fa fa-calendar-o" title="{% trans 'Date' %}" aria-label="{% trans 'Date' %}"></span>
<time datetime="{{event.start|date:'c'}}">
{{ event.start|date:'D' }}
{{ event.start|date:'SHORT_DATE_FORMAT' }} {{hanchan.start|time:'H:i'}}
</time>
<span class="fa fa-clock-o" title="{% trans 'Time' %}" aria-label="{% trans 'Time' %}"></span>
{% if event.end %}
{% trans "from" %} {{ event.start|time:'H:i' }} {% trans "to" %} {{ event.end|time:'H:i' }}
{% else %}
@@ -59,7 +64,6 @@
<p class="right"><a href="{{ event.get_edit_url }}" class="button"><span class="fa fa-pencil"></span></a></p>
{% endif %}
</div>
{% if forloop.counter|divisibleby:2 %}<br class="clear"/>{% endif %}
{% endfor %}
{% endfor %}
{% endblock %}

View File

@@ -1,5 +1,5 @@
{% extends "events/page.html" %}
{% load i18n django_markdown comments %}
{% load i18n comments thumbnail %}
{% block title %}{{ event.name }}{% endblock %}
@@ -8,19 +8,19 @@
<meta property="og:title" content="{{event.name}}" />
<meta property="og:url" content="http://www.kasu.at{{event.get_absolute_url}}" />
<meta property="og:image" content="http://www.kasu.at{{ event.get_thumbnail.url }}" />
{% if event.description %}<meta property="og:description" content="{{event.description}}" />{% endif %}
{% if event.description %}<meta property="og:description" content="{{event.description|striptags}}" />{% endif %}
{% endblock %}
{% block extra_head %}
<script type="text/javascript" src="https://maps.google.com/maps/api/js?sensor=false"></script>
{% endblock %}
{% block jumbotron_background %} {{ event.get_callout.url }} {% endblock %}
{% block jumbotron_background %} {{ event.get_image|thumbnail_url:'callout' }} {% endblock %}
{% block teaser %}
<h1>{{event.name}}</h1>
{% if event.description %}
<div id="teaser_text">{{event.description|markdown|truncatewords_html:75}}</div>
<div id="teaser_text">{{event.description|truncatewords_html:75|safe}}</div>
{% endif %}
{% endblock %}
@@ -48,10 +48,8 @@
<li><a href="{% url 'event-photo-list' event.pk %}"><span class="fa fa-camera-retro"></span> {{ event.photo_count }} {% trans 'Photos' %}</a></li>
<li><a href="{% url 'event-hanchan-list' event.pk %}" ><span class="fa fa-table"></span> {{ event.hanchan_set.count }} {% trans "Hanchans" %}</a></li>
<li><a href="{% url 'maistar-game-list' event.pk %}" ><span class="fa fa-glass"></span> {{ event.maistargame_set.count }} {% trans "Mai-Star Games" %}</a></li>
{% if event.mahjong_tournament %}
<li><a href="{% url 'event-ranking' event.id %}"><span class="fa fa-trophy"></span> {% trans "Tournament Ranking" %}</a></li>
{% endif %}
<li><a href="{% url 'event-ranking' event.id %}"><span
class="fa fa-trophy"></span> {% trans "Event Ranking" %}</a></li>
</ul>
{% endblock %}
@@ -81,16 +79,30 @@
<div class="grid_12">
{% if event.description %}
{{event.description|markdown}}
{{event.description|safe}}
{% else %}
{{event.location.description|markdown}}
{{event.location.description|safe}}
{% endif %}
<p class="more_link">
<a href="https://plus.google.com/share?url=http%3A%2F%2Fwww.kasu.at{{event.get_absolute_url|urlencode}}" onclick="javascript:window.open(this.href,
'', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=600,width=600');return false;"><img src="{{STATIC_URL}}img/google_plus.png" alt="Google+" title="{% trans 'Share on Google+'%}" width="39" height="39"/></a>
<a href="https://twitter.com/share?url=http%3A%2F%2Fwww.kasu.at{{event.get_absolute_url|urlencode}}" target='_blank'><img src="{{STATIC_URL}}img/twitter.png" alt="Twitter" title=" {% trans 'Share on Twitter' %}" width="39" height="39"/></a>
<a href="http://facebook.com/sharer.php?u=http%3A%2F%2Fwww.kasu.at{{event.get_absolute_url|urlencode}}" target="_blank"><img src="{{STATIC_URL}}img/facebook.png" alt="Facebook" title="{% trans 'Share on Facebook'%}" width="39" height="39"/></a>
<a href="http://maps.google.com/maps?q={{event.location.address|urlencode}}&amp;z=16" target="gmaps"><img src="{{ STATIC_URL }}img/google_maps.png" alt="Google Maps" title="{% trans 'Show on Google Maps' %}" width="39" height="39"/></a>
<a class="button" href="http://facebook.com/sharer.php?u=http%3A%2F%2Fwww.kasu.at{{event.get_absolute_url|urlencode}}" target="_blank">
<span class="fa fa-facebook"></span>
{% trans 'Share on Facebook'%}
</a>
<a class="button" href="https://plus.google.com/share?url=http%3A%2F%2Fwww.kasu.at{{event.get_absolute_url|urlencode}}" onclick="javascript:window.open(this.href,
'', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=600,width=600');return false;">
<span class="fa fa-google-plus"></span>
{% trans 'Share on Google+'%}
</a>
<a class="button" href="https://twitter.com/share?url=http%3A%2F%2Fwww.kasu.at{{event.get_absolute_url|urlencode}}" target='_blank'>
<span class="fa fa-twitter"></span>
{% trans 'Share on Twitter' %}
</a>
<a class="button" href="http://maps.google.com/maps?q={{event.location.address|urlencode}}&amp;z=16" target="gmaps">
<span class="fa fa-map"></span>
{% trans 'Show on Google Maps' %}
</a>
</p>
</div>
<br class="clear" />

View File

@@ -1,5 +1,5 @@
{% extends "events/page.html" %}
{% load i18n comments%}
{% load i18n comments thumbnail %}
{% block title %}{% trans "Upcoming Events" %}{% endblock %}
{% block teaser%}<h2>{% trans "Upcoming Events" %}</h2>{% endblock %}
@@ -10,22 +10,33 @@
<h3 class="grid_12">{{ month.grouper }}</h3>
{% for event in month.list %}
{% get_comment_count for event as comment_count %}
<a href="{{ event.get_absolute_url }}" class="grid_2"><img
src="{{ event.get_thumbnail.url }}" alt=" {% trans 'Event Image' %}" class="thumbnail"/></a>
<div class="grid_4">
<div class="grid_6">
{% if perms.events.change_event %}
<a href="{{ event.get_edit_url }}" class="button" style="float:right"><span class="fa fa-pencil"></span></a>
{% endif %}
{% if perms.events.add_photo %}
<a href="{% url 'event-photo-list' event.pk %}" class="button" style="float:right"><span class="fa fa-camera-retro"></span></a>
{% endif %}
<a href="{{ event.get_absolute_url }}" class="thumbnail"><img
src="{{ event.get_image|thumbnail_url:'thumbnail' }}" alt="{% trans 'Event Image' %}" width="140" height="140"/>
</a>
<h4><a href="{{ event.get_absolute_url }}">{{ event.name }}</a></h4>
<ul class="info">
<li><span class="fa fa-calendar-o" title="{% trans 'Date' %}"></span> <time datetime="{{event.start|date:'c'}}">{{ event.start|date:'SHORT_DATE_FORMAT' }}</time></li>
<li><span class="fa fa-map-marker" title="{% trans 'Location' %}"></span> {{ event.location }}</li>
<li><span class="fa fa-comments" title="{% trans 'Comments' %}"></span> <a href="{{event.get_absolute_url}}#comments">{{ comment_count }}</a></li>
<li><span class="fa fa-calendar-o" title="{% trans 'Date' %}" aria-label="{% trans 'Date' %}"></span>
<time datetime="{{event.start|date:'c'}}">
{{ event.start|date:'D' }}
{{ event.start|date:'SHORT_DATE_FORMAT' }}
</time>
</li>
<li><span class="fa fa-clock-o" title="{% trans 'Start' %}" aria-label="{% trans 'Start' %}"></span>
{{ event.start|time:'H:i' }}
</li>
<li><span class="fa fa-map-marker" title="{% trans 'Location' %}" aria-label="{% trans 'Location' %}"></span>
{{ event.location }}
</li>
<li><span class="fa fa-comments" title="{% trans 'Comments' %}" aria-label="{% trans 'Comments' %}"></span>
<a href="{{event.get_absolute_url}}#comments">{{ comment_count }}</a>
</li>
</ul>
<p>{{event.description|truncatewords_html:20}}</p>
<p>{{event.description|truncatewords_html:25|safe}}</p>
</div>
{% if forloop.counter|divisibleby:2 %}<br class="clear">{% endif %}
{% endfor %}

View File

@@ -1,5 +1,5 @@
{% extends "base.html" %}
{% load i18n django_markdown%}
{% load i18n %}
{% block title %}{{ event.name }}{% endblock %}
@@ -11,12 +11,12 @@
{% if event.description %}<meta property="og:description" content="{{event.description}}" />{% endif %}
{% endblock %}
{% block jumbotron_background %}{{ event.get_callout.url }}')}{% endblock %}
{% block jumbotron_background %} {{ event.get_image|thumbnail_url:'callout' }} {% endblock %}
{% block teaser %}
<h1>{{event.name}}</h1>
<div id="teaser_text">
{% if event.description %}{{event.description|markdown}}{% else %}{{event.location.description|markdown}}{% endif %}
{% if event.description %}{{event.description}}{% else %}{{event.location.description}}{% endif %}
</div>
{% endblock %}

View File

@@ -1,15 +1,8 @@
{% extends "events/event_detail.html" %}
{% load i18n django_markdown comments %}
{% load i18n comments %}
{% block title %}{{ event.name }}{% endblock %}
{% block teaser %}
<h1>{{event.name}}</h1>
{% if event.description %}
<div id="teaser_text">{{event.description|markdown|truncatewords_html:75}}</div>
{% endif %}
{% endblock %}
{% block event_content %}
<h3>Hier kommt eine Tabelle rein!</h3>
<form class="grid_12" method="post">

View File

@@ -1,5 +1,5 @@
{% extends "events/event_detail.html" %}
{% load i18n comments %}
{% load i18n comments thumbnail %}
{% block maincontent %}
<form action="" method="post" class="grid_12">
@@ -8,13 +8,16 @@
<h1 class="grid_12">Dieses Photo wirklich löschen?</h1>
</header>
<p>Sind Sie sicher, dass Sie das Bild &ldquo;{{photo.name}}&rdquo; löschen wollen?</p>
<img src="{{photo.display.url}}" alt="{{photo.name}}" title="{{photo.name}}" class="grid_10 push_1"/>
<img src="{{photo.image|thumbnail_url:'display'}}" alt="{{photo.name}}" title="{{photo.name}}" class="grid_10 push_1"/>
<br class="clear"/>
<p>&nbsp;</p>
<p class="buttonbar">
<a href="{% url 'event-photo-list' photo.event.id %}" class="button" style="float: left;"><img
src="{{STATIC_URL}}icons/cancel.png" alt="{% trans 'Cancel' %}"/> {% trans 'Cancel' %}</a>
<button type="submit"><img src="{{STATIC_URL}}icons/delete.png" alt="{% trans 'Delete' %}"/>
<a class="button" href="{% url 'event-photo-list' photo.event.id %}" style="float: left;">
<span class="fa fa-ban"></span>
{% trans 'Cancel' %}
</a>
<button type="submit">
<span class="fa fa-trash"></span>
{% trans 'Delete' %}
</button>
</p>

View File

@@ -0,0 +1,85 @@
{% extends "events/event_detail.html" %}
{% load i18n comments thumbnail %}
{% block title %} {{ photo.name }} - {{ photo.event.name }} {% endblock %}
{% block extra_head %}
<script type="text/javascript" src="{{ STATIC_URL }}/js/jquery.min.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}/js/mousetrap.js"></script>
{% endblock %}
{% block javascript %}
if ($('a.previous').attr('href')) {
Mousetrap.bind('left', function() { window.location = $('a.previous').attr('href'); });
}
if ($('a.next').attr('href')) {
Mousetrap.bind('right', function() { window.location = $('a.next').attr('href'); });
}
{% endblock %}
{% block teaser %}
<h1 class="grid_12">{{event.name}} - {{ photo.name }}</h1>
{% if event.description %}
<div id="teaser_text">{{event.description|truncatewords_html:75}}</div>
{% endif %}
{% endblock %}
{% block opengraph %}
<meta property="og:type" content="photo" />
<meta property="og:title" content="{{photo.name}} - Foto" />
<meta property="og:url" content="http://www.kasu.at{{photo.get_absolute_url}}" />
<meta property="og:image" content="http://www.kasu.at{{photo.thumbnail.url}}" />
{% if photo.description %}<meta property="og:description" content="{{photo.description}}" />{% endif %}
{% endblock %}
{% block maincontent %}
<div id="display" class="grid_12">
<img src="{{photo.image|thumbnail_url:'display'}}" alt="{{photo.name}}" title="{{photo.name}}"/>
{% if photo.previous_photo %}
<a href="{% url 'event-photo' photo.previous_photo.event.id photo.previous_photo.id %}#display" class="previous" id="previous">{% trans 'previous' %}</a>
{% endif %}
{% if photo.next_photo %}
<a href="{% url 'event-photo' photo.next_photo.event.id photo.next_photo.id %}#display" class="next" id="next">Next</a>
{% endif %}
</div>
<div class="grid_12">
<ul class="info">
<li><span class="fa fa-user"></span> <strong>{% trans 'Photographer' %}: </strong>{{ photo.photographer }}</li>
<li><span class="fa fa-calendar-o"></span> <strong>{% trans 'Date' %}</strong> {{ photo.created_date }}</li>
</ul>
<p>{{ photo.description }}</p>
</div>
<p class="right">
<strong>{% trans 'share on' %}:</strong>
<a class="button" href="http://facebook.com/sharer.php?u=http%3A%2F%2Fwww.kasu.at{{photo.get_absolute_url|urlencode}}" target="_blank" rel="nofollow">
<span class="fa fa-twitter"></span>Facebook
</a>
<a class="button" 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" rel="nofollow">
<span class="fa fa-google-plus"></span> Google+
</a>
<a class="button" href="https://twitter.com/share?url=http%3A%2F%2Fwww.kasu.at/{{photo.get_absolute_url|urlencode}}" target='_blank' rel="nofollow">
<span class="fa fa-twitter"></span> Twitter
</a>
</p>
{% 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 %}
<p class="buttonbar">
<a href="{{ photo.image.url }}" class="button" type="application/octet-stream"><span class="fa fa-download"></span> {% trans 'download' %}</a>
<button type="submit" name="rotate" value="counter-clockwise"><span class="fa fa-undo"></span> {% trans 'Rotate counter clockwise' %}</button>
<button type="submit" name="rotate" value="clockwise"><span class="fa fa-repeat"></span> {% trans 'Rotate clockwise' %}</button>
<button type="submit"><span class="fa fa-check"></span> {% trans 'Save' %}</button>
</p>
</form>
{% endif %}
{% endblock %}

View File

@@ -1,11 +1,11 @@
{% extends "base.html" %}
{% load i18n %}
{% load i18n thumbnail %}
{% block maincontent %}
{% for event in event_list %}
<div class="gallery grid_4">
<h3><a href="{% url 'event-photo-list' event.id %}">{{event.name}}</a></h3>
<a href="{% url 'event-photo-list' event.id %}"><img src="{{event.get_thumbnail.url}}" class="thumbnail" alt="{{ event.name }}"/></a>
<a href="{% url 'event-photo-list' event.id %}"><img src="{{event.get_image|thumbnail_url:'thumbnail' }}" class="thumbnail" alt="{{ event.name }}"/></a>
</div>
{% empty %}
<p>Sorry da kommt erst was hin!</p>

View File

@@ -0,0 +1,45 @@
{% extends "events/event_detail.html" %}
{% load i18n thumbnail %}
{% block title %}{{event.name}}{% endblock %}
{% block opengraph %}
<meta property="og:type" content="album" />
<meta property="og:title" content="{{event.name}}" />
<meta property="og:url" content="http://www.kasu.at{% url 'event-photo-list' event.pk %}" />
<meta property="og:image" content="http://www.kasu.at{{ event.get_thumbnail.url }}" />
{% if event.description %}<meta property="og:description" content="{{event.description}}" />{% endif %}
{% endblock %}
{% block maincontent %}
{% for photo in photo_list %}
<div class="thumbnail">
<a href="{% url 'event-photo' event.id photo.id %}"><img src="{{photo.image|thumbnail_url:'thumbnail'}}" alt=""/></a>
{% if perms.events.delete_photo %}
<a href="{% url 'delete-event-photo' photo.pk %}" class="button delete_image">
<span class="fa fa-trash" aria-label="{% trans 'Delete' %}" title="{% trans 'Delete' %}"></span>
</a>
{% endif %}
</div>
{% endfor %}
{% if perms.events.add_photo %}
<form action="{% url 'event-photo-upload' event.id %}" method="post" enctype="multipart/form-data" class="grid_12">
{% csrf_token %}
<fieldset>
<legend>Photos hochladen</legend>
{% include "form.html"%}
<p class="buttonbar">
<button type="reset"><span class="fa fa-undo"></span> {% trans 'reset' %}</button>
<button type="submit"><span class="fa fa-cloud-upload"></span> {% trans 'Upload' %}</button>
</p>
</fieldset>
</form>
{% endif %}
{% endblock %}
{% block buttonbar %}{% endblock %}

View File

@@ -1,16 +1,16 @@
{% extends "base.html" %}
{% load i18n comments %}
{% load i18n comments thumbnail %}
{% block maincontent %}
{% for event in event_list %}
{% get_comment_count for event as comment_count %}
{% ifchanged %}<h3 class="grid_12">{{ event.start|date:'F Y' }}</h3>{% endifchanged %}
<div style="float:left">
<a href="{% url 'event-photo-list' event.pk %}"><img src="{{ event.get_thumbnail.url }}" alt="" class="thumbnail"/></a>
<a href="{% url 'event-photo-list' event.pk %}"><img src="{{ event.get_image|thumbnail_url:'thumbnail' }}" alt="" class="thumbnail"/></a>
<div class="grid_4" />
<h4><a href="{% url 'event-photo-list' event.pk %}">{{ event.name }}</a></h4>
<div class="info">
<img src="{{ STATIC_URL }}/icons/date.png" alt="{% trans 'Start' %}" title="{% trans 'Start' %}">
<span class="fa fa-calendar-o" title="{% trans 'Start' %}"></span>
{{ event.start|date }}
{% if event.end %}
{% trans "from" %} {{ event.start|time:'H:i' }} {% trans "to" %} {{ event.end|time:'H:i' }}
@@ -20,16 +20,19 @@
</div>
{% if event.description %}<p>{{event.description}}</p>{% endif %}
<div class="info">
<img src="{{ STATIC_URL }}/icons/map.png" alt="{% trans 'Location' %}" title="{% trans 'Location' %}">
<span class="fa fa-map-marker" title="{% trans 'Location' %}"></span>
{{ event.location }}
<img src="{{ STATIC_URL }}/icons/comments.png" alt="{% trans 'Comments' %}" title="{% trans 'Comments' %}">
<span class="fa fa-comments" title="{% trans 'Comments' %}"></span>
<a href="{{event.get_absolute_url}}#comments">{{ comment_count }} {% trans 'Comments' %}</a>
<img src="{{ STATIC_URL }}/icons/images.png" alt="{% trans 'Photos' %}" title="{% trans 'Photos' %}">
<span class="fa fa-camera-retro" title="{% trans 'Photos' %}"></span>
<a href="{% url 'event-photo-list' event.pk %}">{{ event.photo_count }} {% trans 'Photos' %}</a>
</div>
<p style="text-align:right">
{% if perms.events.add_photo %}
<a href="{% url 'event-photo-list' event.pk %}" class="button"><img src="{{ STATIC_URL }}icons/image_add.png" alt="{%trans "Upload" %}"></a>
<a href="{% url 'event-photo-list' event.pk %}" class="button">
<span class="fa fa-cloud-upload"></span>
{%trans "Upload" %}</a>
{% endif %}
</p>
</div></div>
@@ -42,8 +45,8 @@
{% include "form.html" %}
<p class="buttonbar">
<button type="submit">
<img src="{{ STATIC_URL }}icons/drive_go.png" alt="" />
{% trans "upload" %}
<span class="fa fa-cloud-upload"></span>
{% trans "Upload" %}
</button>
</p>
</fieldset>

View File

@@ -9,6 +9,7 @@ from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.

View File

@@ -1,11 +1,11 @@
# -*- encoding: utf-8 -*-
from django.conf.urls import patterns, url
from django.views.generic import RedirectView
from .views import *
urlpatterns = patterns(
'',
url(r'^$', UpcomingEvents.as_view(), name='upcoming-events'),
url(r'^$', RedirectView.as_view(url='/events/upcoming/', permanent=True)),
url(r'^(?P<year>[\d]{4})/$', EventArchiveYear.as_view(),
name='event-archive'),
url(r'^(?P<year>[\d]{4})/(?P<month>[\d]+)/$', EventArchiveMonth.as_view(),
@@ -18,4 +18,5 @@ urlpatterns = patterns(
EventForm.as_view(), name='event-form'),
url(r'^add/$', EventForm.as_view(), name='event-form'),
url(r'^archive/$', EventArchiveIndex.as_view(), name='event-archive'),
url(r'^upcoming/$', UpcomingEvents.as_view(), name='upcoming-events'),
)

View File

@@ -2,6 +2,7 @@
# Create your views here.
from datetime import timedelta
from django.db.models import Q
from django.contrib.auth.decorators import permission_required
from django.contrib.auth import get_user_model
from django.core.urlresolvers import reverse
@@ -13,22 +14,23 @@ 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
class DeleteEventPhoto(generic.DeleteView):
model = models.Photo
"""
def get_object(self, queryset=None):
return models.Photo.objects.get(pk=self.kwargs['pk'])
"""
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)
@@ -39,10 +41,9 @@ class EventArchiveIndex(generic.ArchiveIndexView):
context_object_name = 'event_list'
date_field = 'start'
model = models.Event
queryset = model.objects.all()
ordering = ('-start', '-end')
paginate_by = 15
def get_context_data(self, **kwargs):
context = generic.ArchiveIndexView.get_context_data(self, **kwargs)
context['is_archive'] = True
@@ -53,6 +54,7 @@ class EventArchiveMonth(generic.MonthArchiveView):
date_field = 'start'
make_object_list = True
model = models.Event
ordering = ('start', 'end')
month_format = '%m'
paginate_by = 15
template_name = 'events/event_archive.html'
@@ -64,9 +66,10 @@ class EventArchiveMonth(generic.MonthArchiveView):
class EventArchiveYear(generic.YearArchiveView):
model = models.Event
date_field = 'start'
make_object_list = True
model = models.Event
ordering = ('start', 'end')
paginate_by = 15
template_name = 'events/event_archive.html'
year_format = '%Y'
@@ -117,27 +120,13 @@ class EventForm(PermissionRequiredMixin, generic.UpdateView):
return models.Event()
class EventSeriesForm(EventDetailMixin, PermissionRequiredMixin, InlineFormSetView):
model = models.Event
inline_model = models.Event
fk_name = 'event_series'
fields = ('start', 'end')
form_class = forms.EventForm
extra = 3
permission_required = 'events.add_event'
template_name = 'events/eventseries_form.html'
def get_object(self, queryset=None):
self.event = models.Event.objects.get(pk=self.kwargs['pk'])
if self.event.event_series:
self.event = self.event.event_series
return self.event
class EventGallery(generic.ListView):
template_name = 'events/photo_gallery.html'
queryset = models.Event.objects.filter(start__lt=timezone.now(),
photo_count__gt=0)
queryset = models.Event.objects.filter(
start__lt=timezone.now(),
event_series__isnull=True,
photo_count__gt=0
)
paginate_by = 12
@@ -180,7 +169,10 @@ class EventPhoto(generic.UpdateView):
def get_context_data(self, **kwargs):
context = super(EventPhoto, self).get_context_data()
try:
event = models.Event.objects.get(id=self.kwargs['event'])
except models.Event.DoesNotExist:
event = self.object.event
context['event'] = event
return context
@@ -209,7 +201,10 @@ class EventPhotoList(generic.ListView):
def get_queryset(self):
try:
self.event = models.Event.objects.get(id=self.kwargs['event'])
return models.Photo.objects.filter(event=self.event)
return models.Photo.objects.filter(
Q(event=self.event) |
Q(event__event_series=self.event)
)
except models.Event.DoesNotExist:
raise Http404(_('Event does not exist'))
@@ -261,20 +256,28 @@ class EventPhotoUpload(generic.FormView):
return redirect('event-photo-list', event=self.event.id)
def read_exif(self, photo):
exif_data = pyexiv2.ImageMetadata.from_buffer(photo.read())
exif_data.read()
try:
created_date = exif_data['Exif.Image.DateTime'].value
except:
created_date = self.event.start + timedelta(minutes=self.counter)
try:
description = exif_data['Exif.Image.ImageDescription'].value
except:
description = ''
return created_date, description
class EventSeriesForm(EventDetailMixin, PermissionRequiredMixin, InlineFormSetView):
model = models.Event
inline_model = models.Event
fk_name = 'event_series'
fields = ('start', 'end')
form_class = forms.EventForm
extra = 3
permission_required = 'events.add_event'
template_name = 'events/eventseries_form.html'
def get_object(self, queryset=None):
self.event = models.Event.objects.get(pk=self.kwargs['pk'])
if self.event.event_series:
self.event = self.event.event_series
return self.event
class UpcomingEvents(generic.ListView):
queryset = models.Event.objects.upcoming(limit=None)
paginate_by = 16

View File

@@ -1 +0,0 @@
__author__ = 'christian'

View File

@@ -1,42 +0,0 @@
"""
Created on 03.10.2011
@author: christian
"""
from django import forms
from django.utils.translation import ugettext as _
from django.contrib.auth import get_user_model
from . import models
from events.models import Event
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(Event.objects.all(), required=True, )
upload = forms.FileField(
label=_('Images'),
required=True,
widget=forms.widgets.ClearableFileInput(
attrs={
'multiple': 'multiple',
'accept': "image/gif,image/png,image/jpeg"
}
)
)
class EditPhotoForm(forms.ModelForm):
error_css_class = 'error'
required_css_class = 'required'
class Meta(object):
model = models.Photo
fields = ('event', 'name', 'description', 'photographer',
'anchor_horizontal', 'anchor_vertical',
'created_date', 'on_startpage')

View File

@@ -1,154 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-22 23:28+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: forms.py:23
msgid "Images"
msgstr ""
#: models.py:44
msgid "Name"
msgstr ""
#: models.py:45
msgid "Image"
msgstr ""
#: models.py:48
msgid "horizontal Anchorpoint"
msgstr ""
#: models.py:55
msgid "vertical Anchorpoint"
msgstr ""
#: models.py:64
msgid "Description"
msgstr ""
#: models.py:70
msgid "Startpage"
msgstr ""
#: models.py:72
msgid "Display this Photo on the Startpage Teaser"
msgstr ""
#: models.py:74
msgid "Published on"
msgstr ""
#: models.py:76
msgid "Number of views"
msgstr ""
#: models.py:88
msgid "Event Image"
msgstr ""
#: models.py:89
msgid "Event Images"
msgstr ""
#: templates/gallery/photo_confirm_delete.html:16
msgid "Cancel"
msgstr ""
#: templates/gallery/photo_confirm_delete.html:17
#: templates/gallery/photo_confirm_delete.html:18
msgid "Delete"
msgstr ""
#: templates/gallery/photo_detail.html:19
msgid "previous"
msgstr ""
#: templates/gallery/photo_detail.html:27
msgid "Share on Google+"
msgstr ""
#: templates/gallery/photo_detail.html:28
msgid "Share on Twitter"
msgstr ""
#: templates/gallery/photo_detail.html:29
msgid "Share on Facebook"
msgstr ""
#: templates/gallery/photo_detail.html:33
msgid "Photographer"
msgstr ""
#: templates/gallery/photo_detail.html:34
msgid "on"
msgstr ""
#: templates/gallery/photo_detail.html:48
msgid "download"
msgstr ""
#: templates/gallery/photo_detail.html:51
msgid "save"
msgstr ""
#: templates/gallery/photo_list.html:20
msgid "delete"
msgstr ""
#: templates/gallery/photo_list.html:37
msgid "reset"
msgstr ""
#: templates/gallery/photo_list.html:38 templates/gallery/photo_upload.html:46
msgid "upload"
msgstr ""
#: templates/gallery/photo_upload.html:13
msgid "Start"
msgstr ""
#: templates/gallery/photo_upload.html:16
msgid "from"
msgstr ""
#: templates/gallery/photo_upload.html:16
msgid "to"
msgstr ""
#: templates/gallery/photo_upload.html:23
msgid "Location"
msgstr ""
#: templates/gallery/photo_upload.html:25
#: templates/gallery/photo_upload.html:26
msgid "Comments"
msgstr ""
#: templates/gallery/photo_upload.html:27
#: templates/gallery/photo_upload.html:28
msgid "Photos"
msgstr ""
#: templates/gallery/photo_upload.html:32
msgid "Upload"
msgstr ""
#: views.py:80
msgid "Event does not exist"
msgstr ""

View File

@@ -1,41 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import gallery.models
import utils
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
('events', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Photo',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=100, verbose_name='Name', blank=True)),
('image', models.ImageField(upload_to=gallery.models.get_upload_path, storage=utils.OverwriteStorage(), verbose_name='Bild')),
('anchor_horizontal', models.FloatField(blank=True, help_text=b'Der Ankerpunkt ist der interessante Teil des Bildes, welcher nie abgeschnitten werden darf', null=True, verbose_name='horizontal Anchorpoint', choices=[(1e-08, 'Links'), (0.5, 'Mitte'), (1, 'Rechts')])),
('anchor_vertical', models.FloatField(blank=True, help_text=b'Wenn kein Ankerpunkt von Hand (horizontal und vertikal) festgelegt wird, versucht die Software diesen selbst zu erraten.', null=True, verbose_name='vertical Anchorpoint', choices=[(1e-08, 'Oben'), (0.5, 'Mitte'), (1, 'Unten')])),
('description', models.TextField(max_length=300, verbose_name='Beschreibung', blank=True)),
('on_startpage', models.BooleanField(default=False, help_text='Display this Photo on the Startpage Teaser', verbose_name='Startpage')),
('created_date', models.DateTimeField(verbose_name='Published on')),
('views', models.PositiveIntegerField(default=0, verbose_name='Number of views', editable=False)),
('event', models.ForeignKey(to='events.Event')),
('photographer', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['created_date'],
'db_table': 'events_photo',
'verbose_name': 'Veranstaltungsbild',
'verbose_name_plural': 'Event Images',
'get_latest_by': 'created_date',
},
),
]

View File

@@ -1,171 +0,0 @@
# -'- Encoding: utf-8 -*-
import os
from django.conf import settings
from django.core.urlresolvers import reverse
from django.db import models
from django.utils.translation import ugettext as _
import pyexiv2
from utils import OverwriteStorage
from kasu import image_models
def get_upload_path(instance, filename):
"""
Generates the desired file path and filename for an uploaded Image.
With this function Django can save the uploaded images to subfolders that
also have a meaning for humans.
@param instance: an Django Object for which the Image has been uploaded.
@type instance: a instace of an models.Model sub-class.
@param filename: The filename of the uploaded image.
@type filename: String
"""
extension = filename[filename.rfind('.') + 1:]
if isinstance(instance, Photo):
return "events/%s/%s" % (instance.event.id, filename)
class PhotoManager(models.Manager):
def get_random(self, startpage=True):
if startpage:
queryset = self.filter(on_startpage=True)
else:
queryset = self.all().order_by('?')[0]
try:
return queryset.order_by('?')[0]
except IndexError:
return Photo()
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=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=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('events.Event')
description = models.TextField(
_("Description"),
max_length=300,
blank=True
)
photographer = models.ForeignKey(settings.AUTH_USER_MODEL)
on_startpage = models.BooleanField(
_("Startpage"),
default=False,
help_text=_('Display this Photo on the Startpage Teaser')
)
created_date = models.DateTimeField(_("Published on"))
views = models.PositiveIntegerField(
_("Number of views"),
editable=False,
default=0
)
objects = PhotoManager()
metadata = None
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')
def __unicode__(self):
return os.path.basename(self.image.name)
def read_metadata(self):
image_path = os.path.join(settings.MEDIA_ROOT, self.image.name)
self.metadata = pyexiv2.ImageMetadata(image_path)
self.metadata.read()
try:
self.orientation = self.metadata['Exif.Image.Orientation'].value
except:
self.orientation = 1
def save_metadata(self):
if not self.metadata:
self.read_metadata()
self.metadata['Exif.Image.DateTime'] = self.created_date
self.metadata['Exif.Image.ImageDescription'] = self.description
self.metadata['Exif.Image.Artist'] = self.photographer.username
self.metadata['Exif.Image.Orientation'] = self.orientation or 1
self.metadata.write()
def rotate(self, rotate):
"""
Sets an the Exif tag in an image to set the right direction.
This provides lossless image rotation.
@param rotate: 'clockwise' or 'counter-clockwise' the direction in
which we should rotate the image in 90° steps.
"""
if not self.metadata:
self.read_metadata()
if rotate == 'clockwise':
if self.orientation == 1:
self.orientation = 6
elif self.orientation == 6:
self.orientation = 3
elif self.orientation == 3:
self.orientation = 8
else:
self.orientation = 1
elif rotate == 'counter-clockwise':
if self.orientation == 1:
self.orientation = 8
elif self.orientation == 8:
self.orientation = 3
elif self.orientation == 3:
self.orientation = 6
else:
self.orientation = 1
self.save()
def get_absolute_url(self):
return reverse(
'event-photo',
kwargs={'event': self.event.id, 'pk': self.id}
)
@property
def next_photo(self):
return self.get_next_by_created_date(event=self.event)
@property
def previous_photo(self):
return self.get_previous_by_created_date(event=self.event)
def save(self, **kwargs):
"""
Triggers to save related Event to save. This should force an update for
the denormalized Photo count.
"""
super(Photo, self).save()
self.save_metadata()
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,57 +0,0 @@
{% extends "gallery/photo_list.html" %}
{% load i18n comments %}
{% block title %} {{ photo.name }} - {{ photo.event.name }} {% endblock %}
{% block opengraph %}
<meta property="og:type" content="photo" />
<meta property="og:title" content="{{photo.name}} - Foto" />
<meta property="og:url" content="http://www.kasu.at{{photo.get_absolute_url}}" />
<meta property="og:image" content="http://www.kasu.at{{photo.thumbnail.url}}" />
{% if photo.description %}<meta property="og:description" content="{{photo.description}}" />{% endif %}
{% endblock %}
{% block maincontent %}
<h2 class="grid_12"><a href="{% url 'event-photo-list' photo.event.id %}">{{photo.event.name}}</a> &raquo; {{ photo.name }}</h2>
<div id="display" class="grid_12 clearfix">
<img src="{{photo.display.url}}" alt="{{photo.name}}" title="{{photo.name}}"/>
{% if photo.previous_photo %}
<a href="{{ photo.previous_photo.get_absolute_url }}" class="previous">{% trans 'previous' %}</a>
{% endif %}
{% if photo.next_photo %}
<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>
<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 %}
<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>
</form>
{% endif %}
{% endblock %}

View File

@@ -1,47 +0,0 @@
{% extends "events/event_detail.html" %}
{% load i18n %}
{% block title %}{{event.name}}{% endblock %}
{% block opengraph %}
<meta property="og:type" content="album" />
<meta property="og:title" content="{{event.name}}" />
<meta property="og:url" content="http://www.kasu.at{% url 'event-photo-list' event.pk %}" />
<meta property="og:image" content="http://www.kasu.at{{ event.get_thumbnail.url }}" />
{% if event.description %}<meta property="og:description" content="{{event.description}}" />{% endif %}
{% endblock %}
{% block maincontent %}
{% if perms.events.delete_photo %}
{% for photo in photo_list %}
<div class="thumbnail">
<a href="{{photo.get_absolute_url}}"><img src="{{photo.thumbnail.url}}" alt=""/></a>
<a href="{% url 'delete-event-photo' photo.pk %}" class="delete_image"><img src="{{STATIC_URL}}icons/delete.png" title="{% trans 'delete' %}"/></a>
</div>
{% endfor %}
{% else %}
{% for photo in photo_list %}
<a href="{{photo.get_absolute_url}}" class="thumbnail"><img src="{{photo.thumbnail.url}}" alt=""/></a>
{% endfor %}
{% endif %}
{% if perms.events.add_photo %}
<br class="clear" />
<form action="{% url 'event-photo-upload' event.id %}" method="post" enctype="multipart/form-data" class="grid_12">
{% csrf_token %}
<fieldset>
<legend>Photos hochladen</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/image_add.png" alt="{% trans 'upload' %}" /> {% trans 'upload' %}</button>
</p>
</fieldset>
</form>
{% endif %}
{% endblock %}
{% block buttonbar %}{% endblock %}

View File

@@ -1,142 +0,0 @@
# -*- encoding: utf-8 -*-
# Create your views here.
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 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
import pyexiv2
from events.models import Event
from .models import Photo
from . import forms
class DeleteEventPhoto(generic.DeleteView):
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 EventGallery(generic.ListView):
template_name = 'gallery/photo_gallery.html'
queryset = Event.objects.filter(start__lt=timezone.now(), photo_count__gt=0)
paginate_by = 12
class EventPhoto(generic.UpdateView):
form_class = forms.EditPhotoForm
model = Photo
template_name = 'gallery/photo_detail.html'
def get_context_data(self, **kwargs):
context = super(EventPhoto, self).get_context_data()
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 = Photo.objects.get(pk=kwargs['pk'])
photo.rotate(request.POST['rotate'])
# return redirect(photo.get_absolute_url())
return self.get(request)
else:
return generic.UpdateView.post(self, request, *args, **kwargs)
class EventPhotoList(generic.ListView):
context_object_name = 'photo_list'
paginate_by = 36
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})
return context
def get_queryset(self):
try:
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 = 'gallery/photo_upload.html'
@method_decorator(permission_required('events.add_photo'))
def dispatch(self, *args, **kwargs):
return super(EventPhotoUpload, self).dispatch(*args, **kwargs)
def get_context_data(self, **kwargs):
context = generic.FormView.get_context_data(self, **kwargs)
context['event_list'] = Event.objects.archive()[:12]
return context
def get_initial(self):
"""
Set the current logged in user a default value for the photographer.
"""
return {
'photographer': self.request.user,
}
def post(self, *args, **kwargs):
"""
"""
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 = Photo(
event=self.event,
photographer=photographer,
image=upload,
name=name,
created_date=created_date,
description=description
)
photo.save()
self.counter += 1
return redirect('event-photo-list', event=self.event.id)
def read_exif(self, photo):
exif_data = pyexiv2.ImageMetadata.from_buffer(photo.read())
exif_data.read()
try:
created_date = exif_data['Exif.Image.DateTime'].value
except:
created_date = self.event.start + timedelta(minutes=self.counter)
try:
description = exif_data['Exif.Image.ImageDescription'].value
except:
description = ''
return created_date, description

View File

@@ -10,19 +10,6 @@ from imagekit.models import ImageSpecField
import imagekit
CHOICES_HORIZONTAL = (
(0.00000001, _('left')),
(0.5, _('center')),
(1, _('right'))
)
CHOICES_VERTICAL = (
(0.00000001, _('top')),
(0.5, _('middle')),
(1, _('bottom'))
)
class ArticleImage(imagekit.ImageSpec):
format = 'JPEG'
width = 200
@@ -96,11 +83,10 @@ def regenerate_image_cache(sender, instance=None, created=False, raw=False,
Reganerate the images.
"""
if instance.image:
print instance.image
print instance.display
print instance.callout
for cached_image in (instance.article, instance.callout, instance.display, instance.thumbnail):
try:
os.remove(cached_image.path)
except IOError:
pass
except OSError:
pass

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 663 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1021 B

View File

@@ -12,55 +12,6 @@
src: url('../fonts/amerikasans.woff') format('woff'), url('../fonts/amerikasans.ttf') format('truetype');
}
.clear {
clear: both;
display: block;
height: 0;
overflow: hidden;
visibility: hidden;
width: 0;
}
#display {position:relative;top:0px; text-align: center;}
.clearfix {
clear: both;
}
.grid_1,.grid_2,.grid_3,.grid_4,.grid_5,.grid_6,.grid_7,.grid_8,.grid_9,.grid_10,.grid_11,.grid_12
{
display: inline;
float: left;
margin: 0px 10px;
position: relative;
box-sizing: border-box;
}
.grid_1 {
width: 60px;
}
.grid_2 {
width: 140px;
}
.grid_3 {
width: 220px;
}
.grid_4 {
width: 300px;
}
.grid_5 {
width: 380px;
}
.more_link {
text-align: right;
clear: left;
}
.error, ul.errorlist li {
color: #a40000;
}
a:hover {
color: #a40000;
text-decoration: underline;
@@ -71,11 +22,13 @@ a:link {
font-weight: 700;
text-decoration: none;
}
a:visited {
color: #5c3566;
a:visited {color: #5c3566;}
article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section {display: block;}
body {
font: 12pt Philosopher, Georgia, serif;
line-height: 1;
vertical-align: baseline;
}
button, a.button, #redbox a.button:link, #redbox a.button:visited {
display: inline-block;
padding: 0.25em;
@@ -90,17 +43,79 @@ button, a.button, #redbox a.button:link, #redbox a.button:visited {
text-decoration: none;
text-shadow: 1px 1px 1px #ffffff;
}
div.tab_container {
background-color:#fff;
padding-top: 1em;
article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section {
display: block;
}
h1 a:link, h2 a:link, h3 a:link, h4 a:link, h5 a:link, h6 a:link, h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited {
color: #bc0a19;
fieldset {
border: none;
color: #2e3436;
border-radius: 10px;
padding: 0 10px 0 160px;
background-color: #f2f5f6;
background: linear-gradient(135deg, #f2f5f6 0%, #e3eaed 37%, #c8d7dc 100%);
vertical-align: top;
margin-bottom: 1em;
}
fieldset div {margin: 5px 0px;}
fieldset legend {
margin-top: -.1em;
margin-left: -150px;
color: #a40000;
font-family: 'Amerika Sans', sans-serif;
font-variant: small-caps;
font-weight: 400;
text-decoration: none;
font-size: 16pt;
text-shadow: 2px 2px 2px #888;
}
fieldset .required {font-weight: bold;}
fieldset .buttonbar {
border-radius: 0px 0px 10px 10px;
margin: 0 -10px 0 -160px;
}
fieldset .help_text {font-size: small;}
fieldset .field_name {
text-align: right;
width: 140px;
margin: 0 20px 0 -160px;
padding-top: 3px;
display: inline-block;
clear: left;
vertical-align: top;
}
fieldset input,
fieldset textarea {
border: 1px solid #999999;
border-radius: 5px;
padding: 2px;
margin: 0;
}
fieldset input[maxlength="255"],
fieldset textarea {
box-sizing: border-box;
width: 100%;
max-width: 760px;
}
fieldset ul {
display: inline-block;
padding: 0;
}
fieldset ul li {
list-style: none;
display: inline;
}
fieldset table {
display: inline-table;
max-width: 760px;
}
fieldset.comment {
padding: 0;
legend {margin-left: 15px}
.buttonbar {margin: 0; width: 100%}
}
h1, h2, h3, h4, h5, h6, .player {
color: #bc0a19;
font-family: 'Amerika Sans', sans-serif;
@@ -110,66 +125,57 @@ h1, h2, h3, h4, h5, h6, .player {
margin: 1em 0 0.5em 0;
text-shadow: 1px 1px 1px #888;
vertical-align: baseline;
a:link, a:visited {
color: #bc0a19;
font-weight: 400;
text-decoration: none;
}
}
ol {
list-style: cjk-ideographic;
padding-left: 2em;
}
table {
border-collapse: collapse;
border-spacing: 0;
width: 100%;
margin: 0 auto 1em auto;
td {
border-bottom: 1px solid #d3d7cf;
border-top: 1px solid #d3d7cf;
padding: 2px;
vertical-align: middle;
}
.player {
margin:0
th {
background: #a40000;
color: #fff;
padding: 2px;
vertical-align: middle;
a:link, a:visited {color: #FFF;}
}
html, div, span, applet, object, iframe, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
border: 0;
margin: 0;
padding: 0;
vertical-align: baseline;
tr:nth-child(2n+1) {background-color: #eeeeec;}
tr:hover {background-color: #eedcdc;}
}
p {
margin-bottom: 0.5em
ul {
list-style: circle outside;
padding-left: 2em;
margin:0.5em 0 0.5em 0
}
img.partner, img.posting_image {
border: 1px solid #babdb6;
display:block;
float: left;
height: 120px;
margin: 0 20px 0 0;
padding: 4px;
width: 200px;
}
img.partner:nth-of-type(odd) {
float: right;
}
input {font: normal 12pt Philosopher, sans-serif;}
input[type=number] {text-align: right;}
input[maxlength="255"] {width: 100%}
input[readonly="readonly"], input[readonly] {
border: none;
background: transparent;
color: #2e3436;
}
.cke_chrome {border:0 !important}
.cke_wysiwyg_div {padding: 1em 0 !important}
ul.info {
list-style: none;
margin: 0 0 0.5em 0;
padding-left: 0;
li {
margin-bottom: .2em;
display: inline-block;
margin-right: 1em;
}
.thumbnail {
display: block;
position: relative;
float: left;
height: 140px;
width: 140px;
padding: 5px;
border: 0;
margin: 5px;
background: transparent url('../img/thumbnail-bg.png') top left no-repeat;
}
ul.tabs {
width: 100%;
list-style: none;
@@ -205,102 +211,9 @@ ul.tabs {
}
}
}
div.tab_container {
background-color:#fff;
padding-top: 1em;
}
ol {
list-style: cjk-ideographic;
padding-left: 2em;
}
table {
border-collapse: collapse;
border-spacing: 0;
width: 100%;
margin: 0 auto 1em auto;
}
table td {
border-bottom: 1px solid #d3d7cf;
border-top: 1px solid #d3d7cf;
padding: 2px;
vertical-align: middle;
}
table th {
background: #a40000;
color: #fff;
padding: 2px;
vertical-align: middle;
}
table th a:link, table th a:visited {
color: #FFF;
}
table tr:nth-child(2n+1) {
background-color: #eeeeec;
}
table tr:hover {
background-color: #eedcdc;
}
ul {
list-style: circle outside;
padding-left: 30px;
}
ul.info {
list-style: none;
margin-bottom: 0.5em;
padding-left: 0;
}
ul.info li {
display: inline-block;
margin-right: 10px;
}
.buttonbar {
text-align: right;
border-radius: 10px;
background-color: #000000;
background: linear-gradient(to bottom, #45484d 0%,#000000 100%);
}
/** PAGINATOR **/
.pagination {
text-align:center
}
.pagination a, .pagination .current, .pagination .next, .pagination .previous {
display: inline-block;
text-decoration: none;
padding: 0 0.5em 0 0.5em;
}
.pagination .next {
float: right;
background: none;
}
.pagination .previous {
float: left;
background: none;
}
.center {
text-align: center;
}
.right {
text-align: right;
}
#bottom_buttonbar {border-radius: 0 0 10px 10px;}
#display {position:relative; text-align: center;}
#redbox {
color: white;
background-color: #a90329;
@@ -312,25 +225,106 @@ ul.info li {
h2:first-of-type {margin: -20px 0 0 10px; color: black; text-shadow: 1px 1px 1px #ffffff;}
}
.avatar {
display: block;
position: relative;
float: left;
width: 70px;
height: 70px;
padding: 0;
margin: 0 1em 1em 0;
box-shadow: 2px 2px 5px #888;
img {
height: 70px;
width: 70px;
}
}
.buttonbar {
text-align: right;
border-radius: 10px;
background-color: #000000;
background: linear-gradient(to bottom, #45484d 0%,#000000 100%);
}
.center {text-align: center;}
.clear, .clearfix {clear: both;}
.cke_chrome {border:0 !important}
.cke_wysiwyg_div {padding: 1em 0 !important}
.disabled {color: #ccc}
.comment {
display:table;
margin-bottom: 1em;
width: 100%;
padding: 0;
}
.error, ul.errorlist li {color: #a40000;}
.game h2 {margin: 0.5em 0;}
.grid_1,.grid_2,.grid_3,.grid_4,.grid_5,.grid_6,.grid_7,.grid_8,.grid_9,.grid_10,.grid_11,.grid_12
{
display: inline;
float: left;
margin: 0px 10px;
position: relative;
box-sizing: border-box;
}
.grid_1 { width: 60px;}
.grid_2 {width: 140px;}
.grid_3 {width: 220px;}
.grid_4 {width: 300px;}
.grid_5 {width: 380px;}
.grid_6 {width: 460px;}
.grid_7 {width: 540px;}
.grid_8 {width: 620px;}
.grid_9 {width: 700px;}
.grid_10 {width: 780px;}
.grid_11 {width: 860px;}
.grid_12 {width: 940px;}
fieldset.comment {
.more_link {text-align: right; clear: left;}
.pagination {
clear: both;
margin-bottom: 1em;
padding: 0;
position: relative;
text-align: center;
z-index: 30;
legend {margin-left: 15px}
.buttonbar {margin: 0; width: 100%}
.buttonbar {margin: 0; width: 100%}
a {
background-color: #000000;
background: linear-gradient(to bottom, #45484d 0%,#000000 100%);
border-radius: 5px;
display: inline-block;
font-weight: bold;
padding: 0.5em 1em;
text-decoration: none;
}
#bottom_buttonbar {
position: absolute;
border-radius: 0 0 10px 10px;
bottom: 0px;
margin: 0;
width: 100%
a:link, a:visited {color: #fff;}
a:hover, a.active {color: #bc0a19;}
a.disabled, a.disabled:hover {color: #666}
a.previous {
float:left;
border-radius: 10px 5px 5px 10px;
}
a.next {
float: right;
border-radius: 5px 10px 10px 5px;
}
}
.player {margin:0 auto; float:none}
.right {text-align: right;}
.thumbnail {
display: block;
position: relative;
float: left;
height: 140px;
width: 140px;
padding: 5px;
border: 0;
margin: 5px;
background: transparent url('../img/thumbnail-bg.png') top left no-repeat;
}

View File

@@ -1,12 +1,30 @@
@media screen and (min-width: @min-desktop-width) {
body {
position: relative;
margin: 0;
padding: 0;
min-width: 960px;
height: 100%;
}
#body {
background-color: #ffffff;
background-image: url('../img/kranich.png'), url('../img/header_bg.jpg');
background-repeat: no-repeat, no-repeat;
background-position: center bottom, center top;
background-attachment: scroll, fixed;
}
#bottom_buttonbar {
position: absolute;
bottom: 0px;
margin: 0;
width: 100%
}
#content {
width: 940px;
margin: 0px 10px;
position: relative;
}
#display .next, #display .previous {
#display .next,
#display .previous {
display: block;
position: absolute;
top: 0px;
@@ -18,50 +36,74 @@
overflow: hidden;
opacity: .5;
}
#display .next:hover, #display .previous:hover {
#display .next:hover,
#display .previous:hover {
opacity: 1;
transition: all 0.2s ease-out;
}
#display .next {
background: transparent url(../img/right-arrow.png) no-repeat center center;
right: 10px;
z-index: 3;
}
#display .previous {
background: transparent url(../img/left-arrow.png) no-repeat center center;
left: 10px;
z-index: 2
}
#display img {
box-shadow: 1px 1px 5px 1px #444;
}
#display img {box-shadow: 1px 1px 5px 1px #444;}
#footer {
width: 920px;
min-height: 50px;
margin: 20px auto 0 auto;
z-index: 30;
p {text-align: center;}
}
#footer p {text-align: center;}
#footer_kranich {
display: block;
#google_maps {
position: relative;
max-width:1250px;
width:100%;
margin:0 auto;
top: -320px;
text-align: right;
z-index: -2;
top: 0px;
left: 0px;
height: 280px;
padding: 10px;
border-radius: 0px 10px 10px 0px;
}
#jumbotron {
clear: both;
position: relative;
padding: 0;
width: 940px;
margin: 0 10px 1em 10px;
z-index: 5;
min-height: 300px;
border: none;
border-radius: 10px;
background-repeat: no-repeat;
background-color: #333;
background-position: center left;
> h2, > h1 {
color: #eff0ef;
text-shadow: 1px 1px 1px #000;
position: absolute;
top: 33%;
left: 10px;
max-width: 600px;
margin: 0;
}
#teaser_text {
display: block;
position: absolute;
left: 0px;
bottom: 0px;
width: 620px;
color: #FFF;
background: rgba(0, 0, 0, 0.5);
padding: 1em;
border-radius: 0px 0px 0px 10px;
a:link, a:active, a:visited {color: #fff; text-decoration:underline;}
}
}
#maincontent {
margin: 0 auto;
height: auto !important;
@@ -74,16 +116,14 @@
background: rgba(255, 255, 255, 0.5);
box-shadow: 0px 0px 20px 1px rgba(0, 0, 0, 0.75);
}
#messages {
clear: both;
margin: 0 auto;
padding: 8px 0 0 30px;
width: 920px;
list-style: none;
}
#messages li.success {
li.success {
color: #253324;
background: #89bd84;
border: 1px solid #253324;
@@ -91,79 +131,35 @@
margin: 10px;
padding: 10px;
}
#navigation, .pagination {
}
#navigation {
clear: both;
position: relative;
background: url(../img/navigation-bg.png) no-repeat left top;
height: 56px;
list-style: none;
margin: 0 auto;
padding: 8px 35px 0px 25px;
position: relative;
width: 900px;
z-index: 30;
a {
background: url(../img/navigation-separator.png) no-repeat right center;
color: #FFF;
display: block;
float: left;
display: inline-block;
font-weight: bold;
height: 33px;
padding: 17px 15px 0;
text-decoration: none;
}
a:hover, #navigation a.active {
a:hover, a.active {
background: url(../img/navigation-hover.png) repeat-x left top;
color: #3B3B3B;
}
li {
display: inline;
margin: 0;
li {display: inline;}
}
}
#jumbotron {
clear: both;
position: relative;
padding: 0 1px 0 0;
width: 940px;
margin: 0 10px 1em 10px;
z-index: 5;
min-height: 300px;
border: none;
border-radius: 10px;
background-repeat: no-repeat;
background-color: #333;
background-position: center left;
> h2, > h1 {
color: #eff0ef;
text-shadow: 1px 1px 1px #000;
position: absolute;
top: 33%;
left: 10px;
max-width: 600px;
margin: 0;
}
#teaser_text {
display: block;
position: absolute;
left: 0px;
bottom: 0px;
width: 620px;
color: #FFF;
background: rgba(0, 0, 0, 0.5);;
padding: 1em;
border-radius: 0px 0px 0px 10px;
}
}
#recaptcha_widget_div {margin-top: -20px;}
#redbox {
position: absolute;
top: 0px;
@@ -171,9 +167,8 @@
height: 280px;
width: 280px;
border-radius: 0px 10px 10px 0px;
z-index: 100;
}
#usernav {
position: absolute;
top: 0;
@@ -188,23 +183,28 @@
z-index: 50;
box-shadow: -1px -1px 5px 1px rgba(0, 0, 0, 0.75);
a {
color: #FFF;
}
}
#usernav img {
vertical-align: middle;
a {color: #FFF;}
}
.clearfix {
zoom: 1px;
.comment_picture {
display: table-cell;
padding: 0px 10px;
width: 60px;
vertical-align: top;
}
.clearfix:after {
clear: both;
.comment_header {
display: table-cell;
padding: 0px 10px;
width: 140px;
vertical-align: top;
}
.comment_header h3 {margin: 0}
.comment_text {
display: table-cell;
padding: 0px 10px;
width: auto;
max-width: 700px;
}
.gallery {
display: inline;
float: left;
@@ -214,221 +214,56 @@
text-align: center;
width: 300px;
}
.gallery .thumbnail {
display: block;
float: none;
margin: 5px auto;
}
div.thumbnail a.delete_image {
.game img {
float:right;
margin: 0.5em 0 0.5em 1em;
width: 300px;
height: auto;
box-shadow: 1px 1px 5px 1px #444;
}
.game:nth-child(2n+1) img {
float:left;
margin-right:1em;
margin: 0.5em 2em 0.5em 0;
}
.officer {
float:left;
width: 140px;
margin:5px;
box-sizing: border-box;
text-align: center;
img {
border: 0;
border-radius: 50%;
box-shadow: 1px 1px 5px 1px #444;
width:130px;
height:130px;
}
.function {font-size:small;margin-top: 0.25em}
}
img.posting_image, img.partner {
float: left;
width: 200px;
height: 120px;
padding: 2px;
margin: 0 1em 1em 0;
border: 1px solid #babdb6;
}
.thumbnail a.delete_image {
position: absolute;
right: 4px;
bottom: 0px;
}
#body {
background-color: #ffffff;
background-image: url('../img/kranich.png'), url('../img/header_bg.jpg');
background-repeat: no-repeat, no-repeat;
background-position: center bottom, center top;
background-attachment: scroll, fixed;
}
body {
font: 12pt Philosopher, Georgia, serif;
line-height: 1;
position: relative;
margin: 0;
height: 100%;
min-width: 960px;
padding: 0;
vertical-align: baseline;
}
fieldset {
border: none;
color: #2e3436;
border-radius: 10px;
margin: 10px 0 0 0;
padding: 0 10px 0 160px;
background-color: #f2f5f6;
background: linear-gradient(135deg, #f2f5f6 0%, #e3eaed 37%, #c8d7dc 100%);
vertical-align: top;
}
fieldset legend {
margin-top: -.1em;
margin-left: -150px;
color: #a40000;
font-family: 'Amerika Sans', sans-serif;
font-variant: small-caps;
font-weight: 400;
font-size: 16pt;
text-shadow: 2px 2px 2px #888;
}
fieldset div {
margin: 5px 0px;
}
fieldset .required {
font-weight: bold;
}
fieldset .buttonbar {
border-radius: 0px 0px 10px 10px;
margin: 0 -10px 0 -160px;
}
fieldset .help_text {
font-size: small;
}
fieldset .field_name {
text-align: right;
width: 140px;
margin: 0 20px 0 -160px;
padding-top: 3px;
display: inline-block;
clear: left;
vertical-align: top;
}
fieldset input, fieldset textarea {
border: 1px solid #999999;
border-radius: 5px;
padding: 2px;
margin: 0;
}
fieldset input[maxlength="255"], fieldset textarea {
box-sizing: border-box;
width: 100%;
max-width: 760px;
}
fieldset ul {
display: inline-block;
padding: 0;
}
fieldset ul li {
list-style: none;
display: inline;
}
fieldset table {
display: inline-table;
max-width: 760px;
}
img.partner, img.partner_right, img.posting_image {
border: 1px solid #babdb6;
float: left;
height: 120px;
margin: 0 20px 0 0;
padding: 4px;
width: 200px;
}
img.partner:nth-of-type(odd) {
float: right;
}
.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;
width: 60px;
height: 60px;
}
.comment_picture {
display: table-cell;
padding: 0px 10px;
width: 60px;
vertical-align: top;
}
.comment_header {
display: table-cell;
padding: 0px 10px;
width: 140px;
vertical-align: top;
}
.comment_header h3 {
margin: 0
}
.comment_text {
display: table-cell;
padding: 0px 10px;
width: auto;
max-width: 700px;
}
.userinfo {
width: 140px;
}
.grid_6 {
width: 460px;
}
.grid_7 {
width: 540px;
}
.grid_8 {
width: 620px;
}
.grid_9 {
width: 700px;
}
.grid_10 {
width: 780px;
}
.grid_11 {
width: 860px;
}
.grid_12 {
width: 940px;
}
#recaptcha_widget_div {
margin-top: -20px;
}
#google_maps {
position: relative;
top: 0px;
left: 0px;
height: 280px;
padding: 10px;
border-radius: 0px 10px 10px 0px;
}
}

View File

@@ -1,6 +1,6 @@
@media screen and (min-width: @min-desktop-width) {
#siteheader {
min-height: 100px;
min-height: 110px;
width: 960px;
margin: 0 auto;
padding: 0;
@@ -33,17 +33,17 @@
#mainnav {
left: 233px;
position: absolute;
top: 65px;
bottom: 0px;
#toggle, .toggle {display: none;}
> ul.main_menu {
padding: 0px;
position:relativ;
ul.main_menu {
list-style:none;
margin:0;
padding: 0;
> li {
display: block;
float: left;
display: inline-block;
min-width: 50px;
padding: 8px;
font: normal small-caps 18px 'Amerika Sans', sans-serif;
@@ -70,17 +70,16 @@
display: none;
background:rgba(255, 255, 255, 0.8);
border-radius: 10px;
padding: 10px 0;
padding: 0.25em;
min-width: 10em;
position: absolute;
top: 30px;
margin-left: -10px;
top: 100%;
margin: 0 0 0 -15px;
box-shadow: -1px 1px 5px 0px rgba(0,0,0,0.75);
transition: all 0.25s linear;
li {
display:block;
padding:2px;
float: none;
font: normal small-caps 14pt 'Amerika Sans', sans-serif;
text-align: left;
@@ -89,14 +88,14 @@
li a {
display:block;
color: black;
padding: 0.5em 0.25em;
padding: 5px;
transition: all 0.25s linear;
border-radius: 0.5em;
}
li a:hover {
color: white;
background: #bc0a19;
background: linear-gradient(135deg, #6d0019 0%, #8f0222 44%, #a90329 100%);
background: linear-gradient(135deg, #a90329 0%,#8f0222 44%,#6d0019 100%);
transition: all 0.25s linear;
}
}

View File

@@ -1,9 +1,31 @@
@min-desktop-width: 700px;
@max-mobile-with: 699px;
@import "font-awesome/path.less";
@import "font-awesome/variables.less";
@import "common";
@import "desktop";
@import "mobile";
@import "header_nav";
@media screen and (max-width: @max-mobile-with) {
@import "mobile";
}
@media screen and (min-width: @min-desktop-width) {
@import "desktop";
}
@page {
margin: 1cm 1cm 1cm 2cm;
size: A4 portrait;
}
@media print {
@import "print";
@import "font-aweseome/font-awesome";
}
@import "font-awesome/core.less";
@import "font-awesome/larger.less";
@import "font-awesome/fixed-width.less";
@import "font-awesome/list.less";
@import "font-awesome/icons.less";

View File

@@ -1,19 +1,44 @@
@media screen and (max-width: @max-mobile-with) {
body {
margin: 5px 10px;
background: url('../img/background_mobile.png') no-repeat top center;
background-attachment: fixed;
font: 12pt "Philosopher", Georgia, serif;
}
img {
max-width: 100%;
height: auto;
}
img.thumbnail {
display: block;
float: left;
height: 70px;
width: 70px;
margin: 5px;
box-shadow: 2px 2px 5px #888;
}
img.posting_image, img.partner {
float: left;
width: 99px;
height: 59px;
padding: 2px;
margin: 1em 0.5em 0 0;
border: 1px solid #babdb6;
}
ul.main_dropdown {
list-style-type: none;
margin: 0;
padding: 0;
li {padding: 0;}
a {padding-left: 2em; font-size: 12pt;}
}
#display .grid_10 {
margin: 0;
position: relative;
z-index: 1
}
#display .next, #display .previous {
display: block;
position: absolute;
@@ -26,62 +51,46 @@
overflow: hidden;
opacity: .5;
}
#display .next:hover, #display .previous:hover {
opacity: .9;
transition: all 0.2s ease-out;
}
#display .next {
background: transparent url(../img/right-arrow.png) no-repeat center center;
right: 0px;
z-index: 3;
}
#display .previous {
background: transparent url(../img/left-arrow.png) no-repeat center center;
left: 0px;
z-index: 2
}
#footer {
border-top: 1px solid black;
text-align: center;
}
img.posting_image, img.partner {
float: left;
width: 99px;
height: 59px;
padding: 2px;
margin: 1em 0.5em 0 0;
border: 1px solid #babdb6;
#jumbotron {background: none !important;}
#maincontent {width: 100%;}
#mainnav {display: block; float: right}
#navigation {
margin: 10px 0;
padding: 0;
background: #45484d url("../img/navigation-mobile.png") top left repeat-x;
background-size: contain;
}
img {
max-width: 100%;
height: auto;
}
#topnav a {
display: inline-block;
color: #000;
font: 400 small-caps 24pt 'Amerika Sans', sans-serif;
min-width: 80px;
text-align: center;
text-decoration: none;
text-shadow: 2px 2px 2px #2e3436;
padding: 5px;
}
#topnav a.active {
color: #bc0a19;
}
#topnav a:hover {
#navigation a {
font: bold 12px Arial;
color: #FFF;
text-decoration: none;
}
#navigation li {
display: inline-block;
padding: 0.5em 0.3em 0.5em 0.5em;
text-align: center;
border-left: 1px solid #ffffff;
margin: 0;
}
#navigation li:first-of-type {border: none;}
#sitelogo {
background: url('../img/logo_mobile.png') no-repeat;
width: 114px;
@@ -94,77 +103,45 @@
z-index: 20;
float: left;
}
#teaser {
background: none;
margin-bottom: 1em;
}
#teaser_text {
background: rgba(255, 255, 255, 0.5);
}
#navigation {
margin: 10px 0;
padding: 0;
background: #45484d url("../img/navigation-mobile.png") top left repeat-x;
background-size: contain;
}
#navigation li {
display: inline-block;
padding: 0.5em 0.3em 0.5em 0.5em;
text-align: center;
border-left: 1px solid #ffffff;
margin: 0;
}
#navigation li:first-of-type {
border: none;
}
#navigation a {
font: bold 12px Arial;
color: #FFF;
text-decoration: none;
}
#sitelogo a {
display: block;
width: 114px;
height: 54px;
}
#siteheader:after {
content: ".";
content: "";
clear: both;
display: block;
visibility: hidden;
height: 0px;
}
#maincontent {
width: 100%;
}
/* Dynamische Menü */
#mainnav {
#redbox {
margin-top: 1em;
display: block;
float: right
}
#toggle, .toggle {
display: none;
#teaser {
background: none;
margin-bottom: 1em;
}
#teaser_text {background: rgba(255, 255, 255, 0.5);}
#topnav a {
display: inline-block;
color: #000;
font: 400 small-caps 24pt 'Amerika Sans', sans-serif;
min-width: 80px;
text-align: center;
text-decoration: none;
text-shadow: 2px 2px 2px #2e3436;
padding: 5px;
}
#topnav a.active {color: #bc0a19;}
#topnav a:hover {color: #FFF;}
#toggle, .toggle {display: none;}
#toggle:checked ~ .main_menu {
display: block;
opacity: 1;
}
#toggle:checked ~ .toggle, .toggle:hover {
background: #45ABD6;
}
#toggle:checked ~ .toggle, .toggle:hover {background: #45ABD6}
.comment_picture {
display: table-cell;
@@ -172,28 +149,68 @@
width: 60px;
vertical-align: top;
}
.comment_header {
display: table-cell;
padding: 0px 10px;
width: 140px;
vertical-align: top;
}
.comment_header h3 {
margin: 0
}
.toggle {
z-index: 2;
.comment_header h3 {margin: 0}
.comment {display: block}
.comment_picture {
display: block;
position: relative;
cursor: pointer;
-webkit-touch-callout: none;
-webkit-user-select: none;
user-select: none;
float: left;
vertical-align: top;
width: 60px;
}
.comment_header {
display: block;
float: left;
padding: 0px 10px;
vertical-align: top;
width: 140px;
}
.comment_header h3 {margin: 0}
.comment_text {
border-top: 1px solid #45484d;
display: block;
margin: 0px 10px;
padding-top: 0.5em;
clear: both;
}
.gallery {
float: left;
width: 150px;
height: 150px;
margin: 10px;
}
.gallery h3 {font-size: 12pt;}
.game img {
float:right;
margin: 0.5em 0 0.5em 1em;
width: 140px;
height: auto;
box-shadow: 1px 1px 5px 1px #444;
}
.game:nth-child(2n+1) img {
float:left;
margin-right:1em;
margin: 0.5em 2em 0.5em 0;
}
.grid_2 {
min-width: 140px;
width:31%;
margin: 1% 0 1% 0;
}
.grid_3 {
width:48%;
margin: 1% 0 1% 0;
}
.grid_4, .grid_5, .grid_6, .grid_7, .grid_8, .grid_9, .grid_10, .grid_11, .grid_12 {
clear: both;
margin:0;
width: 100%;
}
.main_menu {
position: absolute;
display: none;
@@ -231,58 +248,36 @@
border-left: 3px solid #a40000;
}
}
ul.main_dropdown {
list-type: none;
margin: 0;
padding: 0;
li {padding: 0;}
a {padding-left: 2em; font-size: 12pt;}
}
#jumbotron {
background: none !important;
}
#redbox {
margin-top: 1em;
display: block;
}
.grid_6, .grid_7, .grid_8, .grid_9, .grid_10, .grid_11, .grid_12 {
width: 100%;
clear: both;
}
.player {
display: inline;
.officer {
float:left;
margin-left: 10px;
margin-right: 10px;
position: relative;
width: 25%;
padding:5px;
box-sizing: border-box;
-moz-box-sizing: border-box;
min-width: 60px;
text-align: center;
img {
border: 0;
border-radius: 50%;
box-shadow: 1px 1px 5px 1px #444;
width:100%;
height:100%;
}
.function {font-size:small;margin-top: 0.25em}
}
.toggle {
background: #a40000;
border-radius: 5px;
color: #FFFFFF;
cursor: pointer;
display: block;
width: 150px;
margin: 8px 0;
padding: 10px;
background: #a40000;
text-align: center;
color: #FFFFFF;
content: 'Main Menu';
border-radius: 2px;
box-sizing: border-box;
position: relative;
transition: all 0.5s linear;
/*user-select: none;*/
z-index: 2;
}
.thumbnail {
display: block;
position: relative;
@@ -292,152 +287,9 @@ ul.main_dropdown {
width: 70px;
margin: 5px;
box-shadow: 2px 2px 5px #888;
}
.thumbnail img {
img {
height: 70px;
width: 70px;
}
.thumbnail a.delete_image {
display: none
}
img.thumbnail {
display: block;
float: left;
height: 70px;
width: 70px;
margin: 5px;
box-shadow: 2px 2px 5px #888;
}
fieldset {
border: none;
color: #2e3436;
border-radius: 10px;
margin: 10px 0 0 0;
padding: 0 10px 0 160px;
background: #f2f5f6; /* Old browsers */
background: linear-gradient(135deg, #f2f5f6 0%, #e3eaed 37%, #c8d7dc 100%);
background: -moz-linear-gradient(-45deg, #f2f5f6 0%, #e3eaed 37%, #c8d7dc 100%);
background: -webkit-gradient(linear, left top, right bottom, color-stop(0%, #f2f5f6),
color-stop(37%, #e3eaed), color-stop(100%, #c8d7dc));
background: -webkit-linear-gradient(-45deg, #f2f5f6 0%, #e3eaed 37%, #c8d7dc 100%);
background: -o-linear-gradient(-45deg, #f2f5f6 0%, #e3eaed 37%, #c8d7dc 100%);
background: -ms-linear-gradient(-45deg, #f2f5f6 0%, #e3eaed 37%, #c8d7dc 100%);
}
fieldset legend {
margin-top: -.1em;
margin-left: -150px;
color: #a40000;
font-family: 'Amerika Sans', sans-serif;
font-variant: small-caps;
font-weight: 400;
font-size: 16pt;
text-shadow: 2px 2px 2px #888;
}
fieldset .required {
font-weight: bold;
}
fieldset .error {
color: #a40000
}
fieldset .buttonbar {
border-radius: 0px 0px 10px 10px;
margin: 0 -10px 0 -160px;
}
fieldset .help_text {
font-size: small;
}
fieldset .field_name {
text-align: right;
width: 140px;
margin: 0 20px 0 -160px;
padding-top: 3px;
display: inline-block;
clear: left;
}
fieldset input, fieldset textarea {
border: 1px solid #999999;
border-radius: 5px;
padding: 2px;
margin: 0;
font-size: 12pt;
}
fieldset input[maxlength="255"], fieldset textarea {
width: 99%;
box-sizing: border-box;
}
fieldset ul {
display: inline-block;
padding: 0;
}
fieldset ul li {
list-style: none;
display: inline;
}
.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;
}
.comment {
display: block
}
.comment_picture {
display: block;
float: left;
vertical-align: top;
width: 60px;
}
.comment_header {
display: block;
float: left;
padding: 0px 10px;
vertical-align: top;
width: 140px;
}
.comment_header h3 {
margin: 0
}
.comment_text {
border-top: 1px solid #45484d;
display: block;
margin-left: 0px 10px;
padding-top: 0.5em;
clear: both;
}
}

View File

@@ -1,33 +1,31 @@
@media print {
@page {
size: portrait;
margin: 0.5cm 0.5cm 0.5cm 1cm;
orphans: 3;
widows: 3;
a:link, a:visited {color: black; font-weight: bold;}
body, article {
width: 100%;
margin: 0;
padding: 0;
color: #000;
background: #fff;
}
nav, aside, #comment_form, #navigation, #mainnav, #usernav, #bottom_buttonbar, #footer > form {
display: none !important;
h1 {font-size: 32pt;}
h2, h3, h4, h5, h6 {
text-shadow: none;
page-break-after: avoid;
}
img {
max-width: 100% !important;
page-break-inside: avoid;
}
nav, aside {display: none;}
ul {page-break-inside: avoid;}
#footer {
width: 100%;
padding-top: 0.5em;
border-top: 1px solid black;
text-align: center;
}
* {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
a:link, a:visited {
color: black;
font-weight: bold;
}
#jumbotron {background: none !important;}
#maincontent nav {display: none}
#maincontent aside {display: none}
#sitelogo {
background: url(../img/logo.png) top right no-repeat;
background-size: contain;
@@ -40,52 +38,8 @@
top: 5px;
z-index: 99;
}
#comment_form, #comments, #footer, #navigation, #mainnav,
#usernav, #bottom_buttonbar, #footer > form {display: none;}
#jumbotron {
background: none !important;
}
body, article {
width: 100%;
margin: 0;
padding: 0;
color: #000;
background: #fff;
}
h1 {
font-size: 32pt;
}
h2, h3, h4, h5, h6 {
text-shadow: none;
page-break-after: avoid;
}
img {
max-width: 100% !important;
}
ul, img {
page-break-inside: avoid;
}
#comment_form, #comments, #footer, #navigation, #mainnav, #usernav, #bottom_buttonbar, #footer > form {
display: none;
}
.more_link {
display: none
}
#maincontent nav {
display: none
}
#maincontent aside {
display: none
}
.grid_6, grid_7, .grid_8, grid_9, .grid_10, .grid_11, .grid_12 {
width: 100%
}
}
.grid_6, grid_7, .grid_8, grid_9, .grid_10, .grid_11, .grid_12 {width: 100%}
.more_link {display: none}

View File

@@ -15,15 +15,28 @@
document.createElement('aside');
document.createElement('footer');
document.createElement('hgroup');
</script>
<![endif]-->
<link rel="stylesheet" href="{{STATIC_URL}}css/kasu.css">
<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' %}"/>
<link rel="shortcut icon" href="{{STATIC_URL}}img/favicon.ico">
<link rel="stylesheet" href="{{STATIC_URL}}css/kasu.css">
<link rel="apple-touch-icon" sizes="57x57" href="{{STATIC_URL}}img/apple-touch-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="{{STATIC_URL}}img/apple-touch-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="{{STATIC_URL}}img/apple-touch-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="{{STATIC_URL}}img/apple-touch-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="{{STATIC_URL}}img/apple-touch-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="{{STATIC_URL}}img/apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="{{STATIC_URL}}img/apple-touch-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="{{STATIC_URL}}img/apple-touch-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="{{STATIC_URL}}img/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" href="{{STATIC_URL}}img/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="{{STATIC_URL}}img/android-chrome-192x192.png" sizes="192x192">
<link rel="icon" type="image/png" href="{{STATIC_URL}}img/favicon-96x96.png" sizes="96x96">
<link rel="icon" type="image/png" href="{{STATIC_URL}}img/favicon-16x16.png" sizes="16x16">
<link rel="mask-icon" href="{{STATIC_URL}}img/safari-pinned-tab.svg" color="#5bbad5">
{% block opengraph %}
<meta property="og:type" content="website"/>
<meta property="og:title" content="Kasu - Verein Japanische Spielekultur"/>
@@ -37,7 +50,7 @@
<div id="sitelogo"><a href="/index.html">Kasu - traditionelle asiatische Spielkultur</a></div>
<nav id="mainnav">
<input type="checkbox" id="toggle" aria-hidden="true" />
<label for="toggle" class="toggle" onclick aria-hidden="true">{% trans "Menu" %}</label>
<label for="toggle" class="toggle" onclick aria-hidden="true"><span class="fa fa-bars"></span> {% trans "Menu" %}</label>
<ul class="main_menu">
{% for item in top_menu_items %}
<li><a href="{{item.get_absolute_url}}" title="{{ item.title }}"
@@ -55,14 +68,10 @@
<main id="maincontent">
<header id="jumbotron"
style="background-image: url('{% block jumbotron_background %}{{STATIC_URL}}img/teaser/{{current_top_page.slug|default:'jumbotron'}}.jpg{% endblock %}')">
{% block teaser %}
<h1>{% if title %}{{title}}{% elif current_page %}{{ current_page.title }}{% elif current_top_page %}{{current_top_page.title }}{% endif %}</h1>
{% endblock %}
<aside id="redbox">
{% block redbox %}
{% if current_event %}
<h2>{% trans "Current Event" %}</h2>
<h3>{{ current_event.name}}</h3>
<ul class="fa-ul">
<li><span class="fa-li fa fa-clock-o"></span><strong>{% trans "Since" %}:</strong> {{current_event.start|timesince}}</li>
@@ -75,9 +84,7 @@
{% trans "More Details" %} <span class="fa fa-arrow-right"></span></a></div>
{% else %}
<h2>{% trans "Next Event" %}</h2>
<h3>{{ next_event.name}}</h3>
<ul class="fa-ul">
<li><span class="fa-li fa fa-clock-o"></span><strong>{% trans "in" %}:</strong> {{next_event.start|timeuntil}}</li>
<li><span class="fa-li fa fa-calendar"></span><strong>{% trans "Start" %}:</strong>
@@ -93,11 +100,17 @@
</h3>
<ul class="fa-ul">
{% for event in upcoming_events %}
<li><span class="fa-li fa fa-calendar-o"></span> {{event.start|date:'d. M:'}} <a href="{{ event.get_absolute_url}}">{{event.name}}</a></li>
<li><span class="fa-li fa fa-calendar-o"></span>
<a href="{{ event.get_absolute_url}}">
<time datetime="{{event.start|date:'c'}}">{{event.start|date:'D d. M:'}}</time>
{{event.name}}</a></li>
{% endfor %}
</ul>
{% endblock %}
</aside>
{% block teaser %}
<h1>{% if title %}{{title}}{% elif current_page %}{{ current_page.title }}{% elif current_top_page %}{{current_top_page.title }}{% endif %}</h1>
{% endblock %}
</header>
{% block navigation %}{% if current_top_page.subpages.count %}
<ul id="navigation">
@@ -145,7 +158,7 @@
</main>
<footer id="footer">
<p><strong>Herausgeber:</strong> Verein Kasu - traditionelle asiatische Spielkultur (<a
href="/verein/impressum.html">{% trans "Imprint" %}</a> &ndash; <a
href="/about.html#impressum">{% 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>

View File

@@ -1,4 +1,4 @@
{% load comments i18n %}
{% load comments i18n thumbnail %}
<form action="{% comment_form_target %}" method="post" id='comment_form' class="grid_12">
{% csrf_token %}
<fieldset class="comment">
@@ -10,10 +10,10 @@
<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.thumbnail %}{{user.thumbnail.url}}{% else %}{{STATIC_URL}}img/unknown_thumbnail.png{% endif %}"
width="60" height="60"
alt=""/></div>
src="{% thumbnail user.avatar|default:'unknown_profile.jpg' 'avatar' %}"
width="70" height="70" alt=""/></div>
<header class="comment_header">
<h3><a href="{{ user.get_profile.get_absolute_url }}" class="user">{{user}}</a></h3>
@@ -28,9 +28,8 @@
{% else %}
<div class="comment">
<div class="comment_picture"><img class="avatar"
src="{{STATIC_URL}}img/unknown_thumbnail.png"
width="60" height="60"
alt=""/></div>
src="{% thumbnail user.avatar|default:'unknown_profile.jpg' 'avatar' %}"
width="70" height="70" alt=""/></div>
<header class="comment_header">
<h3>{% trans "not logged in" %}</h3>
</header>

View File

@@ -1,18 +1,14 @@
{% load i18n django_markdown %}
{% load i18n thumbnail %}
<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=""/>
<img class="avatar" src="{% thumbnail comment.user.avatar|default:'unknown_profile.jpg' 'avatar' %}" 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>
<div class="comment_text">{{comment.comment}}</div>
</article>
{% endfor %}

View File

@@ -1,5 +1,5 @@
{% extends "base.html" %}
{% load i18n django_markdown %}
{% load i18n thumbnail %}
{% block title %}{% trans "Preview your comment" %}{% endblock %}
@@ -11,17 +11,14 @@
{% else %}
<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=""/>
<img class="avatar" src="{% thumbnail user.avatar|default:'unknown_profile.jpg' 'avatar' %}"
width="70" height="70" alt="{{ comment.user }}"/>
</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>
<div class="comment_text">{{comment}}</div>
</article>
{% endif %}

View File

@@ -1,9 +1,10 @@
{{ form.media }}
{% for hidden in form.hidden_fields %}{{ hidden }}{% endfor %}
{% for field in form.visible_fields %}
<div>
<label for="{% if field.html_name == 'recaptcha' %}recaptcha_response_field{% else %}id_{{ field.html_name}}{% endif %}" class="field_name {{ field.css_classes }}">{{ field.label }}</label>
<label {% if field.html_name != 'recaptcha' %}for="id_{{ field.html_name}}"{% endif %} 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,5 +1,5 @@
{% extends "base.html" %}
{% load i18n comments%}
{% load i18n comments thumbnail %}
{% block title %}{% trans 'traditional Asian game culture' %}{% endblock %}
@@ -10,7 +10,8 @@
{% block maincontent %}
<div class="grid_8">
{% for article in recent_article_list %}{% get_comment_count for article as comment_count %}
{% 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>
@@ -24,7 +25,9 @@
{% trans "Comments" %}</a></li>
</ul>
</header>
<a href="{{article.get_absolute_url}}"><img src="{{article.posting_image.url}}" alt="{{article.category}}:"
<a href="{{article.get_absolute_url}}">
<img src="{{article.get_image|thumbnail_url:'article'}}" alt="{{article.category}}:"
class="posting_image" width="200" height="120"/></a>
{{article.content|truncatewords_html:50}}
<footer class="more_link"><a href="{{article.get_absolute_url}}" class="button">{% trans "Read More"%} <span class="fa fa-arrow-right"></span></a></footer>
@@ -56,12 +59,10 @@
<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" width="78" height="78"></a>
<a href="https://twitter.com/KasuAustria"><img src="{{STATIC_URL}}img/twitter.png" alt="Twitter"
title="{% trans 'Visit us on' %} Twitter" width="78" height="78"></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+" width="78" height="78"></a>
<a href="https://www.facebook.com/Kasu.at"><span class="fa fa-facebook fa-5x" title="{% trans 'Visit us on' %} Facebook"></span></a>
<a href="https://twitter.com/KasuAustria"><span
class="fa fa-twitter fa-5x"
title="{% trans 'Visit us on' %} Twitter"></span></a>
</p>
</section>

View File

@@ -1,22 +1,15 @@
{% load i18n %}
<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 %}
<nav class="grid_12 pagination">
<a {% if page_obj.has_previous %}class="previous" href="?page={{ page_obj.previous_page_number }}"{% else %}class="previous disabled" {% endif %}>
<span class="fa fa-arrow-left"></span>{% trans "Previous" %}
</a>
{% for page in paginator.page_range %}
{% ifequal page_obj.number page %}
<div class="current">{{page}}</div>
{% else %}
<a href="?page={{page}}">{{page}}</a>
{% endifequal %}
<a {% ifequal page_obj.number page %}class="active"{% else %}href="?page={{page}}"{% endifequal %}>{{page}}</a>
{% 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>
<a {% if page_obj.has_next %}class="next" href="?page={{ page_obj.next_page_number }}"{% else %}class="next disabled"{% endif %}>
{% trans "Next" %} <span class="fa fa-arrow-right"></span>
</a>
</nav>

View File

@@ -17,39 +17,43 @@ urlpatterns = patterns(
url(r'^404/$', TemplateView.as_view(template_name='404.html')),
url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
url(r'^admin/', include(admin.site.urls)),
url(r'^ckeditor/', include('ckeditor.urls')),
url(r'^ckeditor/', include('ckeditor_uploader.urls')),
url(r'^comments/', include('django_comments.urls')),
url(r'^content/', include('content.urls')),
url(r'^events/', include('events.urls')),
url(r'^events.ics$', EventListIcal.as_view(), name='events-ical'),
url(r'^feeds/latest/$', LatestNews(), name='feed-latest-news'),
url(r'^feeds/comments/$', LatestComments(), name='feed-latest-comments'),
url(r'^gallery/', include('gallery.urls')),
url(r'^google25dabc1a49a9ef03.html$', TemplateView.as_view(template_name='google25dabc1a49a9ef03.html')),
url(r'^gallery/', include('events.gallery_urls')),
url(r'^google25dabc1a49a9ef03.html$', TemplateView.as_view(
template_name='google25dabc1a49a9ef03.html')),
url(r'^grappelli/', include('grappelli.urls')),
url(r'^i18n/', include('django.conf.urls.i18n'), name='start-page'),
url(r'^index.html$', StartPage.as_view()),
url(r'^markdown/', include('django_markdown.urls')),
url(r'^membership/', include('membership.urls')),
url(r'^news/', include('content.news_urls')),
url(r'^ranking/', include('mahjong_ranking.urls')),
url(r'^ranking/', include('maistar_ranking.urls')),
url(r'^robots.txt$', TemplateView.as_view(template_name='robots.txt')),
url(r'^users/$', MembershipDetail.as_view(), name='membership-details'),
url(r'^users/(?P<username>[\-\.\d\w]+)/$', MembershipDetail.as_view(), name='membership-details'),
url(r'^users/(?P<username>[\-\.\d\w]+)/$',
MembershipDetail.as_view(), name='membership-details'),
)
if settings.DEBUG:
urlpatterns += patterns('',
url(r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT}),
url(r'^media/(?P<path>.*)$', 'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT}),
)
if 'rosetta' in settings.INSTALLED_APPS:
urlpatterns += patterns('', url(r'^rosetta/', include('rosetta.urls')),)
urlpatterns += patterns('', url(r'^rosetta/',
include('rosetta.urls')),)
if 'debug_toolbar' in settings.INSTALLED_APPS:
import debug_toolbar
urlpatterns += patterns('', url(r'^__debug__/', include(debug_toolbar.urls)),)
urlpatterns += patterns('', url(r'^__debug__/',
include(debug_toolbar.urls)),)
urlpatterns += patterns('',
url(r'^add_page/(?P<path>[\+\.\-\d\w\/]+)/$',
@@ -58,5 +62,6 @@ urlpatterns += patterns('',
PageEditForm.as_view(), name='edit-page'),
url(r'^(?P<path>[\-\d\w\/]+)\.html$',
PageHtml.as_view(), name='view-page'),
url(r'^(?P<path>[\-\d\w\/]+)\.pdf$', PagePdf.as_view()),
url(r'^(?P<path>[\-\d\w\/]+)\.pdf$',
PagePdf.as_view()),
)

View File

@@ -273,13 +273,16 @@ STATUS_CHOICES = (
)
USER_MODEL = get_user_model()
class OverwriteStorage(FileSystemStorage):
def get_available_name(self, name):
"""
Returns a filename that's free on the target storage system, and
available for new content to be written to.
"""
# If the filename already exists, remove it as if it was a true file system
# If the filename already exists, remove it as if it was a true file
# system
if self.exists(name):
os.remove(os.path.join(settings.MEDIA_ROOT, name))
return name

View File

@@ -14,5 +14,3 @@ os.environ['DJANGO_SETTINGS_MODULE'] = 'kasu.settings.production'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

View File

@@ -24,7 +24,8 @@ def recalculate(modeladmin, request, queryset):
set_dirty(user=kyu_dan_ranking.user_id)
elif isinstance(modeladmin, SeasonRankingAdmin):
for ladder_ranking in queryset:
set_dirty(user=ladder_ranking.user_id, season=ladder_ranking.season)
set_dirty(user=ladder_ranking.user_id,
season=ladder_ranking.season)
recalculate.short_description = _("Recalculate")
@@ -41,6 +42,7 @@ def unconfirm(modeladmin, request, queryset):
hanchan.save()
unconfirm.short_description = _('Set unconfirmed')
class EventRankingAdmin(admin.ModelAdmin):
list_filter = ['event']
list_display = ('placement', 'user', 'event', 'avg_placement', 'avg_score',
@@ -84,7 +86,7 @@ class KyuDanAdmin(admin.ModelAdmin):
'classes': ('grp-collapse grp-open',),
}),
('Frühere Aufzeichnungen', {
'fields': ('legacy_date', ('legacy_kyu_points', 'legacy_dan_points')),
'fields': ('legacy_date', 'legacy_hanchan_count', ('legacy_kyu_points', 'legacy_dan_points')),
'classes': ('grp-collapse grp-closed',),
}),
)

View File

@@ -24,10 +24,10 @@ class HanchanForm(forms.ModelForm):
class Meta(object):
model = models.Hanchan
fields = ('start',
'player1', 'player1_input_score',
'player2', 'player2_input_score',
'player3', 'player3_input_score',
'player4', 'player4_input_score',
'player1', 'player1_input_score', # 'player1_comment',
'player2', 'player2_input_score', # 'player2_comment',
'player3', 'player3_input_score', # 'player3_comment',
'player4', 'player4_input_score', # 'player4_comment',
'comment')
widgets = {'event': forms.HiddenInput(),
'comment': forms.widgets.Textarea(attrs={'rows': 4, 'cols': 40})
@@ -37,31 +37,19 @@ class HanchanForm(forms.ModelForm):
super(HanchanForm, self).__init__(*args, **kwargs)
# self.fields['event'].widget.attrs['disabled'] = True
for i in xrange(1, 4):
self.fields['player%d_input_score' % i].widget.attrs['size'] = 6
self.fields['player%d_input_score' % i].widget.attrs['type'] = 'number'
player_input_score = 'player%d_input_score' % i
self.fields[player_input_score].widget.attrs['size'] = 6
self.fields[player_input_score].widget.attrs['type'] = 'number'
'''
def clean_start(self):
u"""Das Datum darf nicht in der Zukunft liegen und es muss innerhalb
der Dauer des Events liegen."""
start = self.cleaned_data['start']
event = self.cleaned_data['event']
if start > timezone.now():
raise django.forms.ValidationError(
_("It's not allowed to enter future games."))
if not event.start <= start <= event.end:
raise django.forms.ValidationError(
_("Only games running during this event are allowed."))
return start
'''
class HanchanAdminForm(HanchanForm):
class Meta(object):
model = models.Hanchan
fields = HanchanForm.Meta.fields + ('confirmed',)
class SeasonSelectForm(django.forms.Form):
season = django.forms.ChoiceField(label='', choices=('a', 'b', 'c'))

View File

@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: kasu.mahjong_ranking\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-22 23:28+0200\n"
"PO-Revision-Date: 2015-08-22 15:09+0100\n"
"Last-Translator: Christian Berg <xeniac@posteo.at>\n"
"PO-Revision-Date: 2015-09-06 00:13+0200\n"
"Last-Translator: Christian Berg <xeniac.at@gmail.com>\n"
"Language-Team: Kasu <verein@kasu.at>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
@@ -375,7 +375,7 @@ msgstr "%s wurde erfolgreich aktualisiert."
#: views.py:96
#, python-format
msgid "%s has been added successfully. You can now add a new one."
msgstr "%s wurde erfolgreich hinzugefügt. Du kannst eine neue anlagen."
msgstr "%s wurde erfolgreich hinzugefügt. Du kannst eine neue eintragen."
#: views.py:113 views.py:129
msgid "Event does not exist"

View File

@@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
"""
Export Mahjong Rankings...
"""
from operator import itemgetter
from django.core.management.base import BaseCommand
from mahjong_ranking.models import SeasonRanking
from openpyxl import Workbook
class Command(BaseCommand):
help = "Exports the SeasonRankings"
def geneate_seasonexcel(self, json_data):
wb = Workbook()
worksheet = wb.active
worksheet.append([
'Rang', 'Spitzname',
'⌀ Platz', '⌀ Punkte',
'Hanchans', 'Gut', 'Gewonnen'
])
json_data = json_data.values()
json_data = sorted(json_data, key=itemgetter('placement'))
for row in json_data:
print row
worksheet.append([
row['placement'], row['username'],
row['avg_placement'], row['avg_score'],
row['hanchan_count'],
row['good_hanchans'], row['won_hanchans']
])
wb.save("sample.xlsx")
def handle(self, *args, **options):
season_json = SeasonRanking.objects.json_data()
self.geneate_seasonexcel(season_json)

View File

@@ -85,7 +85,6 @@ class Command(BaseCommand):
self.add_players(hanchan)
hanchan.save()
def handle(self, *args, **options):
num_hanchans = int(options.get('hanchans', 4))
self.user_list = list(auth.get_user_model().objects.all())
@@ -93,5 +92,3 @@ class Command(BaseCommand):
for event in Event.objects.all():
for i in range(random.randrange(2, 8)):
self.create_hanchan(event)

View File

@@ -1,11 +1,11 @@
__author__ = 'christian'
from datetime import date
from django.db import models
class HanchanManager(models.Manager):
use_for_related_fields = True
def confirmed_hanchans(self, user=None, **kwargs):
@@ -77,3 +77,25 @@ class SeasonRankingManager(models.Manager):
def season_list(self):
values_list = self.model.objects.values_list('season', flat=True)
return values_list.order_by('season').distinct()
def json_data(self, season=None):
season = season or date.today().year
json_data = {}
values = self.filter(season=season, placement__isnull=False)
values = values.values('placement', 'user_id', 'user__username',
'user__first_name', 'user__last_name', 'avg_placement', 'avg_score',
'hanchan_count', 'good_hanchans', 'won_hanchans')
for user in values:
json_data[user['user_id']] = {
'placement': user['placement'],
'user_id': user['user_id'],
'username': user['user__username'],
'first_name': user['user__first_name'],
'last_name': user['user__last_name'],
'avg_placement': user['avg_placement'],
'avg_score': user['avg_score'],
'hanchan_count': user['hanchan_count'],
'good_hanchans': user['good_hanchans'],
'won_hanchans': user['won_hanchans']
}
return json_data

View File

@@ -36,38 +36,41 @@ class DenormalizationUpdateMiddleware(object):
cache.set('ladder_ranking_queue', set(), 360)
for event_id in self.event_queue:
self.update_event_placement()
self.update_event_placements()
for season in self.season_queue:
self.update_season_placements()
return response
def recalculate_event_rankings(self, queue):
# recalculate tournament (event) rankings:
for event_id, user_id in queue:
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]
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()
self.event_queue.add(event_id)
return queue
def recalulate_kyu_dan_ranking(self, queue):
for user_id in queue:
ranking = models.KyuDanRanking.objects.get_or_create(user_id=user_id)[0]
ranking = models.KyuDanRanking.objects.get_or_create(user_id=user_id)[
0]
ranking.recalculate()
return queue
def recalculate_ladder_ranking(self, queue):
for season, user_id in queue:
ladder = models.SeasonRanking.objects.get_or_create(user_id=user_id, season=season)[0]
ladder = models.SeasonRanking.objects.get_or_create(
user_id=user_id, season=season)[0]
ladder.recalculate()
self.season_queue.add(season)
def update_event_placements(self):
for event_id in self.event_queue:
eventranking_set = models.EventRanking.objects.filter(event_id=event_id).order_by('avg_placement', '-avg_score')
eventranking_set = models.EventRanking.objects.filter(
event_id=event_id).order_by('avg_placement', '-avg_score')
placement = 1
for ranking in eventranking_set:
ranking.placement = placement

View File

@@ -0,0 +1,157 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('events', '0005_auto_20150907_2021'),
]
operations = [
migrations.CreateModel(
name='EventRanking',
fields=[
('id', models.AutoField(verbose_name='ID',
serialize=False, auto_created=True, primary_key=True)),
('placement', models.PositiveIntegerField(null=True, blank=True)),
('avg_placement', models.FloatField(default=4)),
('avg_score', models.FloatField(default=0)),
('hanchan_count', models.PositiveIntegerField(default=0)),
('good_hanchans', models.PositiveIntegerField(default=0)),
('won_hanchans', models.PositiveIntegerField(default=0)),
('event', models.ForeignKey(to='events.Event')),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ('placement', 'avg_placement', '-avg_score'),
},
),
migrations.CreateModel(
name='Hanchan',
fields=[
('id', models.AutoField(verbose_name='ID',
serialize=False, auto_created=True, primary_key=True)),
('start', models.DateTimeField(
help_text='Wichtig damit die richtigen Hanchans in die Wertung kommen.', verbose_name='Beginn')),
('player1_input_score', models.IntegerField(verbose_name='Punkte')),
('player1_game_score', models.PositiveIntegerField(
default=0, verbose_name='Punkte', editable=False)),
('player1_placement', models.PositiveSmallIntegerField(
default=0, editable=False)),
('player1_kyu_points', models.SmallIntegerField(
null=True, editable=False, blank=True)),
('player1_dan_points', models.SmallIntegerField(
null=True, editable=False, blank=True)),
('player1_bonus_points', models.SmallIntegerField(
null=True, editable=False, blank=True)),
('player1_comment', models.CharField(verbose_name='Anmerkung',
max_length=255, editable=False, blank=True)),
('player2_input_score', models.IntegerField(verbose_name='Punkte')),
('player2_game_score', models.PositiveIntegerField(
default=0, verbose_name='Punkte', editable=False)),
('player2_placement', models.PositiveSmallIntegerField(
default=0, editable=False)),
('player2_kyu_points', models.SmallIntegerField(
null=True, editable=False, blank=True)),
('player2_dan_points', models.SmallIntegerField(
null=True, editable=False, blank=True)),
('player2_bonus_points', models.SmallIntegerField(
null=True, editable=False, blank=True)),
('player2_comment', models.CharField(verbose_name='Anmerkung',
max_length=255, editable=False, blank=True)),
('player3_input_score', models.IntegerField(verbose_name='Punkte')),
('player3_game_score', models.PositiveIntegerField(
default=0, verbose_name='Punkte', editable=False)),
('player3_placement', models.PositiveSmallIntegerField(
default=0, editable=False)),
('player3_kyu_points', models.SmallIntegerField(
null=True, editable=False, blank=True)),
('player3_dan_points', models.SmallIntegerField(
null=True, editable=False, blank=True)),
('player3_bonus_points', models.SmallIntegerField(
null=True, editable=False, blank=True)),
('player3_comment', models.CharField(verbose_name='Anmerkung',
max_length=255, editable=False, blank=True)),
('player4_input_score', models.IntegerField(verbose_name='Punkte')),
('player4_game_score', models.PositiveIntegerField(
default=0, verbose_name='Punkte', editable=False)),
('player4_placement', models.PositiveSmallIntegerField(
default=0, editable=False)),
('player4_kyu_points', models.SmallIntegerField(
null=True, editable=False, blank=True)),
('player4_dan_points', models.SmallIntegerField(
null=True, editable=False, blank=True)),
('player4_bonus_points', models.SmallIntegerField(
null=True, editable=False, blank=True)),
('player4_comment', models.CharField(verbose_name='Anmerkung',
max_length=255, editable=False, blank=True)),
('comment', models.TextField(verbose_name='Anmerkung', blank=True)),
('confirmed', models.BooleanField(
default=True, help_text='Nur g\xfcltige und best\xe4tigte Hanchans kommen in die Wertung.', verbose_name='Wurde best\xe4tigt')),
('player_names', models.CharField(max_length=255, editable=False)),
('season', models.PositiveSmallIntegerField(
verbose_name='Saison', editable=False, db_index=True)),
('event', models.ForeignKey(to='events.Event')),
('player1', models.ForeignKey(related_name='user_hanchan+',
verbose_name='Spieler 1', to=settings.AUTH_USER_MODEL)),
('player2', models.ForeignKey(related_name='user_hanchan+',
verbose_name='Spieler 2', to=settings.AUTH_USER_MODEL)),
('player3', models.ForeignKey(related_name='user_hanchan+',
verbose_name='Spieler 3', to=settings.AUTH_USER_MODEL)),
('player4', models.ForeignKey(related_name='user_hanchan+',
verbose_name='Spieler 4', to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ('-start',),
'verbose_name': 'Hanchan',
'verbose_name_plural': 'Hanchans',
},
),
migrations.CreateModel(
name='KyuDanRanking',
fields=[
('id', models.AutoField(verbose_name='ID',
serialize=False, auto_created=True, primary_key=True)),
('dan', models.PositiveSmallIntegerField(null=True, blank=True)),
('dan_points', models.PositiveIntegerField(default=0)),
('kyu', models.PositiveSmallIntegerField(
default=10, null=True, blank=True)),
('kyu_points', models.PositiveIntegerField(default=0)),
('won_hanchans', models.PositiveIntegerField(default=0)),
('good_hanchans', models.PositiveIntegerField(default=0)),
('hanchan_count', models.PositiveIntegerField(default=0)),
('legacy_date', models.DateField(null=True, blank=True)),
('legacy_dan_points', models.PositiveIntegerField(default=0)),
('legacy_kyu_points', models.PositiveIntegerField(default=0)),
('user', models.OneToOneField(to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ('-dan', '-dan_points', '-kyu_points'),
'verbose_name': 'Ky\u016b/Dan Wertung',
'verbose_name_plural': 'Ky\u016b/Dan Wertungen',
},
),
migrations.CreateModel(
name='SeasonRanking',
fields=[
('id', models.AutoField(verbose_name='ID',
serialize=False, auto_created=True, primary_key=True)),
('season', models.PositiveSmallIntegerField(verbose_name='Saison')),
('placement', models.PositiveIntegerField(null=True, blank=True)),
('avg_placement', models.FloatField(null=True, blank=True)),
('avg_score', models.FloatField(null=True, blank=True)),
('hanchan_count', models.PositiveIntegerField(default=0)),
('good_hanchans', models.PositiveIntegerField(default=0)),
('won_hanchans', models.PositiveIntegerField(default=0)),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ('placement', 'avg_placement', '-avg_score'),
},
),
]

View File

@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('mahjong_ranking', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='kyudanranking',
name='legacy_hanchan_count',
field=models.PositiveIntegerField(default=0),
),
]

Some files were not shown because too many files have changed in this diff Show More