Events und Gallery in einzelne Apps aufgetielt.
Lokalisierung auf einzelne Apps aufgeteilt Mai-Star Ranking in die Navigation integriert
@@ -5,6 +5,7 @@ Created on 19.09.2011
|
|||||||
"""
|
"""
|
||||||
# import stuff we need from django
|
# import stuff we need from django
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
@@ -57,6 +58,7 @@ class PageAdmin(admin.ModelAdmin):
|
|||||||
'/static/js/tinymce_setup.js',
|
'/static/js/tinymce_setup.js',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(models.Article, ArticleAdmin)
|
admin.site.register(models.Article, ArticleAdmin)
|
||||||
admin.site.register(models.Page, PageAdmin)
|
admin.site.register(models.Page, PageAdmin)
|
||||||
admin.site.register(models.Category, CategoryAdmin)
|
admin.site.register(models.Category, CategoryAdmin)
|
||||||
|
|||||||
@@ -4,9 +4,10 @@ Created on 30.09.2011
|
|||||||
|
|
||||||
@author: christian
|
@author: christian
|
||||||
"""
|
"""
|
||||||
from . import models
|
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
|
||||||
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
def content_menus(request):
|
def content_menus(request):
|
||||||
current_page = None
|
current_page = None
|
||||||
@@ -46,4 +47,4 @@ def content_menus(request):
|
|||||||
'current_top_page': current_top_page,
|
'current_top_page': current_top_page,
|
||||||
'current_path': current_path,
|
'current_path': current_path,
|
||||||
'current_page': current_page
|
'current_page': current_page
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
from datetime import datetime, time
|
from datetime import datetime, time
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.contrib import comments
|
from django.contrib import comments
|
||||||
from django.contrib.syndication.views import Feed
|
from django.contrib.syndication.views import Feed
|
||||||
from django.utils.feedgenerator import Rss201rev2Feed
|
from django.utils.feedgenerator import Rss201rev2Feed
|
||||||
|
|
||||||
from models import Article
|
from models import Article
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyMethodMayBeStatic
|
# noinspection PyMethodMayBeStatic
|
||||||
class LatestNews(Feed):
|
class LatestNews(Feed):
|
||||||
link = "http://www.kasu.at/"
|
link = "http://www.kasu.at/"
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ from django.template.defaultfilters import slugify
|
|||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from utils.html5 import forms
|
from utils.html5 import forms
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
BIN
content/locale/de/LC_MESSAGES/django.mo
Normal file
251
content/locale/de/LC_MESSAGES/django.po
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: kasu.content\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2014-12-09 20:35+0100\n"
|
||||||
|
"PO-Revision-Date: 2014-12-08 16:15+0100\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"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
"X-Translated-Using: django-rosetta 0.7.2\n"
|
||||||
|
"X-Generator: Poedit 1.6.11\n"
|
||||||
|
|
||||||
|
#: feeds.py:16
|
||||||
|
msgid "Current news from Kasu"
|
||||||
|
msgstr "Aktuelle Nachrichten von Kasu"
|
||||||
|
|
||||||
|
#: feeds.py:44
|
||||||
|
msgid "Latest comments on kasu.at"
|
||||||
|
msgstr "Neueste Kommentare auf Kasu.at "
|
||||||
|
|
||||||
|
#: feeds.py:45
|
||||||
|
msgid "Kasu - latest comments"
|
||||||
|
msgstr "Kasu - neue Kommentare"
|
||||||
|
|
||||||
|
#: forms.py:52 models.py:201
|
||||||
|
msgid "Please upload a PDF-File to this PDF-Page."
|
||||||
|
msgstr "Bitte eine PDF Datei für diese PDF Seite hochladen."
|
||||||
|
|
||||||
|
#: models.py:48
|
||||||
|
msgid "Headline"
|
||||||
|
msgstr "Schlagzeile"
|
||||||
|
|
||||||
|
#: models.py:50
|
||||||
|
msgid "Content"
|
||||||
|
msgstr "Inhalt"
|
||||||
|
|
||||||
|
#: models.py:52 models.py:231 templates/content/article_detail.html:34
|
||||||
|
msgid "Category"
|
||||||
|
msgstr "Kategorie"
|
||||||
|
|
||||||
|
#: models.py:53 models.py:225
|
||||||
|
msgid "Image"
|
||||||
|
msgstr "Bild"
|
||||||
|
|
||||||
|
#: models.py:55 models.py:227
|
||||||
|
msgid "Slug"
|
||||||
|
msgstr "Slug"
|
||||||
|
|
||||||
|
#: models.py:57 templates/content/article_detail.html:32
|
||||||
|
msgid "Author"
|
||||||
|
msgstr "Autor"
|
||||||
|
|
||||||
|
#: models.py:58
|
||||||
|
msgid "Status"
|
||||||
|
msgstr "Status"
|
||||||
|
|
||||||
|
#: models.py:60
|
||||||
|
msgid "Created"
|
||||||
|
msgstr "Erstellt"
|
||||||
|
|
||||||
|
#: models.py:61
|
||||||
|
msgid "Modified"
|
||||||
|
msgstr "Bearbeitet"
|
||||||
|
|
||||||
|
#: models.py:65
|
||||||
|
msgid "Article"
|
||||||
|
msgstr "Artikel"
|
||||||
|
|
||||||
|
#: models.py:66
|
||||||
|
msgid "Articles"
|
||||||
|
msgstr "Artikel"
|
||||||
|
|
||||||
|
#: models.py:123 models.py:129
|
||||||
|
msgid "The short name for the menu-entry of this page"
|
||||||
|
msgstr "Ein kurzer Name für den Menüeintrag"
|
||||||
|
|
||||||
|
#: models.py:133 models.py:136
|
||||||
|
msgid "This title appears in the HTML header"
|
||||||
|
msgstr "Der Titel erscheint im HTML Header"
|
||||||
|
|
||||||
|
#: models.py:137
|
||||||
|
msgid "slug"
|
||||||
|
msgstr "Slug"
|
||||||
|
|
||||||
|
#: models.py:138
|
||||||
|
msgid "Path"
|
||||||
|
msgstr "Pfad"
|
||||||
|
|
||||||
|
#: models.py:144
|
||||||
|
msgid "Position"
|
||||||
|
msgstr "Position"
|
||||||
|
|
||||||
|
#: models.py:146
|
||||||
|
msgid "status"
|
||||||
|
msgstr "Status"
|
||||||
|
|
||||||
|
#: models.py:152
|
||||||
|
msgid "enable comments"
|
||||||
|
msgstr "Kommentare möglich"
|
||||||
|
|
||||||
|
#: models.py:153
|
||||||
|
msgid "Template"
|
||||||
|
msgstr "Vorlage"
|
||||||
|
|
||||||
|
#: models.py:216
|
||||||
|
msgid "Page"
|
||||||
|
msgstr "Seite"
|
||||||
|
|
||||||
|
#: models.py:217
|
||||||
|
msgid "Pages"
|
||||||
|
msgstr "Seiten"
|
||||||
|
|
||||||
|
#: models.py:221 models.py:222
|
||||||
|
msgid "Name"
|
||||||
|
msgstr "Name"
|
||||||
|
|
||||||
|
#: models.py:223 models.py:224
|
||||||
|
msgid "Description"
|
||||||
|
msgstr "Beschreibung"
|
||||||
|
|
||||||
|
#: models.py:232
|
||||||
|
msgid "Categories"
|
||||||
|
msgstr "Kategorien"
|
||||||
|
|
||||||
|
#: views.py:42
|
||||||
|
msgid "This Category does not exist."
|
||||||
|
msgstr "Diese Kategorie existiert nicht."
|
||||||
|
|
||||||
|
#: views.py:152
|
||||||
|
#, python-format
|
||||||
|
msgid "No Page found matching the Path %s"
|
||||||
|
msgstr "Keine Seite unter dem Pfad %s gefunden"
|
||||||
|
|
||||||
|
#: views.py:166
|
||||||
|
#, python-format
|
||||||
|
msgid "No PDF Document found matching the Path %s"
|
||||||
|
msgstr "Kein PDF Dokument unter dem Pfad %s gefunden."
|
||||||
|
|
||||||
|
#: templates/content/article_archive.html:5
|
||||||
|
#: templates/content/article_archive.html:11
|
||||||
|
#: templates/content/article_archive.html:17
|
||||||
|
msgid "Article Archive"
|
||||||
|
msgstr "Nachrichtenarchiv"
|
||||||
|
|
||||||
|
#: templates/content/article_archive.html:32
|
||||||
|
#: templates/content/article_archive_month.html:5
|
||||||
|
#: templates/content/article_archive_year.html:7
|
||||||
|
msgid "Archive"
|
||||||
|
msgstr "Archiv"
|
||||||
|
|
||||||
|
#: templates/content/article_archive.html:49
|
||||||
|
msgid "All Categories"
|
||||||
|
msgstr "Alle Kategorien"
|
||||||
|
|
||||||
|
#: templates/content/article_archive.html:64
|
||||||
|
msgid "created on"
|
||||||
|
msgstr "erstellt am"
|
||||||
|
|
||||||
|
#: templates/content/article_archive.html:65
|
||||||
|
msgid "by"
|
||||||
|
msgstr "von"
|
||||||
|
|
||||||
|
#: templates/content/article_archive.html:66
|
||||||
|
msgid "comments"
|
||||||
|
msgstr "Kommentare"
|
||||||
|
|
||||||
|
#: templates/content/article_archive.html:70
|
||||||
|
msgid "Read More"
|
||||||
|
msgstr "Mehr lesen"
|
||||||
|
|
||||||
|
#: templates/content/article_archive.html:73
|
||||||
|
msgid "We're sorry. Your search yielded no results."
|
||||||
|
msgstr "Es tut uns leid. Deine Suche ergab keine Treffer."
|
||||||
|
|
||||||
|
#: templates/content/article_archive.html:91
|
||||||
|
msgid "Add Article"
|
||||||
|
msgstr "neuer Artikel "
|
||||||
|
|
||||||
|
#: templates/content/article_archive_month.html:7
|
||||||
|
msgid "back"
|
||||||
|
msgstr "Zurück"
|
||||||
|
|
||||||
|
#: templates/content/article_detail.html:33
|
||||||
|
msgid "Created on"
|
||||||
|
msgstr "Erstellt am"
|
||||||
|
|
||||||
|
#: templates/content/article_detail.html:39
|
||||||
|
msgid "Share on Google+"
|
||||||
|
msgstr "Auf Google+ teilen"
|
||||||
|
|
||||||
|
#: templates/content/article_detail.html:40
|
||||||
|
msgid "Share on Twitter"
|
||||||
|
msgstr "Auf Twitter teilen"
|
||||||
|
|
||||||
|
#: templates/content/article_detail.html:41
|
||||||
|
msgid "Share on Facebook"
|
||||||
|
msgstr "Auf Facebook teilen"
|
||||||
|
|
||||||
|
#: templates/content/article_detail.html:52
|
||||||
|
#: templates/content/article_form.html:5
|
||||||
|
#: templates/content/article_form.html:21
|
||||||
|
msgid "Edit Article"
|
||||||
|
msgstr "Artikel bearbeiten"
|
||||||
|
|
||||||
|
#: templates/content/article_form.html:5
|
||||||
|
#: templates/content/article_form.html:21
|
||||||
|
msgid "Create Article"
|
||||||
|
msgstr "Artikel erstellen"
|
||||||
|
|
||||||
|
#: templates/content/article_form.html:26 templates/content/page_form.html:29
|
||||||
|
#: templates/content/page_form.html:35
|
||||||
|
msgid "German"
|
||||||
|
msgstr "Deutsch"
|
||||||
|
|
||||||
|
#: templates/content/article_form.html:27 templates/content/page_form.html:30
|
||||||
|
#: templates/content/page_form.html:39
|
||||||
|
msgid "English"
|
||||||
|
msgstr "Englisch"
|
||||||
|
|
||||||
|
#: templates/content/article_form.html:40 templates/content/page_form.html:50
|
||||||
|
msgid "reset"
|
||||||
|
msgstr "Zurücksetzen"
|
||||||
|
|
||||||
|
#: templates/content/article_form.html:41 templates/content/page_form.html:51
|
||||||
|
msgid "save"
|
||||||
|
msgstr "Speichern"
|
||||||
|
|
||||||
|
#: templates/content/page.html:23
|
||||||
|
msgid "Subpages"
|
||||||
|
msgstr "Unterseiten"
|
||||||
|
|
||||||
|
#: templates/content/page_form.html:4 templates/content/page_form.html:24
|
||||||
|
msgid "Edit Page"
|
||||||
|
msgstr "Seite bearbeiten"
|
||||||
|
|
||||||
|
#: templates/content/page_form.html:4 templates/content/page_form.html:24
|
||||||
|
msgid "Add Page"
|
||||||
|
msgstr "Seite hinzufügen"
|
||||||
|
|
||||||
|
#: templates/content/page_form.html:45
|
||||||
|
msgid "HTML Specific"
|
||||||
|
msgstr "HTML spezifisch"
|
||||||
@@ -24,7 +24,8 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
def create_article(self):
|
def create_article(self):
|
||||||
self.slug = slugify(self.headline[:50])
|
self.slug = slugify(self.headline[:50])
|
||||||
article, created = Article.objects.get_or_create(slug=self.slug, date_created=self.date_created,
|
article, created = Article.objects.get_or_create(slug=self.slug,
|
||||||
|
date_created=self.date_created,
|
||||||
defaults={
|
defaults={
|
||||||
'author': self.author,
|
'author': self.author,
|
||||||
'headline_de': self.headline,
|
'headline_de': self.headline,
|
||||||
@@ -37,9 +38,11 @@ class Command(BaseCommand):
|
|||||||
article.save()
|
article.save()
|
||||||
|
|
||||||
def parse_with_date(self, original):
|
def parse_with_date(self, original):
|
||||||
match_obj = re.search(self.date_header_regex, original, re.IGNORECASE | re.DOTALL)
|
match_obj = re.search(self.date_header_regex, original,
|
||||||
|
re.IGNORECASE | re.DOTALL)
|
||||||
if match_obj:
|
if match_obj:
|
||||||
self.date_created = datetime.strptime(match_obj.group('date'), '%d.%m.%Y')
|
self.date_created = datetime.strptime(match_obj.group('date'),
|
||||||
|
'%d.%m.%Y')
|
||||||
self.headline = match_obj.group('title').strip()
|
self.headline = match_obj.group('title').strip()
|
||||||
self.content = match_obj.group('content').strip()
|
self.content = match_obj.group('content').strip()
|
||||||
return True
|
return True
|
||||||
@@ -47,7 +50,8 @@ class Command(BaseCommand):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def parse_without_date(self, original):
|
def parse_without_date(self, original):
|
||||||
match_obj = re.search(self.header_regex, original, re.IGNORECASE | re.DOTALL)
|
match_obj = re.search(self.header_regex, original,
|
||||||
|
re.IGNORECASE | re.DOTALL)
|
||||||
if match_obj:
|
if match_obj:
|
||||||
self.date_created = datetime.strptime('01.01.1982', '%d.%m.%Y')
|
self.date_created = datetime.strptime('01.01.1982', '%d.%m.%Y')
|
||||||
self.headline = match_obj.group('title').strip()
|
self.headline = match_obj.group('title').strip()
|
||||||
@@ -71,7 +75,8 @@ class Command(BaseCommand):
|
|||||||
if not table.cell_value(row, 2) in ('Archiv', 'News'):
|
if not table.cell_value(row, 2) in ('Archiv', 'News'):
|
||||||
continue
|
continue
|
||||||
original = table.cell_value(row, 3)
|
original = table.cell_value(row, 3)
|
||||||
if self.parse_with_date(original) or self.parse_without_date(original):
|
if self.parse_with_date(original) or self.parse_without_date(
|
||||||
|
original):
|
||||||
self.create_article()
|
self.create_article()
|
||||||
else:
|
else:
|
||||||
print "Fehler bei String!"
|
print "Fehler bei String!"
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
from django.utils.datetime_safe import datetime
|
from django.utils.datetime_safe import datetime
|
||||||
|
|
||||||
from events.models import Event, Location
|
from events.models import Event, Location
|
||||||
import xlrd
|
import xlrd
|
||||||
|
|
||||||
|
|||||||
@@ -9,10 +9,9 @@ from django.db import models
|
|||||||
from django.template.defaultfilters import slugify
|
from django.template.defaultfilters import slugify
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import get_language, ugettext as _
|
from django.utils.translation import get_language, ugettext as _
|
||||||
from imagekit.models import ImageSpecField
|
|
||||||
from imagekit.processors import SmartResize
|
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
|
||||||
|
from kasu.image_models import ImageModel
|
||||||
from utils import STATUS_CHOICES, STATUS_WAITING, STATUS_PUBLISHED, \
|
from utils import STATUS_CHOICES, STATUS_WAITING, STATUS_PUBLISHED, \
|
||||||
cleaner
|
cleaner
|
||||||
|
|
||||||
@@ -40,17 +39,6 @@ def get_upload_path(instance, filename):
|
|||||||
return "categories/%s.%s" % (instance.slug, extension)
|
return "categories/%s.%s" % (instance.slug, extension)
|
||||||
|
|
||||||
|
|
||||||
class ImageModel(models.Model):
|
|
||||||
article = ImageSpecField(
|
|
||||||
source='image',
|
|
||||||
processors=[SmartResize(width=210, height=130)]
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
abstract = True
|
|
||||||
|
|
||||||
|
|
||||||
class ArticleManager(models.Manager):
|
class ArticleManager(models.Manager):
|
||||||
def published(self):
|
def published(self):
|
||||||
return self.filter(status=STATUS_PUBLISHED, date_created__lte=now())
|
return self.filter(status=STATUS_PUBLISHED, date_created__lte=now())
|
||||||
@@ -65,7 +53,8 @@ class Article(ImageModel):
|
|||||||
image = models.ImageField(_('Image'), upload_to='news/',
|
image = models.ImageField(_('Image'), upload_to='news/',
|
||||||
blank=True, null=True)
|
blank=True, null=True)
|
||||||
slug = models.SlugField(_('Slug'), unique_for_month='date_created')
|
slug = models.SlugField(_('Slug'), unique_for_month='date_created')
|
||||||
author = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=_('Author'))
|
author = models.ForeignKey(settings.AUTH_USER_MODEL,
|
||||||
|
verbose_name=_('Author'))
|
||||||
status = models.SmallIntegerField(_('Status'), choices=STATUS_CHOICES,
|
status = models.SmallIntegerField(_('Status'), choices=STATUS_CHOICES,
|
||||||
default=STATUS_PUBLISHED)
|
default=STATUS_PUBLISHED)
|
||||||
date_created = models.DateTimeField(_('Created'), blank=True)
|
date_created = models.DateTimeField(_('Created'), blank=True)
|
||||||
@@ -140,15 +129,18 @@ class Page(models.Model):
|
|||||||
help_text=_('The short name for the menu-entry of this page')
|
help_text=_('The short name for the menu-entry of this page')
|
||||||
)
|
)
|
||||||
title_de = models.CharField('Titel', max_length=255,
|
title_de = models.CharField('Titel', max_length=255,
|
||||||
help_text=_('This title appears in the HTML header'))
|
help_text=_(
|
||||||
|
'This title appears in the HTML header'))
|
||||||
title_en = models.CharField('Title', max_length=255, blank=True,
|
title_en = models.CharField('Title', max_length=255, blank=True,
|
||||||
help_text=_('This title appears in the HTML header'))
|
help_text=_(
|
||||||
|
'This title appears in the HTML header'))
|
||||||
slug = models.SlugField(_('slug'))
|
slug = models.SlugField(_('slug'))
|
||||||
path = models.CharField(_('Path'), max_length=100, db_index=True,
|
path = models.CharField(_('Path'), max_length=100, db_index=True,
|
||||||
editable=False, unique=True)
|
editable=False, unique=True)
|
||||||
|
|
||||||
parent = models.ForeignKey('self', blank=True, null=True,
|
parent = models.ForeignKey('self', blank=True, null=True,
|
||||||
related_name='subpages', on_delete=models.SET_NULL)
|
related_name='subpages',
|
||||||
|
on_delete=models.SET_NULL)
|
||||||
position = models.PositiveSmallIntegerField(_('Position'),
|
position = models.PositiveSmallIntegerField(_('Position'),
|
||||||
blank=True, null=True)
|
blank=True, null=True)
|
||||||
status = models.SmallIntegerField(_('status'), choices=STATUS_CHOICES,
|
status = models.SmallIntegerField(_('status'), choices=STATUS_CHOICES,
|
||||||
|
|||||||
30
content/news_urls.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Created on 03.10.2011
|
||||||
|
|
||||||
|
@author: christian
|
||||||
|
"""
|
||||||
|
from django.conf.urls import * # @UnusedWildImport
|
||||||
|
|
||||||
|
from .views import ArticleArchiveIndex, ArticleForm, ArticleYearArchive, \
|
||||||
|
ArticleMonthArchive, ArticleDetail
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = patterns(
|
||||||
|
'content.views',
|
||||||
|
url(r'^$', ArticleArchiveIndex.as_view(), name='article-archive'),
|
||||||
|
url(r'^add/$', ArticleForm.as_view(), name='add-article'),
|
||||||
|
url(r'^edit/(?P<pk>[\d]+)/$', ArticleForm.as_view(), name='edit-article'),
|
||||||
|
url(r'^(?P<year>[\d]{4})/$', ArticleYearArchive.as_view(),
|
||||||
|
name='article-archive'),
|
||||||
|
url(r'^(?P<year>[\d]{4})/(?P<month>[\d]+)/$', ArticleMonthArchive.as_view(),
|
||||||
|
name='article-archive'),
|
||||||
|
url(r'^(?P<year>[\d]{4})/(?P<month>[\d]+)/(?P<slug>[\-\d\w]+)/$',
|
||||||
|
ArticleDetail.as_view(), name='show-article'),
|
||||||
|
url(r'^(?P<category>[\-\d\w]+)/$', ArticleArchiveIndex.as_view(),
|
||||||
|
name='article-archive'),
|
||||||
|
url(r'^(?P<category>[\-\d\w]+)/(?P<year>[\d]{4})/$',
|
||||||
|
ArticleYearArchive.as_view(), name='article-archive'),
|
||||||
|
url(r'^(?P<category>[\-\d\w]+)/(?P<year>[\d]{4})/(?P<month>[\d]+)/$',
|
||||||
|
ArticleMonthArchive.as_view(), name='article-archive'),
|
||||||
|
)
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
from imagekit.specs import ImageSpec
|
|
||||||
from imagekit import processors
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8
|
|
||||||
class ResizeArticle(processors.Resize):
|
|
||||||
width = 210
|
|
||||||
height = 130
|
|
||||||
crop = True
|
|
||||||
|
|
||||||
|
|
||||||
class Article(ImageSpec):
|
|
||||||
pre_cache = True
|
|
||||||
processors = [ResizeArticle]
|
|
||||||
@@ -7,11 +7,10 @@
|
|||||||
|
|
||||||
{% block opengraph %}
|
{% block opengraph %}
|
||||||
<meta property="og:type" content="article" />
|
<meta property="og:type" content="article" />
|
||||||
<meta property="og:title" content="{{ article.headline }}" />
|
<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: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.posting_image.url}}" />
|
||||||
<meta property="og:description" content="{{article.content|striptags|truncatewords:25}}" />
|
<meta property="og:description" content="{{article.content|striptags|truncatewords:25|force_escape}}" />
|
||||||
<meta property="og:description" content="{{article.content|striptags|truncatewords:25}}" />
|
|
||||||
<link rel="image_src" type="image/jpeg" href="{{article.posting_image.url}}" />
|
<link rel="image_src" type="image/jpeg" href="{{article.posting_image.url}}" />
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ Created on 10.06.2012
|
|||||||
|
|
||||||
@author: christian
|
@author: christian
|
||||||
"""
|
"""
|
||||||
|
import copy
|
||||||
|
|
||||||
from django import template
|
from django import template
|
||||||
from django.utils.datastructures import SortedDict
|
from django.utils.datastructures import SortedDict
|
||||||
import copy
|
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
|||||||
15
content/urls.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Created on 03.10.2011
|
||||||
|
|
||||||
|
@author: christian
|
||||||
|
"""
|
||||||
|
from django.conf.urls import * # @UnusedWildImport
|
||||||
|
from .views import ImageList, PageList
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = patterns(
|
||||||
|
'content.views',
|
||||||
|
url(r'^image_list.js$', ImageList.as_view(), name='content-image-list'),
|
||||||
|
url(r'^link_list.js$', PageList.as_view(), name='content-page-list'),
|
||||||
|
)
|
||||||
@@ -1,15 +1,17 @@
|
|||||||
# Create your views here.
|
# Create your views here.
|
||||||
from . import models, forms
|
import os
|
||||||
from aggregator.models import Feed
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import comments
|
from django.contrib import comments
|
||||||
from django.http import HttpResponse, Http404
|
from django.http import HttpResponse, Http404
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
|
|
||||||
|
from . import models, forms
|
||||||
|
from aggregator.models import Feed
|
||||||
from utils.mixins import PermissionRequiredMixin
|
from utils.mixins import PermissionRequiredMixin
|
||||||
import events.models
|
import events.models
|
||||||
import os
|
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
|
|
||||||
|
|
||||||
class ArticleArchiveMixin(object):
|
class ArticleArchiveMixin(object):
|
||||||
@@ -53,7 +55,8 @@ class ArticleYearArchive(ArticleArchiveMixin, generic.YearArchiveView):
|
|||||||
queryset = generic.YearArchiveView.get_queryset(self)
|
queryset = generic.YearArchiveView.get_queryset(self)
|
||||||
self.category = self.kwargs.get('category')
|
self.category = self.kwargs.get('category')
|
||||||
if self.category:
|
if self.category:
|
||||||
self.category = get_object_or_404(models.Category, slug=self.category)
|
self.category = get_object_or_404(models.Category,
|
||||||
|
slug=self.category)
|
||||||
queryset = queryset.filter(category=self.category)
|
queryset = queryset.filter(category=self.category)
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
@@ -98,7 +101,8 @@ class ImageList(generic.View):
|
|||||||
response = HttpResponse(content_type='text/javascript')
|
response = HttpResponse(content_type='text/javascript')
|
||||||
response.write('var tinyMCEImageList = new Array(')
|
response.write('var tinyMCEImageList = new Array(')
|
||||||
os.chdir(settings.MEDIA_ROOT)
|
os.chdir(settings.MEDIA_ROOT)
|
||||||
for dirpath, dirnames, filenames in os.walk('images'): # @UnusedVariable @IgnorePep8
|
for dirpath, dirnames, filenames in os.walk(
|
||||||
|
'images'): # @UnusedVariable @IgnorePep8
|
||||||
filenames.sort()
|
filenames.sort()
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
image_list.append('["%(name)s", "%(path)s"]' % {
|
image_list.append('["%(name)s", "%(path)s"]' % {
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ Created on 19.09.2011
|
|||||||
"""
|
"""
|
||||||
# import stuff we need from django
|
# import stuff we need from django
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from events.models import Event, Photo, Location
|
|
||||||
from imagekit.admin import AdminThumbnail
|
from imagekit.admin import AdminThumbnail
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
|
from events.models import Event, Photo, Location
|
||||||
|
|
||||||
|
|
||||||
class EventInline(admin.TabularInline):
|
class EventInline(admin.TabularInline):
|
||||||
model = Event
|
model = Event
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ Created on 30.09.2011
|
|||||||
"""
|
"""
|
||||||
from . import models
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
def upcoming_events(request):
|
def upcoming_events(request):
|
||||||
return {
|
return {
|
||||||
'current_event': models.Event.objects.current_event(),
|
'current_event': models.Event.objects.current_event(),
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
from django.conf.urls import patterns, include, url
|
|
||||||
|
|
||||||
from . import views
|
|
||||||
|
|
||||||
urlpatterns = patterns(
|
|
||||||
'',
|
|
||||||
url(r'^$', views.UpcomingEvents.as_view(), name='upcoming-events'),
|
|
||||||
url(
|
|
||||||
r'^(?P<year>[\d]{4})/$',
|
|
||||||
views.EventArchiveYear.as_view(),
|
|
||||||
name='event-archive'
|
|
||||||
),
|
|
||||||
url(
|
|
||||||
r'^(?P<year>[\d]{4})/(?P<month>[\d]+)/$',
|
|
||||||
views.EventArchiveMonth.as_view(),
|
|
||||||
name='event-archive'
|
|
||||||
),
|
|
||||||
url(
|
|
||||||
r'^(?P<year>[\d]{4})/(?P<month>[\d]+)/(?P<pk>[\d]+)/$',
|
|
||||||
views.EventDetail.as_view(),
|
|
||||||
name='event-detail'
|
|
||||||
),
|
|
||||||
url(
|
|
||||||
r'^(?P<year>[\d]{4})/(?P<month>[\d]+)/(?P<pk>[\d]+)/edit/$',
|
|
||||||
views.EventForm.as_view(),
|
|
||||||
name='event-form'
|
|
||||||
),
|
|
||||||
url(
|
|
||||||
r'^add/$',
|
|
||||||
views.EventForm.as_view(),
|
|
||||||
name='event-form'
|
|
||||||
),
|
|
||||||
url(
|
|
||||||
r'^archive/$',
|
|
||||||
views.EventArchiveIndex.as_view(),
|
|
||||||
name='event-archive'
|
|
||||||
),
|
|
||||||
)
|
|
||||||
@@ -3,20 +3,22 @@ Created on 03.10.2011
|
|||||||
|
|
||||||
@author: christian
|
@author: christian
|
||||||
"""
|
"""
|
||||||
from . import models
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
|
from . import models
|
||||||
from utils.html5.widgets import DateTimeInput
|
from utils.html5.widgets import DateTimeInput
|
||||||
|
|
||||||
|
|
||||||
user_query = get_user_model().objects.all()
|
user_query = get_user_model().objects.all()
|
||||||
|
|
||||||
|
|
||||||
class PhotoUploadForm(forms.Form):
|
class PhotoUploadForm(forms.Form):
|
||||||
error_css_class = 'error'
|
error_css_class = 'error'
|
||||||
required_css_class = 'required'
|
required_css_class = 'required'
|
||||||
photographer = forms.ModelChoiceField(user_query, required=True,)
|
photographer = forms.ModelChoiceField(user_query, required=True, )
|
||||||
event = forms.ModelChoiceField(models.Event.objects.all(), required=True,)
|
event = forms.ModelChoiceField(models.Event.objects.all(), required=True, )
|
||||||
upload = forms.FileField(
|
upload = forms.FileField(
|
||||||
label=_('Images'),
|
label=_('Images'),
|
||||||
required=True,
|
required=True,
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
from django.conf.urls import patterns, include, url
|
|
||||||
|
|
||||||
from . import views
|
|
||||||
|
|
||||||
urlpatterns = patterns(
|
|
||||||
'',
|
|
||||||
url(r'^$', views.EventGallery.as_view(), name='event-gallery'),
|
|
||||||
url(
|
|
||||||
r'^(?P<event>[\d]+)/$',
|
|
||||||
views.EventPhotoList.as_view(),
|
|
||||||
name='event-photo-list'
|
|
||||||
),
|
|
||||||
url(
|
|
||||||
r'^(?P<event>[\d]+)/(?P<pk>[\d]+)/$',
|
|
||||||
views.EventPhoto.as_view(),
|
|
||||||
name='event-photo'
|
|
||||||
),
|
|
||||||
url(
|
|
||||||
r'^(?P<event>[\d]+)/upload/$',
|
|
||||||
views.EventPhotoUpload.as_view(),
|
|
||||||
name='event-photo-upload'
|
|
||||||
),
|
|
||||||
url(
|
|
||||||
r'^delete/(?P<pk>[\d]+)/$',
|
|
||||||
views.DeleteEventPhoto.as_view(),
|
|
||||||
name='delete-event-photo'
|
|
||||||
),
|
|
||||||
url(
|
|
||||||
r'^upload/$',
|
|
||||||
views.EventPhotoUpload.as_view(),
|
|
||||||
name='event-photo-upload'
|
|
||||||
),
|
|
||||||
)
|
|
||||||
BIN
events/locale/de/LC_MESSAGES/django.mo
Normal file
300
events/locale/de/LC_MESSAGES/django.po
Normal file
@@ -0,0 +1,300 @@
|
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: kasu.events\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2014-12-09 20:35+0100\n"
|
||||||
|
"PO-Revision-Date: 2014-12-08 16:06+0100\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"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
"X-Translated-Using: django-rosetta 0.7.2\n"
|
||||||
|
"X-Generator: Poedit 1.6.11\n"
|
||||||
|
|
||||||
|
#: admin.py:17 models.py:81
|
||||||
|
msgid "Event Series"
|
||||||
|
msgstr "Veranstaltungsreihen"
|
||||||
|
|
||||||
|
#: forms.py:23
|
||||||
|
msgid "Images"
|
||||||
|
msgstr "Bilder"
|
||||||
|
|
||||||
|
#: forms.py:50
|
||||||
|
msgid "start"
|
||||||
|
msgstr "Beginn"
|
||||||
|
|
||||||
|
#: forms.py:54
|
||||||
|
msgid "end"
|
||||||
|
msgstr "Ende"
|
||||||
|
|
||||||
|
#: models.py:67 models.py:155
|
||||||
|
msgid "Name"
|
||||||
|
msgstr "Name"
|
||||||
|
|
||||||
|
#: models.py:68 models.py:156
|
||||||
|
msgid "Description"
|
||||||
|
msgstr "Beschreibung"
|
||||||
|
|
||||||
|
#: models.py:70 templates/events/event_archive.html:41
|
||||||
|
#: templates/events/event_detail.html:31 templates/events/event_detail.html:77
|
||||||
|
#: templates/events/event_list.html:15
|
||||||
|
msgid "Start"
|
||||||
|
msgstr "Beginn"
|
||||||
|
|
||||||
|
#: models.py:71 templates/events/event_detail.html:32
|
||||||
|
#: templates/events/event_detail.html:78
|
||||||
|
msgid "End"
|
||||||
|
msgstr "Ende"
|
||||||
|
|
||||||
|
#: models.py:72 models.py:159 templates/events/event_detail.html:37
|
||||||
|
#: templates/events/event_detail.html:73 templates/events/event_detail.html:79
|
||||||
|
msgid "Homepage"
|
||||||
|
msgstr "Homepage"
|
||||||
|
|
||||||
|
#: models.py:73 models.py:157
|
||||||
|
msgid "Image"
|
||||||
|
msgstr "Bild"
|
||||||
|
|
||||||
|
#: models.py:75
|
||||||
|
msgid "Tournament"
|
||||||
|
msgstr "Turnier"
|
||||||
|
|
||||||
|
#: models.py:76
|
||||||
|
msgid ""
|
||||||
|
"This event is a tournament, different rules apply for the kyu "
|
||||||
|
"ranking."
|
||||||
|
msgstr ""
|
||||||
|
"Diese Veranstaltung ist ein Turnier, es gelten andere Regeln für das Kyu "
|
||||||
|
"Ranking."
|
||||||
|
|
||||||
|
#: models.py:82
|
||||||
|
msgid ""
|
||||||
|
"Wenn dieser Event zu einer Veranstaltungsreihe gehört werden Ort, "
|
||||||
|
"Beschreibung, Bild und Homepage von dem hier angegebenen Event "
|
||||||
|
"übernommen."
|
||||||
|
msgstr ""
|
||||||
|
"Wenn dieser Termin zu einer Veranstaltungsreihe gehört werden Ort, "
|
||||||
|
"Beschreibung, Bild und Homepage von dem hier angegebenen Event übernommen."
|
||||||
|
|
||||||
|
#: models.py:88
|
||||||
|
msgid "Event"
|
||||||
|
msgstr "Termin"
|
||||||
|
|
||||||
|
#: models.py:89
|
||||||
|
msgid "Events"
|
||||||
|
msgstr "Termine"
|
||||||
|
|
||||||
|
#: models.py:160
|
||||||
|
msgid "Postal Code"
|
||||||
|
msgstr "Postleitzahl"
|
||||||
|
|
||||||
|
#: models.py:161
|
||||||
|
msgid "Street Address"
|
||||||
|
msgstr "Straße"
|
||||||
|
|
||||||
|
#: models.py:162
|
||||||
|
msgid "Locality"
|
||||||
|
msgstr "Ort"
|
||||||
|
|
||||||
|
#: models.py:163
|
||||||
|
msgid "Country"
|
||||||
|
msgstr "Land"
|
||||||
|
|
||||||
|
#: models.py:166
|
||||||
|
msgid "Venue"
|
||||||
|
msgstr "Veranstaltungsort"
|
||||||
|
|
||||||
|
#: models.py:167
|
||||||
|
msgid "Venues"
|
||||||
|
msgstr "Veranstaltungsorte"
|
||||||
|
|
||||||
|
#: views.py:193
|
||||||
|
msgid "Event does not exist"
|
||||||
|
msgstr "Veranstaltung gibt es nicht"
|
||||||
|
|
||||||
|
#: templates/events/event_archive.html:5 templates/events/event_archive.html:9
|
||||||
|
msgid "Event Archive"
|
||||||
|
msgstr "Veranstaltungsarchiv"
|
||||||
|
|
||||||
|
#: templates/events/event_archive.html:36 templates/events/event_list.html:11
|
||||||
|
msgid "Event Image"
|
||||||
|
msgstr "Veranstaltungsbild"
|
||||||
|
|
||||||
|
#: templates/events/event_archive.html:44 templates/events/event_list.html:18
|
||||||
|
msgid "from"
|
||||||
|
msgstr "von"
|
||||||
|
|
||||||
|
#: templates/events/event_archive.html:44 templates/events/event_list.html:18
|
||||||
|
msgid "to"
|
||||||
|
msgstr "bis"
|
||||||
|
|
||||||
|
#: templates/events/event_archive.html:52
|
||||||
|
#: templates/events/event_detail.html:35 templates/events/event_detail.html:65
|
||||||
|
#: templates/events/event_list.html:26
|
||||||
|
msgid "Location"
|
||||||
|
msgstr "Ort"
|
||||||
|
|
||||||
|
#: templates/events/event_archive.html:56
|
||||||
|
#: templates/events/event_archive.html:57 templates/events/event_list.html:30
|
||||||
|
msgid "Comments"
|
||||||
|
msgstr "Kommentare"
|
||||||
|
|
||||||
|
#: templates/events/event_archive.html:60
|
||||||
|
#: templates/events/event_archive.html:61
|
||||||
|
#: templates/events/event_detail.html:39 templates/events/event_detail.html:49
|
||||||
|
msgid "Photos"
|
||||||
|
msgstr "Fotos"
|
||||||
|
|
||||||
|
#: templates/events/event_archive.html:64
|
||||||
|
#: templates/events/event_archive.html:65
|
||||||
|
#: templates/events/event_archive.html:66
|
||||||
|
#: templates/events/event_detail.html:38 templates/events/event_detail.html:48
|
||||||
|
#: templates/events/event_detail.html:50
|
||||||
|
msgid "Hanchans"
|
||||||
|
msgstr "Hanchans"
|
||||||
|
|
||||||
|
#: templates/events/event_archive.html:70
|
||||||
|
msgid " Edit"
|
||||||
|
msgstr "Bearbeiten"
|
||||||
|
|
||||||
|
#: templates/events/event_detail.html:40
|
||||||
|
msgid "tourney"
|
||||||
|
msgstr "Turnier"
|
||||||
|
|
||||||
|
#: templates/events/event_detail.html:40
|
||||||
|
msgid "other rules apply here"
|
||||||
|
msgstr "hier gelten andere Regeln"
|
||||||
|
|
||||||
|
#: templates/events/event_detail.html:48
|
||||||
|
msgid "Info"
|
||||||
|
msgstr "Info"
|
||||||
|
|
||||||
|
#: templates/events/event_detail.html:51
|
||||||
|
msgid "Mai-Star Games"
|
||||||
|
msgstr "Mai-Star Spiele"
|
||||||
|
|
||||||
|
#: templates/events/event_detail.html:54
|
||||||
|
msgid "Tournament Ranking"
|
||||||
|
msgstr "Turnier Wertung"
|
||||||
|
|
||||||
|
#: templates/events/event_detail.html:75
|
||||||
|
msgid "Date"
|
||||||
|
msgstr "Datum"
|
||||||
|
|
||||||
|
#: templates/events/event_detail.html:91
|
||||||
|
msgid "Share on Google+"
|
||||||
|
msgstr "Auf Google+ teilen"
|
||||||
|
|
||||||
|
#: templates/events/event_detail.html:92
|
||||||
|
msgid "Share on Twitter"
|
||||||
|
msgstr "Auf Twitter teilen"
|
||||||
|
|
||||||
|
#: templates/events/event_detail.html:93
|
||||||
|
msgid "Share on Facebook"
|
||||||
|
msgstr "Auf Facebook teilen"
|
||||||
|
|
||||||
|
#: templates/events/event_detail.html:94
|
||||||
|
msgid "Show on Google Maps"
|
||||||
|
msgstr "Auf Google Maps zeigen"
|
||||||
|
|
||||||
|
#: templates/events/event_detail.html:110 templates/events/event_form.html:13
|
||||||
|
msgid "Edit Event"
|
||||||
|
msgstr "Termin bearbeiten"
|
||||||
|
|
||||||
|
#: templates/events/event_form.html:13 templates/events/page.html:15
|
||||||
|
msgid "Add Event"
|
||||||
|
msgstr "Neuer Termin"
|
||||||
|
|
||||||
|
#: templates/events/event_form.html:23
|
||||||
|
msgid "reset"
|
||||||
|
msgstr "Zurücksetzen"
|
||||||
|
|
||||||
|
#: templates/events/event_form.html:24
|
||||||
|
msgid "save"
|
||||||
|
msgstr "Speichern"
|
||||||
|
|
||||||
|
#: templates/events/event_list.html:4 templates/events/event_list.html.py:5
|
||||||
|
msgid "Upcoming Events"
|
||||||
|
msgstr "Bevorstehende Veranstaltungen"
|
||||||
|
|
||||||
|
#: templates/events/event_list.html:41
|
||||||
|
msgid " Upload"
|
||||||
|
msgstr "Hochladen"
|
||||||
|
|
||||||
|
#: templates/events/page.html:10
|
||||||
|
msgid "Add to Google Calendar"
|
||||||
|
msgstr "Zu Google Kalender hinzufügen"
|
||||||
|
|
||||||
|
#~ msgid "left"
|
||||||
|
#~ msgstr "Links"
|
||||||
|
|
||||||
|
#~ msgid "center"
|
||||||
|
#~ msgstr "Mitte"
|
||||||
|
|
||||||
|
#~ msgid "right"
|
||||||
|
#~ msgstr "Rechts"
|
||||||
|
|
||||||
|
#~ msgid "top"
|
||||||
|
#~ msgstr "Oben"
|
||||||
|
|
||||||
|
#~ msgid "middle"
|
||||||
|
#~ msgstr "Mitte"
|
||||||
|
|
||||||
|
#~ msgid "bottom"
|
||||||
|
#~ msgstr "Unten"
|
||||||
|
|
||||||
|
#~ msgid "horizontal Anchorpoint"
|
||||||
|
#~ msgstr "horizontaler Anker"
|
||||||
|
|
||||||
|
#~ msgid "vertical Anchorpoint"
|
||||||
|
#~ msgstr "vertikaler Anker"
|
||||||
|
|
||||||
|
#~ msgid "Startpage"
|
||||||
|
#~ msgstr "Startseite"
|
||||||
|
|
||||||
|
#~ msgid "Display this Photo on the Startpage Teaser"
|
||||||
|
#~ msgstr "Foto als Teaser auf der Startseite verwenden."
|
||||||
|
|
||||||
|
#~ msgid "Published on"
|
||||||
|
#~ msgstr "Veröffentlicht am"
|
||||||
|
|
||||||
|
#~ msgid "Number of views"
|
||||||
|
#~ msgstr "Wie oft gesehen"
|
||||||
|
|
||||||
|
#~ msgid "Event Images"
|
||||||
|
#~ msgstr "Veranstaltungsbilder"
|
||||||
|
|
||||||
|
#~ msgid "Cancel"
|
||||||
|
#~ msgstr "Abbrechen"
|
||||||
|
|
||||||
|
#~ msgid "Delete"
|
||||||
|
#~ msgstr "Löschen"
|
||||||
|
|
||||||
|
#~ msgid "previous"
|
||||||
|
#~ msgstr "Zurück"
|
||||||
|
|
||||||
|
#~ msgid "download"
|
||||||
|
#~ msgstr "Herunterladen"
|
||||||
|
|
||||||
|
#~ msgid "Photographer"
|
||||||
|
#~ msgstr "Fotograf"
|
||||||
|
|
||||||
|
#~ msgid "on"
|
||||||
|
#~ msgstr "am"
|
||||||
|
|
||||||
|
#~ msgid "Upload"
|
||||||
|
#~ msgstr "Hochladen"
|
||||||
|
|
||||||
|
#~ msgid "delete"
|
||||||
|
#~ msgstr "Löschen"
|
||||||
|
|
||||||
|
#~ msgid "upload"
|
||||||
|
#~ msgstr "hochladen"
|
||||||
240
events/models.py
@@ -1,33 +1,14 @@
|
|||||||
# -'- Encoding: utf-8 -*-
|
# -'- Encoding: utf-8 -*-
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.template.defaultfilters import slugify
|
from django.template.defaultfilters import slugify
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from imagekit import ImageSpec
|
|
||||||
import imagekit
|
|
||||||
from imagekit.models import ImageSpecField
|
|
||||||
from pilkit import processors
|
|
||||||
import pyexiv2
|
|
||||||
|
|
||||||
from utils import COUNTRIES, OverwriteStorage
|
from utils import COUNTRIES, OverwriteStorage
|
||||||
|
from gallery.models import Photo
|
||||||
|
from kasu import image_models
|
||||||
CHOICES_HORIZONTAL = (
|
|
||||||
(0.00000001, _('left')),
|
|
||||||
(0.5, _('center')),
|
|
||||||
(1, _('right'))
|
|
||||||
)
|
|
||||||
|
|
||||||
CHOICES_VERTICAL = (
|
|
||||||
(0.00000001, _('top')),
|
|
||||||
(0.5, _('middle')),
|
|
||||||
(1, _('bottom'))
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_upload_path(instance, filename):
|
def get_upload_path(instance, filename):
|
||||||
@@ -56,79 +37,6 @@ def get_upload_path(instance, filename):
|
|||||||
return "events/%s/%s" % (instance.event.id, filename)
|
return "events/%s/%s" % (instance.event.id, filename)
|
||||||
|
|
||||||
|
|
||||||
def post_save_image(sender, instance=None, created=False, raw=False, **kwargs):
|
|
||||||
"""
|
|
||||||
Reganerate the images.
|
|
||||||
"""
|
|
||||||
os.remove(instance.display.path)
|
|
||||||
os.remove(instance.callout.path)
|
|
||||||
os.remove(instance.thumbnail.path)
|
|
||||||
|
|
||||||
"""
|
|
||||||
instance.callout.generate(force=True)
|
|
||||||
instance.display.generate(force=True)
|
|
||||||
instance.thumbnail.generate(force=True)
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class CalloutImage(ImageSpec):
|
|
||||||
format = 'PNG'
|
|
||||||
width = 620
|
|
||||||
height = 300
|
|
||||||
|
|
||||||
@property
|
|
||||||
def processors(self):
|
|
||||||
model, field_name = imagekit.utils.get_field_info(self.source) # @UnusedVariable @IgnorePep8
|
|
||||||
anchor = model.get_anchor()
|
|
||||||
if anchor:
|
|
||||||
return [processors.Transpose(), processors.ResizeToFill(
|
|
||||||
width=self.width,
|
|
||||||
height=self.height, anchor=anchor
|
|
||||||
)]
|
|
||||||
else:
|
|
||||||
return [processors.Transpose(), processors.SmartResize(
|
|
||||||
width=self.width,
|
|
||||||
height=self.height
|
|
||||||
)]
|
|
||||||
|
|
||||||
|
|
||||||
class DisplayImage(ImageSpec):
|
|
||||||
format = 'PNG'
|
|
||||||
processors = [processors.Transpose(),
|
|
||||||
processors.ResizeToFit(width=940, height=940, upscale=False)]
|
|
||||||
|
|
||||||
|
|
||||||
class ThumbnailImage(CalloutImage):
|
|
||||||
format = 'PNG'
|
|
||||||
width = 140
|
|
||||||
height = 140
|
|
||||||
|
|
||||||
|
|
||||||
imagekit.register.generator('kasu:image:callout', CalloutImage)
|
|
||||||
imagekit.register.generator('kasu:image:display', DisplayImage)
|
|
||||||
imagekit.register.generator('kasu:image:thumbnail', ThumbnailImage)
|
|
||||||
|
|
||||||
|
|
||||||
class ImageModel(models.Model):
|
|
||||||
callout = ImageSpecField(source='image', id='kasu:image:callout')
|
|
||||||
display = ImageSpecField(source='image', id='kasu:image:display')
|
|
||||||
thumbnail = ImageSpecField(source='image', id='kasu:image:thumbnail')
|
|
||||||
|
|
||||||
def get_anchor(self):
|
|
||||||
try:
|
|
||||||
anchor_horizontal = getattr(self, 'anchor_horizontal')
|
|
||||||
anchor_vertical = getattr(self, 'anchor_vertical')
|
|
||||||
except AttributeError:
|
|
||||||
return None
|
|
||||||
if anchor_horizontal and anchor_vertical:
|
|
||||||
return self.anchor_horizontal, self.anchor_vertical
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
abstract = True
|
|
||||||
|
|
||||||
|
|
||||||
class EventManager(models.Manager):
|
class EventManager(models.Manager):
|
||||||
def current_event(self):
|
def current_event(self):
|
||||||
try:
|
try:
|
||||||
@@ -155,7 +63,7 @@ class EventManager(models.Manager):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
class Event(ImageModel):
|
class Event(image_models.ImageModel):
|
||||||
name = models.CharField(_('Name'), max_length=255)
|
name = models.CharField(_('Name'), max_length=255)
|
||||||
description = models.TextField(_("Description"), blank=True)
|
description = models.TextField(_("Description"), blank=True)
|
||||||
location = models.ForeignKey('Location')
|
location = models.ForeignKey('Location')
|
||||||
@@ -232,7 +140,7 @@ class Event(ImageModel):
|
|||||||
self.url = master_event.url
|
self.url = master_event.url
|
||||||
self.image = master_event.image
|
self.image = master_event.image
|
||||||
self.photo_count = self.photo_set.count()
|
self.photo_count = self.photo_set.count()
|
||||||
models.Model.save(self, **kwargs)
|
super(Event, self).save(**kwargs)
|
||||||
|
|
||||||
# Update the rest of the event series:
|
# Update the rest of the event series:
|
||||||
for sub_event in Event.objects.filter(event_series=self):
|
for sub_event in Event.objects.filter(event_series=self):
|
||||||
@@ -243,7 +151,7 @@ class Event(ImageModel):
|
|||||||
hanchan.save()
|
hanchan.save()
|
||||||
|
|
||||||
|
|
||||||
class Location(ImageModel):
|
class Location(image_models.ImageModel):
|
||||||
name = models.CharField(_("Name"), max_length=200)
|
name = models.CharField(_("Name"), max_length=200)
|
||||||
description = models.TextField(_("Description"), blank=True)
|
description = models.TextField(_("Description"), blank=True)
|
||||||
image = models.ImageField(_("Image"), upload_to=get_upload_path,
|
image = models.ImageField(_("Image"), upload_to=get_upload_path,
|
||||||
@@ -267,137 +175,7 @@ class Location(ImageModel):
|
|||||||
return ','.join(address)
|
return ','.join(address)
|
||||||
|
|
||||||
|
|
||||||
class PhotoManager(models.Manager):
|
models.signals.post_save.connect(image_models.regenerate_image_cache,
|
||||||
def get_random(self, startpage=True):
|
sender=Event)
|
||||||
if startpage:
|
models.signals.post_save.connect(image_models.regenerate_image_cache,
|
||||||
queryset = self.filter(on_startpage=True)
|
sender=Location)
|
||||||
else:
|
|
||||||
queryset = self.all().order_by('?')[0]
|
|
||||||
try:
|
|
||||||
return queryset.order_by('?')[0]
|
|
||||||
except IndexError:
|
|
||||||
return Photo()
|
|
||||||
|
|
||||||
|
|
||||||
class Photo(ImageModel):
|
|
||||||
name = models.CharField(_("Name"), max_length=100, blank=True)
|
|
||||||
image = models.ImageField(_("Image"), upload_to=get_upload_path,
|
|
||||||
storage=OverwriteStorage())
|
|
||||||
anchor_horizontal = models.FloatField(
|
|
||||||
_('horizontal Anchorpoint'),
|
|
||||||
choices=CHOICES_HORIZONTAL,
|
|
||||||
blank=True, null=True,
|
|
||||||
help_text='Der Ankerpunkt ist der interessante Teil des Bildes,\
|
|
||||||
welcher nie abgeschnitten werden darf'
|
|
||||||
)
|
|
||||||
anchor_vertical = models.FloatField(
|
|
||||||
_('vertical Anchorpoint'),
|
|
||||||
choices=CHOICES_VERTICAL,
|
|
||||||
blank=True, null=True,
|
|
||||||
help_text='Wenn kein Ankerpunkt von Hand (horizontal und vertikal)\
|
|
||||||
festgelegt wird, versucht die Software diesen selbst zu erraten.'
|
|
||||||
)
|
|
||||||
|
|
||||||
event = models.ForeignKey(Event)
|
|
||||||
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:
|
|
||||||
verbose_name = _('Event Image')
|
|
||||||
verbose_name_plural = _('Event Images')
|
|
||||||
ordering = ["created_date"]
|
|
||||||
get_latest_by = "created_date"
|
|
||||||
|
|
||||||
def __unicode__(self):
|
|
||||||
return os.path.basename(self.image.name)
|
|
||||||
|
|
||||||
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.
|
|
||||||
"""
|
|
||||||
ImageModel.save(self, **kwargs)
|
|
||||||
self.save_metadata()
|
|
||||||
self.event.save()
|
|
||||||
|
|
||||||
|
|
||||||
models.signals.post_save.connect(post_save_image, sender=Photo)
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
from imagekit.specs import ImageSpec
|
|
||||||
from imagekit import processors
|
|
||||||
|
|
||||||
|
|
||||||
class ResizeDisplay(processors.Resize):
|
|
||||||
width = 780
|
|
||||||
crop = False
|
|
||||||
upscale = False
|
|
||||||
|
|
||||||
|
|
||||||
# first we define our thumbnail resize processor
|
|
||||||
class ResizeCallout(processors.Resize):
|
|
||||||
width = 620
|
|
||||||
height = 300
|
|
||||||
crop = True
|
|
||||||
|
|
||||||
|
|
||||||
class ResizeAdmin(processors.Resize):
|
|
||||||
width = 60
|
|
||||||
height = 60
|
|
||||||
crop = True
|
|
||||||
|
|
||||||
|
|
||||||
class ResizeThumbnail(processors.Resize):
|
|
||||||
width = 140
|
|
||||||
height = 140
|
|
||||||
crop = True
|
|
||||||
|
|
||||||
|
|
||||||
# Different Image Sizes
|
|
||||||
class Admin(ImageSpec):
|
|
||||||
pre_cache = False
|
|
||||||
processors = [processors.Transpose, ResizeAdmin]
|
|
||||||
|
|
||||||
|
|
||||||
class Display(ImageSpec):
|
|
||||||
pre_cache = False
|
|
||||||
processors = [processors.Transpose, ResizeDisplay]
|
|
||||||
|
|
||||||
|
|
||||||
class Callout(ImageSpec):
|
|
||||||
pre_cache = False
|
|
||||||
processors = [processors.Transpose, ResizeCallout]
|
|
||||||
|
|
||||||
|
|
||||||
class Thumbnail(ImageSpec):
|
|
||||||
pre_cache = False
|
|
||||||
processors = [processors.Transpose, ResizeThumbnail]
|
|
||||||
@@ -4,45 +4,64 @@
|
|||||||
{% block title %}{{ event.name }}{% endblock %}
|
{% block title %}{{ event.name }}{% endblock %}
|
||||||
|
|
||||||
{% block opengraph %}
|
{% block opengraph %}
|
||||||
<meta property="og:type" content="activity" />
|
<meta property="og:type" content="activity" />
|
||||||
<meta property="og:title" content="{{event.name}}" />
|
<meta property="og:title" content="{{event.name}}" />
|
||||||
<meta property="og:url" content="http://www.kasu.at{{event.get_absolute_url}}" />
|
<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 }}" />
|
<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}}" />{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra_head %}
|
{% block extra_head %}
|
||||||
<script type="text/javascript" src="https://maps.google.com/maps/api/js?sensor=false"></script>
|
<script type="text/javascript" src="https://maps.google.com/maps/api/js?sensor=false"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block jumbotron_background %}{{ event.get_callout.url }}')}{% endblock %}
|
{% block jumbotron_background %} {{ event.get_callout.url }} {% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% block teaser %}
|
{% block teaser %}
|
||||||
<h2>{{event.name}}</h2>
|
<h1>{{event.name}}</h1>
|
||||||
<div id="teaser_text">
|
|
||||||
{% if event.description %}
|
{% if event.description %}
|
||||||
{{event.description|markdown}}
|
<div id="teaser_text">{{event.description|markdown}}</div>
|
||||||
{% else %}
|
|
||||||
{{event.location.description|markdown}}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block redbox %}
|
||||||
|
<h2>Info</h2>
|
||||||
|
<p> </p>
|
||||||
|
<ul>
|
||||||
|
<li class="date"><strong>{% trans "Start" %}:</strong> {{ event.start }}</li>
|
||||||
|
{% if event.end %}<li class="date"><strong>{% trans "End" %}:</strong> {{ event.end }}</li>{% endif %}
|
||||||
|
<li class="location">
|
||||||
|
{% if event.location.url %}<a href="{{ event.location.url }}">{% else %}<a href="http://maps.google.com/maps?q={{event.location.address|urlencode}}&z=16">{% endif %}
|
||||||
|
<strong>{% trans "Location" %}:</strong> {{event.location.name}}</a>
|
||||||
|
</li>
|
||||||
|
{% if event.url %}<li><a href="{{ event.url }}"><strong>{% trans "Homepage" %}:</strong> {{ event.url }}</a></li>{% endif %}
|
||||||
|
<li class="hanchan"><a href="{% url 'event-hanchan-list' event.pk %}" ><strong>{% trans "Hanchans" %}:</strong> {{ event.hanchan_set.count }}</a></li>
|
||||||
|
<li class="photo"><a href="{% url 'event-photo-list' event.pk %}"><strong>{% trans 'Photos' %}:</strong> {{ event.photo_count }}</a></li>
|
||||||
|
{% if event.is_tournament %}<li class="season"><a href="{% url 'event-ranking' event.pk %}"><strong>{% trans "tourney" %}:</strong> {% trans "other rules apply here" %}</a></li>{% endif%}
|
||||||
|
</ul>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block navigation %}
|
||||||
|
<code>{{ event. }}</code>
|
||||||
|
<ul id="navigation">
|
||||||
|
<li><a href="{{ event.get_absolute_url }}"><img src="{{ STATIC_URL }}icons/information.png" alt="{% trans 'Hanchans' %}" /> {% trans 'Info' %}</a></li>
|
||||||
|
<li><a href="{% url 'event-photo-list' event.pk %}"><img src="{{ STATIC_URL }}icons/camera.png" alt="{% trans 'Photos' %}" /> {{ event.photo_count }} {% trans 'Photos' %}</a></li>
|
||||||
|
<li><a href="{% url 'event-hanchan-list' event.pk %}" ><img src="{{ STATIC_URL }}icons/table.png" alt="{% trans 'Hanchans' %}" /> {{ event.hanchan_set.count }} {% trans "Hanchans" %}</a></li>
|
||||||
|
<li><a href="{% url 'maistar-game-list' event.pk %}" ><img src="{{ STATIC_URL }}icons/drink.png" alt="{% trans 'Mai-Star Games' %}" /> {{ event.maistargame_set.count }} {% trans "Mai-Star Games" %}</a></li>
|
||||||
|
|
||||||
|
{% if event.is_tournament %}
|
||||||
|
<li><a href="{% url 'event-ranking' event.id %}"><img src="{{ STATIC_URL }}icons/medal_gold_1.png" alt="{% trans "Tournament Ranking" %}" /> {% trans "Tournament Ranking" %}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block maincontent %}
|
{% block maincontent %}
|
||||||
<div class="grid_4">
|
<div class="grid_6" id="google_maps">
|
||||||
<h3>{% trans "Date" %}</h3>
|
|
||||||
<p></p>
|
|
||||||
<ul>
|
|
||||||
<li><strong>{% trans "Start" %}:</strong> {{ event.start }}</li>
|
|
||||||
{% if event.end %}<li><strong>{% trans "End" %}:</strong> {{ event.end }}</li>{% endif %}
|
|
||||||
{% if event.url %}<li><strong>{% trans "Homepage" %}:</strong> <a href="{{ event.url }}">{{ event.url }}</a></li>{% endif %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid_4">
|
<div class="grid_6">
|
||||||
<h3>{% trans 'Location' %}</h3>
|
<h3>{% trans 'Location' %}</h3>
|
||||||
<strong>{{ event.location.name }}</strong>
|
<strong>{{ event.location.name }}</strong>
|
||||||
<address>
|
<address>
|
||||||
@@ -53,28 +72,43 @@
|
|||||||
{% if event.location.url %}
|
{% if event.location.url %}
|
||||||
<p><strong>{% trans "Homepage" %}:</strong> <a href="{{ event.location.url }}">{{ event.location.url }}</a></p>
|
<p><strong>{% trans "Homepage" %}:</strong> <a href="{{ event.location.url }}">{{ event.location.url }}</a></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<h3>{% trans "Date" %}</h3>
|
||||||
|
<ul>
|
||||||
|
<li><strong>{% trans "Start" %}:</strong> {{ event.start }}</li>
|
||||||
|
{% if event.end %}<li><strong>{% trans "End" %}:</strong> {{ event.end }}</li>{% endif %}
|
||||||
|
{% if event.url %}<li><strong>{% trans "Homepage" %}:</strong> <a href="{{ event.url }}">{{ event.url }}</a></li>{% endif %}
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid_4 center">
|
<div class="grid_12">
|
||||||
<ul class="info">
|
{% if event.description %}
|
||||||
<li><img src="{{ STATIC_URL }}icons/table.png" alt="{% trans 'Hanchans' %}" /><a href="{% url 'event-hanchan-list' event.pk %}" >{{ event.hanchan_set.count }} {% trans "Hanchans" %}</a></li>
|
{{event.description|markdown}}
|
||||||
<li><img src="{{ STATIC_URL }}icons/camera.png" alt="{% trans 'Photos' %}" /><a href="{% url 'event-photo-list' event.pk %}">{{ event.photo_count }} {% trans 'Photos' %}</a></li>
|
{% else %}
|
||||||
</ul>
|
{{event.location.description|markdown}}
|
||||||
|
{% 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,
|
<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>
|
'', '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="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://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}}&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 href="http://maps.google.com/maps?q={{event.location.address|urlencode}}&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>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<br class="clear" />
|
<br class="clear" />
|
||||||
{% render_comment_list for event %}
|
{% block event_content %} {% endblock %}
|
||||||
{% render_comment_form for event %}
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block comments %}
|
||||||
|
{% render_comment_list for event %}
|
||||||
|
{% render_comment_form for event %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block buttonbar %}
|
{% block buttonbar %}
|
||||||
{% if perms.events.change_event %}
|
{% if perms.events.change_event %}
|
||||||
<a class="button" href="{{ event.get_edit_url }}"><img src="{{ STATIC_URL }}icons/page_edit.png" alt="" /> {% trans "Edit Event" %}</a>
|
<a class="button" href="{{ event.get_edit_url }}"><img src="{{ STATIC_URL }}icons/page_edit.png" alt="" /> {% trans "Edit Event" %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block javascript %}
|
{% block javascript %}
|
||||||
@@ -103,8 +137,8 @@
|
|||||||
center: latlng,
|
center: latlng,
|
||||||
mapTypeId: google.maps.MapTypeId.ROADMAP
|
mapTypeId: google.maps.MapTypeId.ROADMAP
|
||||||
}
|
}
|
||||||
map = new google.maps.Map(document.getElementById("redbox"), mapOptions);
|
map = new google.maps.Map(document.getElementById("google_maps"), mapOptions);
|
||||||
codeAddress();
|
codeAddress();
|
||||||
}
|
}
|
||||||
initialize();
|
initialize();
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{% extends "events/page.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n django_markdown%}
|
{% load i18n django_markdown%}
|
||||||
|
|
||||||
{% block title %}{{ event.name }}{% endblock %}
|
{% block title %}{{ event.name }}{% endblock %}
|
||||||
@@ -20,20 +20,4 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block redbox %}
|
|
||||||
<h2>Info</h2>
|
|
||||||
<p> </p>
|
|
||||||
<ul>
|
|
||||||
<li class="date"><strong>{% trans "Start" %}:</strong> {{ event.start }}</li>
|
|
||||||
{% if event.end %}<li class="date"><strong>{% trans "End" %}:</strong> {{ event.end }}</li>{% endif %}
|
|
||||||
<li class="location">
|
|
||||||
{% if event.location.url %}<a href="{{ event.location.url }}">{% else %}<a href="http://maps.google.com/maps?q={{event.location.address|urlencode}}&z=16">{% endif %}
|
|
||||||
<strong>{% trans "Location" %}:</strong> {{event.location.name}}</a>
|
|
||||||
</li>
|
|
||||||
{% if event.url %}<li><a href="{{ event.url }}"><strong>{% trans "Homepage" %}:</strong> {{ event.url }}</a></li>{% endif %}
|
|
||||||
<li class="hanchan"><a href="{% url 'event-hanchan-list' event.pk %}" ><strong>{% trans "Hanchans" %}:</strong> {{ event.hanchan_set.count }}</a></li>
|
|
||||||
<li class="photo"><a href="{% url 'event-photo-list' event.pk %}"><strong>{% trans 'Photos' %}:</strong> {{ event.photo_count }}</a></li>
|
|
||||||
{% if event.is_tournament %}<li class="season"><a href="{% url 'event-ranking' event.pk %}"><strong>{% trans "tourney" %}:</strong> {% trans "other rules apply here" %}</a></li>{% endif%}
|
|
||||||
</ul>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,9 @@
|
|||||||
|
|
||||||
|
|
||||||
{% block sidebar %}
|
{% block sidebar %}
|
||||||
<a href="http://www.google.com/calendar/render?cid=http%3A%2F%2Fwww.kasu.at%2Fevents.ics" target="_blank"><img src="http://www.google.com/calendar/images/ext/gc_button6.gif" alt="0" border="0"></a>
|
<a href="http://www.google.com/calendar/render?cid=http%3A%2F%2Fwww.kasu.at%2Fevents.ics"
|
||||||
|
target="_blank"><img src="http://www.google.com/calendar/images/ext/gc_button6.gif"
|
||||||
|
alt="{% trans 'Add to Google Calendar' %}"></a>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block additional_buttonbar %}
|
{% block additional_buttonbar %}
|
||||||
|
|||||||
19
events/urls.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
from django.conf.urls import patterns, url
|
||||||
|
|
||||||
|
from .views import *
|
||||||
|
|
||||||
|
urlpatterns = patterns(
|
||||||
|
'',
|
||||||
|
url(r'^$', UpcomingEvents.as_view(), name='upcoming-events'),
|
||||||
|
url(r'^(?P<year>[\d]{4})/$', EventArchiveYear.as_view(),
|
||||||
|
name='event-archive'),
|
||||||
|
url(r'^(?P<year>[\d]{4})/(?P<month>[\d]+)/$', EventArchiveMonth.as_view(),
|
||||||
|
name='event-archive'),
|
||||||
|
url(r'^(?P<year>[\d]{4})/(?P<month>[\d]+)/(?P<pk>[\d]+)/$',
|
||||||
|
EventDetail.as_view(), name='event-detail'),
|
||||||
|
url(r'^(?P<year>[\d]{4})/(?P<month>[\d]+)/(?P<pk>[\d]+)/edit/$',
|
||||||
|
EventForm.as_view(), name='event-form'),
|
||||||
|
url(r'^add/$', EventForm.as_view(), name='event-form'),
|
||||||
|
url(r'^archive/$', EventArchiveIndex.as_view(), name='event-archive'),
|
||||||
|
)
|
||||||
@@ -15,7 +15,6 @@ from icalendar import Calendar, Event
|
|||||||
import pyexiv2
|
import pyexiv2
|
||||||
|
|
||||||
from utils.mixins import PermissionRequiredMixin
|
from utils.mixins import PermissionRequiredMixin
|
||||||
|
|
||||||
from . import models, forms
|
from . import models, forms
|
||||||
|
|
||||||
|
|
||||||
@@ -80,9 +79,17 @@ class EventArchiveYear(generic.YearArchiveView):
|
|||||||
class EventDetail(generic.DetailView):
|
class EventDetail(generic.DetailView):
|
||||||
model = models.Event
|
model = models.Event
|
||||||
|
|
||||||
|
|
||||||
|
class EventDetailMixin(object):
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = generic.DetailView.get_context_data(self, **kwargs)
|
context = super(EventDetailMixin, self).get_context_data(**kwargs)
|
||||||
context['form'] = forms.PhotoUploadForm(initial={'event': self.object, 'photographer': self.request.user})
|
if hasattr(self, 'event'):
|
||||||
|
context['event'] = self.event
|
||||||
|
else:
|
||||||
|
context['event'] = self.object.event
|
||||||
|
print "EventDetailMixin"
|
||||||
|
print dir(context['event'])
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
@@ -108,7 +115,8 @@ class EventForm(PermissionRequiredMixin, generic.UpdateView):
|
|||||||
|
|
||||||
class EventGallery(generic.ListView):
|
class EventGallery(generic.ListView):
|
||||||
template_name = 'events/photo_gallery.html'
|
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(),
|
||||||
|
photo_count__gt=0)
|
||||||
paginate_by = 12
|
paginate_by = 12
|
||||||
|
|
||||||
|
|
||||||
@@ -156,7 +164,8 @@ class EventPhoto(generic.UpdateView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
if request.POST.get('rotate') and request.user.has_perm('events.change_photo'):
|
if request.POST.get('rotate') and request.user.has_perm(
|
||||||
|
'events.change_photo'):
|
||||||
photo = models.Photo.objects.get(pk=kwargs['pk'])
|
photo = models.Photo.objects.get(pk=kwargs['pk'])
|
||||||
photo.rotate(request.POST['rotate'])
|
photo.rotate(request.POST['rotate'])
|
||||||
# return redirect(photo.get_absolute_url())
|
# return redirect(photo.get_absolute_url())
|
||||||
@@ -172,7 +181,8 @@ class EventPhotoList(generic.ListView):
|
|||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = generic.ListView.get_context_data(self, **kwargs)
|
context = generic.ListView.get_context_data(self, **kwargs)
|
||||||
context['event'] = self.event
|
context['event'] = self.event
|
||||||
context['form'] = forms.PhotoUploadForm(initial={'event': self.event, 'photographer': self.request.user})
|
context['form'] = forms.PhotoUploadForm(
|
||||||
|
initial={'event': self.event, 'photographer': self.request.user})
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
@@ -208,8 +218,10 @@ class EventPhotoUpload(generic.FormView):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.event = models.Event.objects.get(id=self.request.REQUEST.get('event'))
|
self.event = models.Event.objects.get(
|
||||||
photographer = self.request.POST.get('photographer', self.request.user.id)
|
id=self.request.REQUEST.get('event'))
|
||||||
|
photographer = self.request.POST.get('photographer',
|
||||||
|
self.request.user.id)
|
||||||
photographer = get_user_model().objects.get(id=photographer)
|
photographer = get_user_model().objects.get(id=photographer)
|
||||||
self.counter = 1
|
self.counter = 1
|
||||||
for upload in self.request.FILES.getlist('upload'):
|
for upload in self.request.FILES.getlist('upload'):
|
||||||
|
|||||||
1
gallery/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
__author__ = 'christian'
|
||||||
57
gallery/forms.py
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
"""
|
||||||
|
Created on 03.10.2011
|
||||||
|
|
||||||
|
@author: christian
|
||||||
|
"""
|
||||||
|
from . import models
|
||||||
|
from django import forms
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from utils.html5.widgets import DateTimeInput
|
||||||
|
|
||||||
|
user_query = get_user_model().objects.all()
|
||||||
|
|
||||||
|
|
||||||
|
class PhotoUploadForm(forms.Form):
|
||||||
|
error_css_class = 'error'
|
||||||
|
required_css_class = 'required'
|
||||||
|
photographer = forms.ModelChoiceField(user_query, required=True,)
|
||||||
|
event = forms.ModelChoiceField(models.Event.objects.all(), required=True,)
|
||||||
|
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')
|
||||||
|
|
||||||
|
|
||||||
|
class EventForm(forms.ModelForm):
|
||||||
|
error_css_class = 'error'
|
||||||
|
required_css_class = 'required'
|
||||||
|
|
||||||
|
start = forms.DateTimeField(
|
||||||
|
label=_('start'), required=True,
|
||||||
|
widget=DateTimeInput() # widget=SplitDateTimeWidget()
|
||||||
|
)
|
||||||
|
end = forms.DateTimeField(
|
||||||
|
label=_('end'), required=False,
|
||||||
|
widget=DateTimeInput() # widget=SplitDateTimeWidget()
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
model = models.Event
|
||||||
403
gallery/models.py
Normal file
@@ -0,0 +1,403 @@
|
|||||||
|
# -'- Encoding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
from django.db import models
|
||||||
|
from django.template.defaultfilters import slugify
|
||||||
|
from django.utils.timezone import now
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
from imagekit import ImageSpec
|
||||||
|
import imagekit
|
||||||
|
from imagekit.models import ImageSpecField
|
||||||
|
from pilkit import processors
|
||||||
|
import pyexiv2
|
||||||
|
|
||||||
|
from utils import COUNTRIES, OverwriteStorage
|
||||||
|
|
||||||
|
|
||||||
|
CHOICES_HORIZONTAL = (
|
||||||
|
(0.00000001, _('left')),
|
||||||
|
(0.5, _('center')),
|
||||||
|
(1, _('right'))
|
||||||
|
)
|
||||||
|
|
||||||
|
CHOICES_VERTICAL = (
|
||||||
|
(0.00000001, _('top')),
|
||||||
|
(0.5, _('middle')),
|
||||||
|
(1, _('bottom'))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
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, Event):
|
||||||
|
if instance.id:
|
||||||
|
return "events/%s.%s" % (instance.id, extension)
|
||||||
|
else:
|
||||||
|
return "events/%s.%s" % (slugify(instance.name), extension)
|
||||||
|
elif isinstance(instance, Location):
|
||||||
|
if instance.id:
|
||||||
|
return "events/location/%s.%s" % (instance.id, extension)
|
||||||
|
else:
|
||||||
|
return "events/location/%s.%s" % (instance.id, extension)
|
||||||
|
elif isinstance(instance, Photo):
|
||||||
|
return "events/%s/%s" % (instance.event.id, filename)
|
||||||
|
|
||||||
|
|
||||||
|
def post_save_image(sender, instance=None, created=False, raw=False, **kwargs):
|
||||||
|
"""
|
||||||
|
Reganerate the images.
|
||||||
|
"""
|
||||||
|
os.remove(instance.display.path)
|
||||||
|
os.remove(instance.callout.path)
|
||||||
|
os.remove(instance.thumbnail.path)
|
||||||
|
|
||||||
|
"""
|
||||||
|
instance.callout.generate(force=True)
|
||||||
|
instance.display.generate(force=True)
|
||||||
|
instance.thumbnail.generate(force=True)
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class CalloutImage(ImageSpec):
|
||||||
|
format = 'PNG'
|
||||||
|
width = 940
|
||||||
|
height = 300
|
||||||
|
|
||||||
|
@property
|
||||||
|
def processors(self):
|
||||||
|
model, field_name = imagekit.utils.get_field_info(self.source) # @UnusedVariable @IgnorePep8
|
||||||
|
anchor = model.get_anchor()
|
||||||
|
if anchor:
|
||||||
|
return [processors.Transpose(), processors.ResizeToFill(
|
||||||
|
width=self.width,
|
||||||
|
height=self.height, anchor=anchor
|
||||||
|
)]
|
||||||
|
else:
|
||||||
|
return [processors.Transpose(), processors.SmartResize(
|
||||||
|
width=self.width,
|
||||||
|
height=self.height
|
||||||
|
)]
|
||||||
|
|
||||||
|
|
||||||
|
class DisplayImage(ImageSpec):
|
||||||
|
format = 'PNG'
|
||||||
|
processors = [processors.Transpose(),
|
||||||
|
processors.ResizeToFit(width=940, height=940, upscale=False)]
|
||||||
|
|
||||||
|
|
||||||
|
class ThumbnailImage(CalloutImage):
|
||||||
|
format = 'PNG'
|
||||||
|
width = 140
|
||||||
|
height = 140
|
||||||
|
|
||||||
|
|
||||||
|
imagekit.register.generator('kasu:image:callout', CalloutImage)
|
||||||
|
imagekit.register.generator('kasu:image:display', DisplayImage)
|
||||||
|
imagekit.register.generator('kasu:image:thumbnail', ThumbnailImage)
|
||||||
|
|
||||||
|
|
||||||
|
class ImageModel(models.Model):
|
||||||
|
callout = ImageSpecField(source='image', id='kasu:image:callout')
|
||||||
|
display = ImageSpecField(source='image', id='kasu:image:display')
|
||||||
|
thumbnail = ImageSpecField(source='image', id='kasu:image:thumbnail')
|
||||||
|
|
||||||
|
def get_anchor(self):
|
||||||
|
try:
|
||||||
|
anchor_horizontal = getattr(self, 'anchor_horizontal')
|
||||||
|
anchor_vertical = getattr(self, 'anchor_vertical')
|
||||||
|
except AttributeError:
|
||||||
|
return None
|
||||||
|
if anchor_horizontal and anchor_vertical:
|
||||||
|
return self.anchor_horizontal, self.anchor_vertical
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
|
||||||
|
class EventManager(models.Manager):
|
||||||
|
def current_event(self):
|
||||||
|
try:
|
||||||
|
current = self.filter(start__lte=now())
|
||||||
|
current = current.filter(end__gte=now())
|
||||||
|
return current.order_by('start', 'end')[0]
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def next_event(self):
|
||||||
|
try:
|
||||||
|
return self.filter(start__gt=now()).order_by('start', 'end')[0]
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def archive(self):
|
||||||
|
return self.filter(start__lt=now())
|
||||||
|
|
||||||
|
def upcoming(self, limit=3):
|
||||||
|
result = self.filter(start__gt=now()).order_by('start', 'end')
|
||||||
|
if limit:
|
||||||
|
return result[1:(limit + 1)]
|
||||||
|
else:
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class Event(ImageModel):
|
||||||
|
name = models.CharField(_('Name'), max_length=255)
|
||||||
|
description = models.TextField(_("Description"), blank=True)
|
||||||
|
location = models.ForeignKey('Location')
|
||||||
|
start = models.DateTimeField(_('Start'))
|
||||||
|
end = models.DateTimeField(_('End'), blank=True, null=True)
|
||||||
|
url = models.URLField(_('Homepage'), blank=True)
|
||||||
|
image = models.ImageField(_("Image"), upload_to=get_upload_path,
|
||||||
|
storage=OverwriteStorage(), blank=True, null=True)
|
||||||
|
is_tournament = models.BooleanField(_('Tournament'), default=False,
|
||||||
|
help_text=_(u'This event is a tournament, different rules apply for \
|
||||||
|
the kyu ranking.'))
|
||||||
|
photo_count = models.PositiveIntegerField(default=0, editable=False)
|
||||||
|
event_series = models.ForeignKey('Event', blank=True, null=True,
|
||||||
|
on_delete=models.SET_NULL, editable=False,
|
||||||
|
verbose_name=_('Event Series'),
|
||||||
|
help_text=_(u'Wenn dieser Event zu einer Veranstaltungsreihe gehört \
|
||||||
|
werden Ort, Beschreibung, Bild und Homepage von dem hier angegebenen \
|
||||||
|
Event übernommen.'))
|
||||||
|
objects = EventManager()
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
verbose_name = _('Event')
|
||||||
|
verbose_name_plural = _('Events')
|
||||||
|
ordering = ('-start', '-end',)
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
try:
|
||||||
|
return "%(name)s (%(date)s)" % {'name': self.name,
|
||||||
|
'date': self.start.date()}
|
||||||
|
except:
|
||||||
|
return "New Event Model"
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
kwargs = {
|
||||||
|
'pk': self.id,
|
||||||
|
'year': self.start.strftime('%Y'),
|
||||||
|
'month': self.start.strftime('%m')
|
||||||
|
}
|
||||||
|
return reverse('event-detail', kwargs=kwargs)
|
||||||
|
|
||||||
|
def get_edit_url(self):
|
||||||
|
kwargs = {
|
||||||
|
'pk': self.id,
|
||||||
|
'year': self.start.strftime('%Y'),
|
||||||
|
'month': self.start.strftime('%m')
|
||||||
|
}
|
||||||
|
return reverse('event-form', kwargs=kwargs)
|
||||||
|
|
||||||
|
def get_callout(self):
|
||||||
|
if self.image:
|
||||||
|
return self.callout
|
||||||
|
elif self.photo_set.count():
|
||||||
|
return self.photo_set.all().order_by('?')[0].callout
|
||||||
|
elif self.location.image:
|
||||||
|
return self.location.callout
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_thumbnail(self):
|
||||||
|
if self.image:
|
||||||
|
return self.thumbnail
|
||||||
|
elif self.photo_set.count():
|
||||||
|
return self.photo_set.all().order_by('?')[0].thumbnail
|
||||||
|
elif self.location.image:
|
||||||
|
return self.location.thumbnail
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def save(self, **kwargs):
|
||||||
|
if self.event_series:
|
||||||
|
master_event = self.event_series
|
||||||
|
self.description = master_event.description
|
||||||
|
self.location = master_event.location
|
||||||
|
self.url = master_event.url
|
||||||
|
self.image = master_event.image
|
||||||
|
self.photo_count = self.photo_set.count()
|
||||||
|
models.Model.save(self, **kwargs)
|
||||||
|
|
||||||
|
# Update the rest of the event series:
|
||||||
|
for sub_event in Event.objects.filter(event_series=self):
|
||||||
|
sub_event.save()
|
||||||
|
|
||||||
|
# Update the Hanchans if necesery:
|
||||||
|
for hanchan in self.hanchan_set.all():
|
||||||
|
hanchan.save()
|
||||||
|
|
||||||
|
|
||||||
|
class Location(ImageModel):
|
||||||
|
name = models.CharField(_("Name"), max_length=200)
|
||||||
|
description = models.TextField(_("Description"), blank=True)
|
||||||
|
image = models.ImageField(_("Image"), upload_to=get_upload_path,
|
||||||
|
storage=OverwriteStorage(), blank=True, null=True)
|
||||||
|
url = models.URLField(_('Homepage'), blank=True)
|
||||||
|
postal_code = models.CharField(_('Postal Code'), max_length=6)
|
||||||
|
street_address = models.CharField(_('Street Address'), max_length=127)
|
||||||
|
locality = models.CharField(_('Locality'), max_length=127)
|
||||||
|
country = models.CharField(_('Country'), max_length=2, choices=COUNTRIES)
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
verbose_name = _('Venue')
|
||||||
|
verbose_name_plural = _('Venues')
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def address(self):
|
||||||
|
address = (self.street_address, self.locality, self.country,)
|
||||||
|
return ','.join(address)
|
||||||
|
|
||||||
|
|
||||||
|
class PhotoManager(models.Manager):
|
||||||
|
def get_random(self, startpage=True):
|
||||||
|
if startpage:
|
||||||
|
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(ImageModel):
|
||||||
|
name = models.CharField(_("Name"), max_length=100, blank=True)
|
||||||
|
image = models.ImageField(_("Image"), upload_to=get_upload_path,
|
||||||
|
storage=OverwriteStorage())
|
||||||
|
anchor_horizontal = models.FloatField(
|
||||||
|
_('horizontal Anchorpoint'),
|
||||||
|
choices=CHOICES_HORIZONTAL,
|
||||||
|
blank=True, null=True,
|
||||||
|
help_text='Der Ankerpunkt ist der interessante Teil des Bildes,\
|
||||||
|
welcher nie abgeschnitten werden darf'
|
||||||
|
)
|
||||||
|
anchor_vertical = models.FloatField(
|
||||||
|
_('vertical Anchorpoint'),
|
||||||
|
choices=CHOICES_VERTICAL,
|
||||||
|
blank=True, null=True,
|
||||||
|
help_text='Wenn kein Ankerpunkt von Hand (horizontal und vertikal)\
|
||||||
|
festgelegt wird, versucht die Software diesen selbst zu erraten.'
|
||||||
|
)
|
||||||
|
|
||||||
|
event = models.ForeignKey(Event)
|
||||||
|
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:
|
||||||
|
verbose_name = _('Event Image')
|
||||||
|
verbose_name_plural = _('Event Images')
|
||||||
|
ordering = ["created_date"]
|
||||||
|
get_latest_by = "created_date"
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return os.path.basename(self.image.name)
|
||||||
|
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
ImageModel.save(self, **kwargs)
|
||||||
|
self.save_metadata()
|
||||||
|
self.event.save()
|
||||||
|
|
||||||
|
|
||||||
|
models.signals.post_save.connect(post_save_image, sender=Photo)
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
{% for event in event_list %}
|
{% for event in event_list %}
|
||||||
<div class="gallery grid_4">
|
<div class="gallery grid_4">
|
||||||
<h3><a href="{% url 'event-photo-list' event.id %}">{{event.name}}</a></h3>
|
<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"/></a>
|
<a href="{% url 'event-photo-list' event.id %}"><img src="{{event.get_thumbnail.url}}" class="thumbnail" alt="{{ event.name }}"/></a>
|
||||||
</div>
|
</div>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<p>Sorry da kommt erst was hin!</p>
|
<p>Sorry da kommt erst was hin!</p>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
{% extends "events/event_site.html" %}
|
{% extends "events/event_detail.html" %}
|
||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
@@ -12,25 +12,6 @@
|
|||||||
{% if event.description %}<meta property="og:description" content="{{event.description}}" />{% endif %}
|
{% if event.description %}<meta property="og:description" content="{{event.description}}" />{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block navigation %}
|
|
||||||
<ul id="navigation">
|
|
||||||
{% if photo %}
|
|
||||||
<li><a href="{{ current_top_page.get_absolute_url }}">{{current_top_page.menu_name}}</a></li>
|
|
||||||
<li><a href="{% url 'event-photo-list' photo.event.id %}">{{photo.event.name}}</a></li>
|
|
||||||
<li><a class="active">{{photo.name}}</a></li>
|
|
||||||
{% elif event %}
|
|
||||||
<li><a href="{{ current_top_page.get_absolute_url }}">{{current_top_page.menu_name}}</a></li>
|
|
||||||
<li><a class="active">{{event.name}}</a></li>
|
|
||||||
{% else %}
|
|
||||||
<li><a href="{{ current_top_page.get_absolute_url }}" {% ifequal current_page current_top_page %}class="active"{% endifequal %}>{{current_top_page.menu_name}}</a></li>
|
|
||||||
{% if perms.event.add_photo %}
|
|
||||||
<li><a href="/gallery/upload/" class="{% ifequal current_path 'gallery/upload' %}active{% endifequal %}">{% trans 'Upload' %}</a></li>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
|
|
||||||
{% block maincontent %}
|
{% block maincontent %}
|
||||||
{% if perms.events.delete_photo %}
|
{% if perms.events.delete_photo %}
|
||||||
{% for photo in photo_list %}
|
{% for photo in photo_list %}
|
||||||
0
gallery/urls.py
Normal file
247
gallery/views.py
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
# -*- 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 HttpResponse, Http404
|
||||||
|
from django.shortcuts import redirect
|
||||||
|
from django.utils import timezone
|
||||||
|
from django.utils.decorators import method_decorator
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
from django.views import generic
|
||||||
|
from icalendar import Calendar, Event
|
||||||
|
import pyexiv2
|
||||||
|
|
||||||
|
from utils.mixins import PermissionRequiredMixin
|
||||||
|
|
||||||
|
from . import models, forms
|
||||||
|
|
||||||
|
|
||||||
|
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])
|
||||||
|
|
||||||
|
@method_decorator(permission_required('events.delete_photo'))
|
||||||
|
def dispatch(self, *args, **kwargs):
|
||||||
|
return super(DeleteEventPhoto, self).dispatch(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class EventArchiveIndex(generic.ArchiveIndexView):
|
||||||
|
allow_empty = True
|
||||||
|
context_object_name = 'event_list'
|
||||||
|
date_field = 'start'
|
||||||
|
model = models.Event
|
||||||
|
queryset = model.objects.all()
|
||||||
|
paginate_by = 15
|
||||||
|
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = generic.ArchiveIndexView.get_context_data(self, **kwargs)
|
||||||
|
context['is_archive'] = True
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class EventArchiveMonth(generic.MonthArchiveView):
|
||||||
|
date_field = 'start'
|
||||||
|
make_object_list = True
|
||||||
|
model = models.Event
|
||||||
|
month_format = '%m'
|
||||||
|
paginate_by = 15
|
||||||
|
template_name = 'events/event_archive.html'
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = generic.MonthArchiveView.get_context_data(self, **kwargs)
|
||||||
|
context['is_archive'] = True
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class EventArchiveYear(generic.YearArchiveView):
|
||||||
|
date_field = 'start'
|
||||||
|
make_object_list = True
|
||||||
|
model = models.Event
|
||||||
|
paginate_by = 15
|
||||||
|
template_name = 'events/event_archive.html'
|
||||||
|
year_format = '%Y'
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = generic.YearArchiveView.get_context_data(self, **kwargs)
|
||||||
|
context['is_archive'] = True
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class EventDetail(generic.DetailView):
|
||||||
|
model = models.Event
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = generic.DetailView.get_context_data(self, **kwargs)
|
||||||
|
context['form'] = forms.PhotoUploadForm(initial={'event': self.object, 'photographer': self.request.user})
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class EventForm(PermissionRequiredMixin, generic.UpdateView):
|
||||||
|
form_class = forms.EventForm
|
||||||
|
permission_required = 'events.add_event'
|
||||||
|
|
||||||
|
def get_object(self, queryset=None):
|
||||||
|
"""
|
||||||
|
If an id has been submitted, try return the existing Event for an update,
|
||||||
|
else creates a new one.
|
||||||
|
@param queryset:
|
||||||
|
"""
|
||||||
|
if self.kwargs.get('pk'):
|
||||||
|
event = models.Event.objects.get(pk=self.kwargs['pk'])
|
||||||
|
if event.event_series:
|
||||||
|
return event.event_series
|
||||||
|
else:
|
||||||
|
return event
|
||||||
|
else:
|
||||||
|
return models.Event()
|
||||||
|
|
||||||
|
|
||||||
|
class EventGallery(generic.ListView):
|
||||||
|
template_name = 'events/photo_gallery.html'
|
||||||
|
queryset = models.Event.objects.filter(start__lt=timezone.now(), photo_count__gt=0)
|
||||||
|
paginate_by = 12
|
||||||
|
|
||||||
|
|
||||||
|
class EventListIcal(generic.View):
|
||||||
|
"""
|
||||||
|
Generates an returns an iCal File with all upcoming events.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def add_event(self, event):
|
||||||
|
ics_event = Event()
|
||||||
|
dtstart = timezone.localtime(event.start)
|
||||||
|
dtend = timezone.localtime(event.end)
|
||||||
|
|
||||||
|
ics_event.add('DTSTART', dtstart)
|
||||||
|
ics_event.add('SUMMARY', event.name)
|
||||||
|
ics_event.add('DESCRIPTION', event.description)
|
||||||
|
ics_event.add('LOCATION', event.location.address)
|
||||||
|
ics_event.add('URL', 'http://www.kasu.at' + event.get_absolute_url())
|
||||||
|
ics_event['UID'] = 'event-%d@www.kasu.at' % event.pk
|
||||||
|
ics_event.add('PRIORITY', 5)
|
||||||
|
if event.end:
|
||||||
|
ics_event.add('DTEND', dtend)
|
||||||
|
self.calendar.add_component(ics_event)
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
response = HttpResponse(mimetype="text/calendar; charset=UTF-8")
|
||||||
|
self.calendar = Calendar()
|
||||||
|
self.calendar.add('prodid', 'http://www.kasu.at/')
|
||||||
|
self.calendar.add('version', '2.0')
|
||||||
|
for event in models.Event.objects.upcoming(limit=None):
|
||||||
|
self.add_event(event)
|
||||||
|
response.write(self.calendar.to_ical())
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
class EventPhoto(generic.UpdateView):
|
||||||
|
form_class = forms.EditPhotoForm
|
||||||
|
model = models.Photo
|
||||||
|
template_name = 'events/photo_detail.html'
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(EventPhoto, self).get_context_data()
|
||||||
|
event = models.Event.objects.get(id=self.kwargs['event'])
|
||||||
|
context['event'] = event
|
||||||
|
return context
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
if request.POST.get('rotate') and request.user.has_perm('events.change_photo'):
|
||||||
|
photo = models.Photo.objects.get(pk=kwargs['pk'])
|
||||||
|
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 = models.Event.objects.get(id=self.kwargs['event'])
|
||||||
|
return models.Photo.objects.filter(event=self.event)
|
||||||
|
except models.Event.DoesNotExist:
|
||||||
|
raise Http404(_('Event does not exist'))
|
||||||
|
|
||||||
|
|
||||||
|
class EventPhotoUpload(generic.FormView):
|
||||||
|
form_class = forms.PhotoUploadForm
|
||||||
|
template_name = 'events/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'] = models.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 = models.Event.objects.get(id=self.request.REQUEST.get('event'))
|
||||||
|
photographer = self.request.POST.get('photographer', self.request.user.id)
|
||||||
|
photographer = get_user_model().objects.get(id=photographer)
|
||||||
|
self.counter = 1
|
||||||
|
for upload in self.request.FILES.getlist('upload'):
|
||||||
|
name = upload.name
|
||||||
|
created_date, description = self.read_exif(upload)
|
||||||
|
photo = models.Photo(
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
class UpcomingEvents(generic.ListView):
|
||||||
|
queryset = models.Event.objects.upcoming(limit=None)
|
||||||
|
paginate_by = 16
|
||||||
103
kasu/image_models.py
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
from pilkit.processors import ResizeToFill, ResizeToFit, SmartResize, Transpose
|
||||||
|
from imagekit.exceptions import MissingSource
|
||||||
|
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 = 'PNG'
|
||||||
|
width = 210
|
||||||
|
height = 130
|
||||||
|
processors = [SmartResize(width=210, height=130)]
|
||||||
|
|
||||||
|
|
||||||
|
class CalloutImage(imagekit.ImageSpec):
|
||||||
|
format = 'JPEG'
|
||||||
|
width = 660
|
||||||
|
height = 300
|
||||||
|
|
||||||
|
@property
|
||||||
|
def processors(self):
|
||||||
|
model, field_name = imagekit.utils.get_field_info(self.source)
|
||||||
|
anchor = model.get_anchor()
|
||||||
|
if anchor:
|
||||||
|
return [Transpose(), ResizeToFill(
|
||||||
|
width=self.width,
|
||||||
|
height=self.height, anchor=anchor
|
||||||
|
)]
|
||||||
|
else:
|
||||||
|
return [Transpose(), SmartResize(
|
||||||
|
width=self.width,
|
||||||
|
height=self.height
|
||||||
|
)]
|
||||||
|
|
||||||
|
|
||||||
|
class DisplayImage(imagekit.ImageSpec):
|
||||||
|
format = 'PNG'
|
||||||
|
processors = [Transpose(),
|
||||||
|
ResizeToFit(width=940, height=940, upscale=False)]
|
||||||
|
|
||||||
|
|
||||||
|
class ThumbnailImage(CalloutImage):
|
||||||
|
format = 'PNG'
|
||||||
|
width = 140
|
||||||
|
height = 140
|
||||||
|
|
||||||
|
|
||||||
|
imagekit.register.generator('kasu:image:article', ArticleImage)
|
||||||
|
imagekit.register.generator('kasu:image:callout', CalloutImage)
|
||||||
|
imagekit.register.generator('kasu:image:display', DisplayImage)
|
||||||
|
imagekit.register.generator('kasu:image:thumbnail', ThumbnailImage)
|
||||||
|
|
||||||
|
|
||||||
|
class ImageModel(models.Model):
|
||||||
|
article = ImageSpecField(source='image', id='kasu:image:article')
|
||||||
|
callout = ImageSpecField(source='image', id='kasu:image:callout')
|
||||||
|
display = ImageSpecField(source='image', id='kasu:image:display')
|
||||||
|
thumbnail = ImageSpecField(source='image', id='kasu:image:thumbnail')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
def get_anchor(self):
|
||||||
|
try:
|
||||||
|
anchor_horizontal = getattr(self, 'anchor_horizontal')
|
||||||
|
anchor_vertical = getattr(self, 'anchor_vertical')
|
||||||
|
except AttributeError:
|
||||||
|
return None
|
||||||
|
if anchor_horizontal and anchor_vertical:
|
||||||
|
return self.anchor_horizontal, self.anchor_vertical
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def regenerate_image_cache(sender, instance=None, created=False, raw=False,
|
||||||
|
**kwargs):
|
||||||
|
"""
|
||||||
|
Reganerate the images.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
os.remove(instance.display.path)
|
||||||
|
os.remove(instance.callout.path)
|
||||||
|
os.remove(instance.thumbnail.path)
|
||||||
|
except imagekit.exceptions.MissingSource:
|
||||||
|
pass
|
||||||
2563
kasu/output.txt
@@ -1,5 +1,4 @@
|
|||||||
from os import path
|
from os import path
|
||||||
from django.template.defaultfilters import slugify
|
|
||||||
|
|
||||||
gettext = lambda s: s
|
gettext = lambda s: s
|
||||||
PROJECT_PATH = path.abspath(path.join(path.dirname(__file__), '..', '..'))
|
PROJECT_PATH = path.abspath(path.join(path.dirname(__file__), '..', '..'))
|
||||||
@@ -11,6 +10,7 @@ PREREQ_APPS = [
|
|||||||
'django.contrib.auth',
|
'django.contrib.auth',
|
||||||
'django.contrib.comments',
|
'django.contrib.comments',
|
||||||
'django.contrib.contenttypes',
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.humanize',
|
||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.sessions',
|
'django.contrib.sessions',
|
||||||
'django.contrib.sites',
|
'django.contrib.sites',
|
||||||
@@ -22,8 +22,10 @@ PROJECT_APPS = [
|
|||||||
'aggregator',
|
'aggregator',
|
||||||
'content',
|
'content',
|
||||||
'events',
|
'events',
|
||||||
|
'gallery',
|
||||||
'imagekit',
|
'imagekit',
|
||||||
'membership',
|
'membership',
|
||||||
|
'maistar_ranking',
|
||||||
'mahjong_ranking',
|
'mahjong_ranking',
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -39,7 +41,6 @@ EMAIL_HOST_PASSWORD = "Ees6aang"
|
|||||||
EMAIL_USE_TLS = True
|
EMAIL_USE_TLS = True
|
||||||
DEFAULT_FROM_EMAIL = "webmaster@kasu.at"
|
DEFAULT_FROM_EMAIL = "webmaster@kasu.at"
|
||||||
|
|
||||||
|
|
||||||
LOCALE_PATHS = (path.join(PROJECT_PATH, 'kasu', 'locale/'),)
|
LOCALE_PATHS = (path.join(PROJECT_PATH, 'kasu', 'locale/'),)
|
||||||
AUTH_PROFILE_MODULE = 'membership.Membership'
|
AUTH_PROFILE_MODULE = 'membership.Membership'
|
||||||
|
|
||||||
@@ -120,7 +121,7 @@ STATICFILES_DIRS = (
|
|||||||
# Put strings here, like "/home/html/static" or "C:/www/django/static".
|
# Put strings here, like "/home/html/static" or "C:/www/django/static".
|
||||||
# Always use forward slashes, even on Windows.
|
# Always use forward slashes, even on Windows.
|
||||||
# Don't forget to use absolute paths, not relative paths.
|
# Don't forget to use absolute paths, not relative paths.
|
||||||
path.join(PROJECT_PATH, 'kasu','static'),
|
path.join(PROJECT_PATH, 'kasu', 'static'),
|
||||||
)
|
)
|
||||||
|
|
||||||
# List of finder classes that know how to find static files in
|
# List of finder classes that know how to find static files in
|
||||||
@@ -151,7 +152,7 @@ TEMPLATE_LOADERS = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
TEMPLATE_DIRS = (
|
TEMPLATE_DIRS = (
|
||||||
path.join(PROJECT_PATH, 'templates/'),
|
path.join(PROJECT_PATH, 'kasu/templates/'),
|
||||||
)
|
)
|
||||||
|
|
||||||
TEMPLATE_CONTEXT_PROCESSORS = (
|
TEMPLATE_CONTEXT_PROCESSORS = (
|
||||||
@@ -197,7 +198,6 @@ LOGIN_ERROR_URL = '/membership/login/error/'
|
|||||||
LOGIN_REDIRECT_URL = '/users/'
|
LOGIN_REDIRECT_URL = '/users/'
|
||||||
SOCIAL_AUTH_NEW_USER_REDIRECT_URL = '/users/'
|
SOCIAL_AUTH_NEW_USER_REDIRECT_URL = '/users/'
|
||||||
|
|
||||||
|
|
||||||
SOCIAL_AUTH_FACEBOOK_KEY = '115196761917023'
|
SOCIAL_AUTH_FACEBOOK_KEY = '115196761917023'
|
||||||
SOCIAL_AUTH_FACEBOOK_SECRET = '6edf715f0506a1177b5479f8cae47566'
|
SOCIAL_AUTH_FACEBOOK_SECRET = '6edf715f0506a1177b5479f8cae47566'
|
||||||
SOCIAL_AUTH_FACEBOOK_SCOPE = ['user_about_me', 'email']
|
SOCIAL_AUTH_FACEBOOK_SCOPE = ['user_about_me', 'email']
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ from base import *
|
|||||||
|
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
TEMPLATE_DEBUG = True
|
TEMPLATE_DEBUG = True
|
||||||
INSTALLED_APPS.append('maistar_ranking')
|
|
||||||
|
|
||||||
# Load the Rosetta translation tool
|
# Load the Rosetta translation tool
|
||||||
try:
|
try:
|
||||||
import rosetta # @UnusedImport
|
import rosetta # @UnusedImport
|
||||||
|
|
||||||
INSTALLED_APPS.append('rosetta')
|
INSTALLED_APPS.append('rosetta')
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
@@ -18,7 +18,9 @@ except ImportError:
|
|||||||
# Load the Django debug toolbar
|
# Load the Django debug toolbar
|
||||||
try:
|
try:
|
||||||
import debug_toolbar # @UnusedImport
|
import debug_toolbar # @UnusedImport
|
||||||
|
|
||||||
INSTALLED_APPS.append('debug_toolbar')
|
INSTALLED_APPS.append('debug_toolbar')
|
||||||
MIDDLEWARE_CLASSES.append('debug_toolbar.middleware.DebugToolbarMiddleware') # @IgnorePep8
|
MIDDLEWARE_CLASSES.append(
|
||||||
|
'debug_toolbar.middleware.DebugToolbarMiddleware') # @IgnorePep8
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
__author__ = "christian"
|
##########################################
|
||||||
|
# Settings for the production enviroment #
|
||||||
|
##########################################
|
||||||
|
__author__ = 'Christian Berg'
|
||||||
from base import *
|
from base import *
|
||||||
|
|
||||||
# A sample logging configuration. The only tangible logging
|
# A sample logging configuration. The only tangible logging
|
||||||
@@ -10,18 +13,24 @@ from base import *
|
|||||||
DEBUG = False
|
DEBUG = False
|
||||||
SESSION_COOKIE_DOMAIN = '.kasu.at' # Die ganze Domain Kasu
|
SESSION_COOKIE_DOMAIN = '.kasu.at' # Die ganze Domain Kasu
|
||||||
SESSION_COOKIE_AGE = 4838400 # Session dauer: 4 Wochen
|
SESSION_COOKIE_AGE = 4838400 # Session dauer: 4 Wochen
|
||||||
TEMPLATE_DEBUG = DEBUG
|
TEMPLATE_DEBUG = False
|
||||||
|
TEMPLATE_LOADERS = (
|
||||||
|
('django.template.loaders.cached.Loader', (
|
||||||
|
'django.template.loaders.filesystem.Loader',
|
||||||
|
'django.template.loaders.app_directories.Loader',
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
|
||||||
LOGGING = {
|
LOGGING = {
|
||||||
'version': 1,
|
'version': 1,
|
||||||
'disable_existing_loggers': True,
|
'disable_existing_loggers': True,
|
||||||
'filters': {
|
'filters': {
|
||||||
'require_debug_false': {
|
'require_debug_false': {'()': 'django.utils.log.RequireDebugFalse'}
|
||||||
'()': 'django.utils.log.RequireDebugFalse'
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
'formatters': {
|
'formatters': {
|
||||||
'verbose': {
|
'verbose': {
|
||||||
'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s' # @IgnorePep8
|
'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
|
||||||
|
# @IgnorePep8
|
||||||
},
|
},
|
||||||
'simple': {
|
'simple': {
|
||||||
'format': '%(levelname)s %(message)s'
|
'format': '%(levelname)s %(message)s'
|
||||||
|
|||||||
75
kasu/settings/staging.py
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
##########################################
|
||||||
|
# Settings for the production enviroment #
|
||||||
|
##########################################
|
||||||
|
__author__ = 'Christian Berg'
|
||||||
|
from base import *
|
||||||
|
|
||||||
|
# A sample logging configuration. The only tangible logging
|
||||||
|
# performed by this configuration is to send an email to
|
||||||
|
# the site admins on every HTTP 500 error.
|
||||||
|
# See http://docs.djangoproject.com/en/dev/topics/logging for
|
||||||
|
# more details on how to customize your logging configuration.
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = ['*']
|
||||||
|
DEBUG = False
|
||||||
|
#SESSION_COOKIE_DOMAIN = '.kasu.at' # Die ganze Domain Kasu
|
||||||
|
SESSION_COOKIE_AGE = 4838400 # Session dauer: 4 Wochen
|
||||||
|
TEMPLATE_DEBUG = False
|
||||||
|
TEMPLATE_LOADERS = (
|
||||||
|
('django.template.loaders.cached.Loader', (
|
||||||
|
'django.template.loaders.filesystem.Loader',
|
||||||
|
'django.template.loaders.app_directories.Loader',
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
|
||||||
|
LOGGING = {
|
||||||
|
'version': 1,
|
||||||
|
'disable_existing_loggers': True,
|
||||||
|
'filters': {
|
||||||
|
'require_debug_false': {'()': 'django.utils.log.RequireDebugFalse'}
|
||||||
|
},
|
||||||
|
'formatters': {
|
||||||
|
'verbose': {
|
||||||
|
'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
|
||||||
|
# @IgnorePep8
|
||||||
|
},
|
||||||
|
'simple': {
|
||||||
|
'format': '%(levelname)s %(message)s'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'handlers': {
|
||||||
|
'null': {
|
||||||
|
'level': 'DEBUG',
|
||||||
|
'class': 'django.utils.log.NullHandler',
|
||||||
|
},
|
||||||
|
'console': {
|
||||||
|
'level': 'DEBUG',
|
||||||
|
'class': 'logging.StreamHandler',
|
||||||
|
'formatter': 'simple'
|
||||||
|
},
|
||||||
|
'mail_admins': {
|
||||||
|
'level': 'ERROR',
|
||||||
|
'filters': ['require_debug_false'],
|
||||||
|
'class': 'django.utils.log.AdminEmailHandler',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'loggers': {
|
||||||
|
'django': {
|
||||||
|
'handlers': ['console'],
|
||||||
|
'level': 'INFO',
|
||||||
|
'propagate': True,
|
||||||
|
},
|
||||||
|
'django.request': {
|
||||||
|
'handlers': ['console', 'mail_admins'],
|
||||||
|
'level': 'ERROR',
|
||||||
|
'propagate': False,
|
||||||
|
},
|
||||||
|
'kasu': {
|
||||||
|
'handlers': ['console', 'mail_admins'],
|
||||||
|
'level': 'DEBUG',
|
||||||
|
'propagate': False,
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ h1 a:link, h2 a:link, h3 a:link, h4 a:link, h5 a:link, h6 a:link, h1 a:visited,
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
h1, h2, h3, h4, h5, h6, .player {
|
||||||
color: #bc0a19;
|
color: #bc0a19;
|
||||||
font-family: 'Amerika Sans', sans-serif;
|
font-family: 'Amerika Sans', sans-serif;
|
||||||
font-variant: small-caps;
|
font-variant: small-caps;
|
||||||
@@ -117,6 +117,10 @@ h1, h2, h3, h4, h5, h6 {
|
|||||||
vertical-align: baseline;
|
vertical-align: baseline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.player {
|
||||||
|
margin:0
|
||||||
|
}
|
||||||
|
|
||||||
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 {
|
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;
|
border: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -356,11 +360,11 @@ ul.info li {
|
|||||||
background: linear-gradient(135deg, #a90329 0%,#8f0222 44%,#6d0019 100%); /* W3C */
|
background: linear-gradient(135deg, #a90329 0%,#8f0222 44%,#6d0019 100%); /* W3C */
|
||||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#a90329', endColorstr='#6d0019',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */
|
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#a90329', endColorstr='#6d0019',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */
|
||||||
}
|
}
|
||||||
#redbox h2 {
|
#redbox h2:first-of-type {
|
||||||
margin: -1em 10px 0 0;
|
margin: -1em 10px 0 0;
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
#redbox h3 {
|
#redbox h2, #redbox h3 {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,585 +0,0 @@
|
|||||||
ul.info {
|
|
||||||
padding-left: 0px;
|
|
||||||
list-style: none;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.info li {
|
|
||||||
display: inline-block;
|
|
||||||
margin-right: 10px
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.event_list,ul.list {
|
|
||||||
list-style: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.comment_list {
|
|
||||||
list-style: none;
|
|
||||||
padding: 0;
|
|
||||||
font-size: small;
|
|
||||||
}
|
|
||||||
|
|
||||||
li.category {
|
|
||||||
background: url("../icons/newspaper.png") left center no-repeat;
|
|
||||||
padding-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
li.comment {
|
|
||||||
background: url("../icons/comment.png") left center no-repeat;
|
|
||||||
padding-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
li.PDF {
|
|
||||||
background: url("../icons/page_white_acrobat.png") left center no-repeat;
|
|
||||||
padding-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
li.HTML {
|
|
||||||
background: url("../icons/page_white_text.png") left center no-repeat;
|
|
||||||
padding-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
li.date {
|
|
||||||
background: url("../icons/date.png") left center no-repeat;
|
|
||||||
padding-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
li.season {
|
|
||||||
background: url("../icons/star.png") left center no-repeat;
|
|
||||||
padding-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
li.event {
|
|
||||||
background: url("../icons/date.png") left center no-repeat;
|
|
||||||
padding-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
li.hanchan {
|
|
||||||
background: url("../icons/table.png") left center no-repeat;
|
|
||||||
padding-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
li.location {
|
|
||||||
background: url("../icons/map.png") left center no-repeat;
|
|
||||||
padding-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
li.user {
|
|
||||||
background: url("../icons/user_red.png") left center no-repeat;
|
|
||||||
padding-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
border-spacing: 0;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
table th {
|
|
||||||
color: #ffffff;
|
|
||||||
background: #a40000;
|
|
||||||
vertical-align: middle;
|
|
||||||
padding: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
table td {
|
|
||||||
vertical-align: middle;
|
|
||||||
padding: 2px;
|
|
||||||
border-bottom: 1px solid #d3d7cf;
|
|
||||||
border-top: 1px solid #d3d7cf
|
|
||||||
}
|
|
||||||
|
|
||||||
table tr:nth-child(2n+1) {
|
|
||||||
background-color: #eeeeec;
|
|
||||||
}
|
|
||||||
|
|
||||||
table tr:hover {
|
|
||||||
background-color: #eedcdc
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#sitelogo {
|
|
||||||
position: absolute;
|
|
||||||
background: url('../img/logo.png') no-repeat;
|
|
||||||
height: 110px;
|
|
||||||
left: 5px;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
text-indent: -9999px;
|
|
||||||
top: 5px;
|
|
||||||
width: 233px;
|
|
||||||
z-index: 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sitelogo a {
|
|
||||||
display: block;
|
|
||||||
height: 110px;
|
|
||||||
left: 0;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
width: 233px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#teaser {
|
|
||||||
border: none;
|
|
||||||
padding: 0;
|
|
||||||
position: relative;
|
|
||||||
vertical-align: bottom;
|
|
||||||
width: 620px;
|
|
||||||
height: 300px;
|
|
||||||
position: relative;
|
|
||||||
border-radius: 10px 0 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#teaser_text {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
display: block;
|
|
||||||
font-size: 10pt;
|
|
||||||
color: #FFF;
|
|
||||||
background: #000;
|
|
||||||
padding: 0px 10px 5px 10px;
|
|
||||||
background: url("../img/teaser_bg.png");
|
|
||||||
width: 600px;
|
|
||||||
}
|
|
||||||
#usernav {
|
|
||||||
position: absolute;
|
|
||||||
top: 0px;
|
|
||||||
right: 0px;
|
|
||||||
color: #FFF;
|
|
||||||
background: url('../img/usernav-bg.png') top left no-repeat;
|
|
||||||
height: 50px;
|
|
||||||
padding: 5px 10px 4px 20px;
|
|
||||||
text-align: right;
|
|
||||||
z-index: 50;
|
|
||||||
}
|
|
||||||
|
|
||||||
#usernav img {
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
#usernav a {
|
|
||||||
color: white;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
#facebook_login,#google_login {
|
|
||||||
display: inline-block;
|
|
||||||
width: 150px;
|
|
||||||
height: 50px;
|
|
||||||
background-image: url('../img/login_buttons.png');
|
|
||||||
text-indent: -9999px;
|
|
||||||
margin: 5px auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#facebook_login {
|
|
||||||
background-position: 0px 0px;
|
|
||||||
margin: 0px 10px
|
|
||||||
}
|
|
||||||
|
|
||||||
#facebook_login:hover {
|
|
||||||
background-position: 150px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#google_login {
|
|
||||||
background-position: 0px 250px;
|
|
||||||
margin: 0px 10px
|
|
||||||
}
|
|
||||||
|
|
||||||
#google_login:hover {
|
|
||||||
background-position: 150px 250px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.center {
|
|
||||||
margin: 0px auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
a.user {
|
|
||||||
color: #2e3436;
|
|
||||||
font-weight: 700;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.userinfo .submit_date {
|
|
||||||
border-top: 1px solid silver;
|
|
||||||
display: block;
|
|
||||||
font-size: small;
|
|
||||||
}
|
|
||||||
|
|
||||||
#display .next {
|
|
||||||
background: transparent url(../img/right-arrow.png) no-repeat center
|
|
||||||
center;
|
|
||||||
display: block;
|
|
||||||
float: left;
|
|
||||||
height: 100%;
|
|
||||||
margin: 10px;
|
|
||||||
min-height: 300px;
|
|
||||||
text-indent: 9999px;
|
|
||||||
vertical-align: bottom;
|
|
||||||
width: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#display .previous {
|
|
||||||
background: transparent url(../img/left-arrow.png) no-repeat center
|
|
||||||
center;
|
|
||||||
display: block;
|
|
||||||
float: left;
|
|
||||||
height: 100%;
|
|
||||||
margin: 10px;
|
|
||||||
min-height: 300px;
|
|
||||||
text-indent: 9999px;
|
|
||||||
vertical-align: bottom;
|
|
||||||
width: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gallery .thumbnail {
|
|
||||||
display: block;
|
|
||||||
float: none;
|
|
||||||
margin: 5px auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
.alpha {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.article_header {
|
|
||||||
font-size: small;
|
|
||||||
}
|
|
||||||
|
|
||||||
.article_header a {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.article_header h3 {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.callout {
|
|
||||||
border: 0;
|
|
||||||
border-radius: 0 10px 10px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.clear {
|
|
||||||
clear: both;
|
|
||||||
display: block;
|
|
||||||
height: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
visibility: hidden;
|
|
||||||
width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.clearfix {
|
|
||||||
zoom: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.clearfix:after {
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
|
|
||||||
.clearfix:before,.clearfix:after {
|
|
||||||
content: '\0020';
|
|
||||||
display: block;
|
|
||||||
height: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
visibility: hidden;
|
|
||||||
width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
font-weight: 400;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
input,textarea,select {
|
|
||||||
margin: 0px;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea,input[maxlength="255"] {
|
|
||||||
width: 690px;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
font-family: "courier-new", monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.form_table tr:hover,table.form_table tr,table.form_table tr:nth-child(2n+1)
|
|
||||||
{
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.form_table th {
|
|
||||||
background: none;
|
|
||||||
color: #2E3436;
|
|
||||||
text-align: right;
|
|
||||||
width: 140px;
|
|
||||||
vertical-align: top;
|
|
||||||
padding: 5px 20px 5px 0px
|
|
||||||
}
|
|
||||||
|
|
||||||
table.form_table td {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
p.help_text {
|
|
||||||
font-size: 8pt
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.errorlist {
|
|
||||||
font-size: small;
|
|
||||||
list-style: square inside;
|
|
||||||
margin-left: 160px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 0 0 1em;
|
|
||||||
text-align: justify;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
img {
|
|
||||||
border: none;
|
|
||||||
vertical-align: text-top;
|
|
||||||
}
|
|
||||||
|
|
||||||
img.posting_image,img.partner {
|
|
||||||
float: left;
|
|
||||||
width: 210px;
|
|
||||||
height: 130px;
|
|
||||||
padding: 4px;
|
|
||||||
margin: 0px 20px 0px 0px;
|
|
||||||
border: 1px solid #babdb6;
|
|
||||||
}
|
|
||||||
|
|
||||||
img.partner_right {
|
|
||||||
float: right;
|
|
||||||
width: 210px;
|
|
||||||
height: 130px;
|
|
||||||
padding: 4px;
|
|
||||||
margin: 0px 00px 0px 20px;
|
|
||||||
border: 1px solid #babdb6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.small {
|
|
||||||
font-size: small;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.layout tr {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.layout td {
|
|
||||||
vertical-align: top;
|
|
||||||
padding: 10px;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
td.right {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
td.center {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.button, button {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 3px;
|
|
||||||
margin: 2px;
|
|
||||||
color: #2e3436;
|
|
||||||
border: 1px solid #d3d7cf;
|
|
||||||
border-radius: 5px;
|
|
||||||
background-color: #f9f9f9;
|
|
||||||
font: bold 16px Philosopher, sans-serif;
|
|
||||||
box-shadow: inset 0px 1px 0px 0px #ffffff;
|
|
||||||
text-decoration: none;
|
|
||||||
text-shadow: 1px 1px 0px #ffffff;
|
|
||||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0.05, #f9f9f9
|
|
||||||
), color-stop(1, #e9e9e9) );
|
|
||||||
background: -moz-linear-gradient(center top, #f9f9f9 5%, #e9e9e9 100%);
|
|
||||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f9f9f9',
|
|
||||||
endColorstr='#e9e9e9' );
|
|
||||||
}
|
|
||||||
|
|
||||||
a.button:hover,button:hover {
|
|
||||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0.05, #e9e9e9
|
|
||||||
), color-stop(1, #f9f9f9) );
|
|
||||||
background: -moz-linear-gradient(center top, #e9e9e9 5%, #f9f9f9 100%);
|
|
||||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#e9e9e9',
|
|
||||||
endColorstr='#f9f9f9' );
|
|
||||||
background-color: #e9e9e9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button:active,button:active {
|
|
||||||
position: relative;
|
|
||||||
top: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#navigation {
|
|
||||||
width: 920px;
|
|
||||||
height: 56px;
|
|
||||||
margin: 0px auto;
|
|
||||||
padding: 8px 0 0 30px;
|
|
||||||
background: url(../img/navigation-bg.png) no-repeat left top;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#navigation li {
|
|
||||||
display: inline;
|
|
||||||
margin: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#navigation a {
|
|
||||||
height: 33px;
|
|
||||||
display: block;
|
|
||||||
float: left;
|
|
||||||
padding: 17px 15px 0 15px;
|
|
||||||
font: bold 12px Arial;
|
|
||||||
color: #FFF;
|
|
||||||
text-decoration: none;
|
|
||||||
background: url(../img/navigation-separator.png) no-repeat right center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#navigation a:hover {
|
|
||||||
color: #3B3B3B;
|
|
||||||
background: url(../img/navigation-hover.png) repeat-x left top;
|
|
||||||
}
|
|
||||||
|
|
||||||
#navigation a.active {
|
|
||||||
color: #3B3B3B;
|
|
||||||
background: url(../img/navigation-hover.png) repeat-x left top;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left {
|
|
||||||
float: left;
|
|
||||||
margin-right: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.push_1,.pull_1,.push_2,.pull_2,.push_3,.pull_3,.push_4,.pull_4,.push_5,.pull_5,.push_6,.pull_6,.push_7,.pull_7,.push_8,.pull_8,.push_9,.pull_9,.push_10,.pull_10,.push_11,.pull_11,.push_12,.pull_12
|
|
||||||
{
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.pull_1 {
|
|
||||||
left: -80px;
|
|
||||||
}
|
|
||||||
.pull_2 {
|
|
||||||
left: -160px;
|
|
||||||
}
|
|
||||||
.pull_3 {
|
|
||||||
left: -240px;
|
|
||||||
}
|
|
||||||
.pull_4 {
|
|
||||||
left: -320px;
|
|
||||||
}
|
|
||||||
.pull_5 {
|
|
||||||
left: -400px;
|
|
||||||
}
|
|
||||||
.pull_6 {
|
|
||||||
left: -480px;
|
|
||||||
}
|
|
||||||
.pull_7 {
|
|
||||||
left: -560px;
|
|
||||||
}
|
|
||||||
.pull_8 {
|
|
||||||
left: -640px;
|
|
||||||
}
|
|
||||||
.pull_9 {
|
|
||||||
left: -720px;
|
|
||||||
}
|
|
||||||
.pull_10 {
|
|
||||||
left: -800px;
|
|
||||||
}
|
|
||||||
.pull_11 {
|
|
||||||
left: -880px;
|
|
||||||
}
|
|
||||||
.push_1 {
|
|
||||||
left: 80px;
|
|
||||||
}
|
|
||||||
.push_2 {
|
|
||||||
left: 160px;
|
|
||||||
}
|
|
||||||
.push_3 {
|
|
||||||
left: 240px;
|
|
||||||
}
|
|
||||||
.push_4 {
|
|
||||||
left: 320px;
|
|
||||||
}
|
|
||||||
.push_5 {
|
|
||||||
left: 400px;
|
|
||||||
}
|
|
||||||
.push_6 {
|
|
||||||
left: 480px;
|
|
||||||
}
|
|
||||||
.push_7 {
|
|
||||||
left: 560px;
|
|
||||||
}
|
|
||||||
.push_8 {
|
|
||||||
left: 640px;
|
|
||||||
}
|
|
||||||
.push_9 {
|
|
||||||
left: 720px;
|
|
||||||
}
|
|
||||||
.push_10 {
|
|
||||||
left: 800px;
|
|
||||||
}
|
|
||||||
.push_11 {
|
|
||||||
left: 880px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#footer_bg {
|
|
||||||
margin-top: -350px;
|
|
||||||
height: 500px;
|
|
||||||
background: url('../img/footer-bg.png') top center no-repeat;
|
|
||||||
z-index: 2;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
#footer {
|
|
||||||
position: relative;
|
|
||||||
top: 0px;
|
|
||||||
z-index: 30;
|
|
||||||
width:920px;
|
|
||||||
margin:-120px auto 0px auto;
|
|
||||||
}
|
|
||||||
#footer p {text-align:center;}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#toggle, .toggle { display: none; }
|
|
||||||
|
|
||||||
@@ -201,11 +201,10 @@ ul.main_menu {padding:0px;}
|
|||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-color: #333;
|
background-color: #333;
|
||||||
background-position: center right;
|
background-position: center left;
|
||||||
background-size: cover;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#jumbotron > h2 {
|
#jumbotron > h2, #jumbotron > h1 {
|
||||||
padding: 10px 5px;
|
padding: 10px 5px;
|
||||||
font-size: 32pt;
|
font-size: 32pt;
|
||||||
color: #eff0ef;
|
color: #eff0ef;
|
||||||
@@ -240,6 +239,7 @@ ul.main_menu {padding:0px;}
|
|||||||
border-radius: 0px 10px 10px 0px;
|
border-radius: 0px 10px 10px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#toggle, .toggle {display: none;}
|
#toggle, .toggle {display: none;}
|
||||||
|
|
||||||
#bottom_buttonbar {
|
#bottom_buttonbar {
|
||||||
@@ -295,17 +295,6 @@ ul.main_menu {padding:0px;}
|
|||||||
margin: 5px auto;
|
margin: 5px auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.player {
|
|
||||||
display: inline;
|
|
||||||
float: left;
|
|
||||||
margin-left: 10px;
|
|
||||||
margin-right: 10px;
|
|
||||||
position: relative;
|
|
||||||
box-sizing: border-box;
|
|
||||||
-moz-box-sizing: border-box;
|
|
||||||
width: 220px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.thumbnail a.delete_image {
|
div.thumbnail a.delete_image {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 4px;
|
right: 4px;
|
||||||
@@ -481,3 +470,14 @@ img.avatar {
|
|||||||
.grid_12 {
|
.grid_12 {
|
||||||
width: 940px;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -98,6 +98,8 @@ img {max-width: 100%; height: auto;}
|
|||||||
background: rgba(255, 255, 255, 0.5);
|
background: rgba(255, 255, 255, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#navigation {margin: 10px 0; padding: 0}
|
||||||
|
|
||||||
#navigation li {
|
#navigation li {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background: #45484d url("../img/buttonbar.gif") top left repeat-x;
|
background: #45484d url("../img/buttonbar.gif") top left repeat-x;
|
||||||
@@ -118,6 +120,14 @@ img {max-width: 100%; height: auto;}
|
|||||||
height: 54px;
|
height: 54px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#siteheader:after {
|
||||||
|
content: ".";
|
||||||
|
clear: both;
|
||||||
|
display: block;
|
||||||
|
visibility: hidden;
|
||||||
|
height: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Dynamische Menü */
|
/* Dynamische Menü */
|
||||||
#mainnav {
|
#mainnav {
|
||||||
display: block;
|
display: block;
|
||||||
@@ -190,6 +200,9 @@ img {max-width: 100%; height: auto;}
|
|||||||
transition: all 0.25s linear;
|
transition: all 0.25s linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#jumbotron {background: none !important;}
|
||||||
|
#redbox {display: block;}
|
||||||
|
|
||||||
.main_menu>li>a:hover,.menu>li>a:focus {
|
.main_menu>li>a:hover,.menu>li>a:focus {
|
||||||
box-shadow: inset 5px 0px #a40000;
|
box-shadow: inset 5px 0px #a40000;
|
||||||
color: #a40000;
|
color: #a40000;
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 524 B |
|
Before Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 781 B |
|
Before Width: | Height: | Size: 733 B |
|
Before Width: | Height: | Size: 523 B |
|
Before Width: | Height: | Size: 464 B |
|
Before Width: | Height: | Size: 619 B |
|
Before Width: | Height: | Size: 524 B |
|
Before Width: | Height: | Size: 610 B |
|
Before Width: | Height: | Size: 533 B |
|
Before Width: | Height: | Size: 703 B |
|
Before Width: | Height: | Size: 656 B |
|
Before Width: | Height: | Size: 467 B |
|
Before Width: | Height: | Size: 592 B |
|
Before Width: | Height: | Size: 605 B |
|
Before Width: | Height: | Size: 714 B |
|
Before Width: | Height: | Size: 612 B |
|
Before Width: | Height: | Size: 581 B |
|
Before Width: | Height: | Size: 634 B |
|
Before Width: | Height: | Size: 685 B |
|
Before Width: | Height: | Size: 670 B |
|
Before Width: | Height: | Size: 656 B |
|
Before Width: | Height: | Size: 701 B |
|
Before Width: | Height: | Size: 487 B |
|
Before Width: | Height: | Size: 525 B |
|
Before Width: | Height: | Size: 585 B |
|
Before Width: | Height: | Size: 478 B |
|
Before Width: | Height: | Size: 547 B |
|
Before Width: | Height: | Size: 581 B |
|
Before Width: | Height: | Size: 510 B |
|
Before Width: | Height: | Size: 483 B |
|
Before Width: | Height: | Size: 520 B |
|
Before Width: | Height: | Size: 432 B |
|
Before Width: | Height: | Size: 492 B |
|
Before Width: | Height: | Size: 493 B |
|
Before Width: | Height: | Size: 576 B |
|
Before Width: | Height: | Size: 555 B |
|
Before Width: | Height: | Size: 463 B |
|
Before Width: | Height: | Size: 473 B |
|
Before Width: | Height: | Size: 457 B |
|
Before Width: | Height: | Size: 426 B |
|
Before Width: | Height: | Size: 507 B |
|
Before Width: | Height: | Size: 582 B |
|
Before Width: | Height: | Size: 677 B |
|
Before Width: | Height: | Size: 379 B |
|
Before Width: | Height: | Size: 600 B |