Events und Gallery in einzelne Apps aufgetielt.

Lokalisierung auf einzelne Apps aufgeteilt
Mai-Star Ranking in die Navigation integriert
This commit is contained in:
Christian Berg
2014-12-09 23:19:04 +01:00
parent 34f5bdca58
commit 2011d3ce25
1084 changed files with 4905 additions and 7628 deletions

View File

@@ -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)

View File

@@ -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
} }

View File

@@ -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/"

View File

@@ -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

Binary file not shown.

View 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"

View File

@@ -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!"

View File

@@ -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

View File

@@ -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
View 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'),
)

View File

@@ -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]

View File

@@ -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 %}

View File

@@ -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
View 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'),
)

View File

@@ -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"]' % {

View File

@@ -5,10 +5,11 @@ Created on 19.09.2011
""" """
# import stuff we need from django # import stuff we need from django
from django.contrib import admin from django.contrib import admin
from 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

View File

@@ -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(),

View File

@@ -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'
),
)

View File

@@ -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,

View File

@@ -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'
),
)

Binary file not shown.

View 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"

View File

@@ -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)

View File

@@ -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]

View File

@@ -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>&nbsp;</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}}&amp;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> &nbsp;
<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}}&amp;z=16" target="gmaps"><img src="{{ STATIC_URL }}img/google_maps.png" alt="Google Maps" title="{% trans 'Show on Google Maps' %}" width="39" height="39"/></a> <a href="http://maps.google.com/maps?q={{event.location.address|urlencode}}&amp;z=16" target="gmaps"><img src="{{ STATIC_URL }}img/google_maps.png" alt="Google Maps" title="{% trans 'Show on Google Maps' %}" width="39" height="39"/></a>
</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 %}

View File

@@ -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>&nbsp;</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}}&amp;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 %}

View File

@@ -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
View 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'),
)

View File

@@ -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
View File

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

57
gallery/forms.py Normal file
View 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
View 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)

View File

@@ -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>

View File

@@ -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
View File

247
gallery/views.py Normal file
View 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
View 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

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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']

View File

@@ -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

View File

@@ -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
View 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,
},
}
}

View File

@@ -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;
} }

View File

@@ -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; }

View File

@@ -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;
}

View File

@@ -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;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 524 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 781 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 733 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 523 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 619 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 524 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 610 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 533 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 703 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 656 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 467 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 592 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 605 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 714 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 612 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 581 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 634 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 670 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 656 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 701 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 487 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 585 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 547 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 581 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 510 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 483 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 520 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 432 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 492 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 576 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 555 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 473 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 677 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 600 B

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