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
+2
View File
@@ -5,6 +5,7 @@ Created on 19.09.2011
"""
# import stuff we need from django
from django.contrib import admin
from . import models
@@ -57,6 +58,7 @@ class PageAdmin(admin.ModelAdmin):
'/static/js/tinymce_setup.js',
]
admin.site.register(models.Article, ArticleAdmin)
admin.site.register(models.Page, PageAdmin)
admin.site.register(models.Category, CategoryAdmin)
+3 -2
View File
@@ -4,9 +4,10 @@ Created on 30.09.2011
@author: christian
"""
from . import models
from django.core.cache import cache
from . import models
def content_menus(request):
current_page = None
@@ -46,4 +47,4 @@ def content_menus(request):
'current_top_page': current_top_page,
'current_path': current_path,
'current_page': current_page
}
}
+3
View File
@@ -1,12 +1,15 @@
from datetime import datetime, time
from django.conf import settings
from django.utils.translation import ugettext as _
from django.contrib import comments
from django.contrib.syndication.views import Feed
from django.utils.feedgenerator import Rss201rev2Feed
from models import Article
# noinspection PyMethodMayBeStatic
class LatestNews(Feed):
link = "http://www.kasu.at/"
-1
View File
@@ -8,7 +8,6 @@ from django.template.defaultfilters import slugify
from django.utils.translation import ugettext as _
from utils.html5 import forms
from . import models
Binary file not shown.
+251
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"
+10 -5
View File
@@ -24,7 +24,8 @@ class Command(BaseCommand):
def create_article(self):
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={
'author': self.author,
'headline_de': self.headline,
@@ -37,9 +38,11 @@ class Command(BaseCommand):
article.save()
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:
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.content = match_obj.group('content').strip()
return True
@@ -47,7 +50,8 @@ class Command(BaseCommand):
return False
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:
self.date_created = datetime.strptime('01.01.1982', '%d.%m.%Y')
self.headline = match_obj.group('title').strip()
@@ -71,7 +75,8 @@ class Command(BaseCommand):
if not table.cell_value(row, 2) in ('Archiv', 'News'):
continue
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()
else:
print "Fehler bei String!"
@@ -2,6 +2,7 @@
from django.contrib.auth import get_user_model
from django.core.management.base import BaseCommand
from django.utils.datetime_safe import datetime
from events.models import Event, Location
import xlrd
+9 -17
View File
@@ -9,10 +9,9 @@ from django.db import models
from django.template.defaultfilters import slugify
from django.utils.safestring import mark_safe
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 kasu.image_models import ImageModel
from utils import STATUS_CHOICES, STATUS_WAITING, STATUS_PUBLISHED, \
cleaner
@@ -40,17 +39,6 @@ def get_upload_path(instance, filename):
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):
def published(self):
return self.filter(status=STATUS_PUBLISHED, date_created__lte=now())
@@ -65,7 +53,8 @@ class Article(ImageModel):
image = models.ImageField(_('Image'), upload_to='news/',
blank=True, null=True)
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,
default=STATUS_PUBLISHED)
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')
)
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,
help_text=_('This title appears in the HTML header'))
help_text=_(
'This title appears in the HTML header'))
slug = models.SlugField(_('slug'))
path = models.CharField(_('Path'), max_length=100, db_index=True,
editable=False, unique=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'),
blank=True, null=True)
status = models.SmallIntegerField(_('status'), choices=STATUS_CHOICES,
+30
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'),
)
-14
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]
@@ -7,11 +7,10 @@
{% block opengraph %}
<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: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}}" />
<meta property="og:description" content="{{article.content|striptags|truncatewords:25|force_escape}}" />
<link rel="image_src" type="image/jpeg" href="{{article.posting_image.url}}" />
{% endblock %}
+3 -1
View File
@@ -3,9 +3,11 @@ Created on 10.06.2012
@author: christian
"""
import copy
from django import template
from django.utils.datastructures import SortedDict
import copy
register = template.Library()
+15
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'),
)
+10 -6
View File
@@ -1,15 +1,17 @@
# Create your views here.
from . import models, forms
from aggregator.models import Feed
import os
from django.conf import settings
from django.contrib import comments
from django.http import HttpResponse, Http404
from django.utils.translation import ugettext as _
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
import events.models
import os
from django.shortcuts import get_object_or_404
class ArticleArchiveMixin(object):
@@ -53,7 +55,8 @@ class ArticleYearArchive(ArticleArchiveMixin, generic.YearArchiveView):
queryset = generic.YearArchiveView.get_queryset(self)
self.category = self.kwargs.get('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)
return queryset
@@ -98,7 +101,8 @@ class ImageList(generic.View):
response = HttpResponse(content_type='text/javascript')
response.write('var tinyMCEImageList = new Array(')
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()
for filename in filenames:
image_list.append('["%(name)s", "%(path)s"]' % {
+2 -1
View File
@@ -5,10 +5,11 @@ Created on 19.09.2011
"""
# import stuff we need from django
from django.contrib import admin
from events.models import Event, Photo, Location
from imagekit.admin import AdminThumbnail
from django.utils.translation import gettext as _
from events.models import Event, Photo, Location
class EventInline(admin.TabularInline):
model = Event
+1
View File
@@ -6,6 +6,7 @@ Created on 30.09.2011
"""
from . import models
def upcoming_events(request):
return {
'current_event': models.Event.objects.current_event(),
-39
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'
),
)
+5 -3
View File
@@ -3,20 +3,22 @@ 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 . import models
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,)
photographer = forms.ModelChoiceField(user_query, required=True, )
event = forms.ModelChoiceField(models.Event.objects.all(), required=True, )
upload = forms.FileField(
label=_('Images'),
required=True,
-34
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.
+300
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"
+9 -231
View File
@@ -1,33 +1,14 @@
# -'- 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'))
)
from gallery.models import Photo
from kasu import image_models
def get_upload_path(instance, filename):
@@ -56,79 +37,6 @@ def get_upload_path(instance, 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):
def current_event(self):
try:
@@ -155,7 +63,7 @@ class EventManager(models.Manager):
return result
class Event(ImageModel):
class Event(image_models.ImageModel):
name = models.CharField(_('Name'), max_length=255)
description = models.TextField(_("Description"), blank=True)
location = models.ForeignKey('Location')
@@ -232,7 +140,7 @@ class Event(ImageModel):
self.url = master_event.url
self.image = master_event.image
self.photo_count = self.photo_set.count()
models.Model.save(self, **kwargs)
super(Event, self).save(**kwargs)
# Update the rest of the event series:
for sub_event in Event.objects.filter(event_series=self):
@@ -243,7 +151,7 @@ class Event(ImageModel):
hanchan.save()
class Location(ImageModel):
class Location(image_models.ImageModel):
name = models.CharField(_("Name"), max_length=200)
description = models.TextField(_("Description"), blank=True)
image = models.ImageField(_("Image"), upload_to=get_upload_path,
@@ -267,137 +175,7 @@ class Location(ImageModel):
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)
models.signals.post_save.connect(image_models.regenerate_image_cache,
sender=Event)
models.signals.post_save.connect(image_models.regenerate_image_cache,
sender=Location)
-48
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]
+70 -36
View File
@@ -4,45 +4,64 @@
{% block title %}{{ event.name }}{% endblock %}
{% block opengraph %}
<meta property="og:type" content="activity" />
<meta property="og:title" content="{{event.name}}" />
<meta property="og:url" content="http://www.kasu.at{{event.get_absolute_url}}" />
<meta property="og:image" content="http://www.kasu.at{{ event.get_thumbnail.url }}" />
{% if event.description %}<meta property="og:description" content="{{event.description}}" />{% endif %}
<meta property="og:type" content="activity" />
<meta property="og:title" content="{{event.name}}" />
<meta property="og:url" content="http://www.kasu.at{{event.get_absolute_url}}" />
<meta property="og:image" content="http://www.kasu.at{{ event.get_thumbnail.url }}" />
{% if event.description %}<meta property="og:description" content="{{event.description}}" />{% endif %}
{% endblock %}
{% 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 %}
{% block jumbotron_background %}{{ event.get_callout.url }}')}{% endblock %}
{% block jumbotron_background %} {{ event.get_callout.url }} {% endblock %}
{% block teaser %}
<h2>{{event.name}}</h2>
<div id="teaser_text">
<h1>{{event.name}}</h1>
{% if event.description %}
{{event.description|markdown}}
{% else %}
{{event.location.description|markdown}}
<div id="teaser_text">{{event.description|markdown}}</div>
{% 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 %}
{% 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 %}
<div class="grid_4">
<h3>{% trans "Date" %}</h3>
<p></p>
<ul>
<li><strong>{% trans "Start" %}:</strong> {{ event.start }}</li>
{% if event.end %}<li><strong>{% trans "End" %}:</strong> {{ event.end }}</li>{% endif %}
{% if event.url %}<li><strong>{% trans "Homepage" %}:</strong> <a href="{{ event.url }}">{{ event.url }}</a></li>{% endif %}
</ul>
<div class="grid_6" id="google_maps">
&nbsp;
</div>
<div class="grid_4">
<div class="grid_6">
<h3>{% trans 'Location' %}</h3>
<strong>{{ event.location.name }}</strong>
<address>
@@ -53,28 +72,43 @@
{% if event.location.url %}
<p><strong>{% trans "Homepage" %}:</strong> <a href="{{ event.location.url }}">{{ event.location.url }}</a></p>
{% 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 class="grid_4 center">
<ul class="info">
<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>
<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>
</ul>
<div class="grid_12">
{% if event.description %}
{{event.description|markdown}}
{% else %}
{{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,
'', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=600,width=600');return false;"><img src="{{STATIC_URL}}img/google_plus.png" alt="Google+" title="{% trans 'Share on Google+'%}" width="39" height="39"/></a>
<a href="https://twitter.com/share?url=http%3A%2F%2Fwww.kasu.at{{event.get_absolute_url|urlencode}}" target='_blank'><img src="{{STATIC_URL}}img/twitter.png" alt="Twitter" title=" {% trans 'Share on Twitter' %}" width="39" height="39"/></a>
<a href="http://facebook.com/sharer.php?u=http%3A%2F%2Fwww.kasu.at{{event.get_absolute_url|urlencode}}" target="_blank"><img src="{{STATIC_URL}}img/facebook.png" alt="Facebook" title="{% trans 'Share on Facebook'%}" width="39" height="39"/></a>
<a href="http://maps.google.com/maps?q={{event.location.address|urlencode}}&amp;z=16" target="gmaps"><img src="{{ STATIC_URL }}img/google_maps.png" alt="Google Maps" title="{% trans 'Show on Google Maps' %}" width="39" height="39"/></a>
</p>
</div>
<br class="clear" />
{% render_comment_list for event %}
{% render_comment_form for event %}
{% block event_content %} {% endblock %}
{% endblock %}
{% block comments %}
{% render_comment_list for event %}
{% render_comment_form for event %}
{% endblock %}
{% block buttonbar %}
{% 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>
{% endif %}
{% 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>
{% endif %}
{% endblock %}
{% block javascript %}
@@ -103,8 +137,8 @@
center: latlng,
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();
}
initialize();
{% endblock %}
{% endblock %}
+1 -17
View File
@@ -1,4 +1,4 @@
{% extends "events/page.html" %}
{% extends "base.html" %}
{% load i18n django_markdown%}
{% block title %}{{ event.name }}{% endblock %}
@@ -20,20 +20,4 @@
</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 %}
+3 -1
View File
@@ -5,7 +5,9 @@
{% 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 %}
{% block additional_buttonbar %}
+19
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'),
)
+20 -8
View File
@@ -15,7 +15,6 @@ from icalendar import Calendar, Event
import pyexiv2
from utils.mixins import PermissionRequiredMixin
from . import models, forms
@@ -80,9 +79,17 @@ class EventArchiveYear(generic.YearArchiveView):
class EventDetail(generic.DetailView):
model = models.Event
class EventDetailMixin(object):
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})
context = super(EventDetailMixin, self).get_context_data(**kwargs)
if hasattr(self, 'event'):
context['event'] = self.event
else:
context['event'] = self.object.event
print "EventDetailMixin"
print dir(context['event'])
return context
@@ -108,7 +115,8 @@ class EventForm(PermissionRequiredMixin, generic.UpdateView):
class EventGallery(generic.ListView):
template_name = 'events/photo_gallery.html'
queryset = models.Event.objects.filter(start__lt=timezone.now(), photo_count__gt=0)
queryset = models.Event.objects.filter(start__lt=timezone.now(),
photo_count__gt=0)
paginate_by = 12
@@ -156,7 +164,8 @@ class EventPhoto(generic.UpdateView):
return context
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.rotate(request.POST['rotate'])
# return redirect(photo.get_absolute_url())
@@ -172,7 +181,8 @@ class EventPhotoList(generic.ListView):
def get_context_data(self, **kwargs):
context = generic.ListView.get_context_data(self, **kwargs)
context['event'] = self.event
context['form'] = forms.PhotoUploadForm(initial={'event': self.event, 'photographer': self.request.user})
context['form'] = forms.PhotoUploadForm(
initial={'event': self.event, 'photographer': self.request.user})
return context
def get_queryset(self):
@@ -208,8 +218,10 @@ class EventPhotoUpload(generic.FormView):
"""
"""
self.event = models.Event.objects.get(id=self.request.REQUEST.get('event'))
photographer = self.request.POST.get('photographer', self.request.user.id)
self.event = 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'):
+1
View File
@@ -0,0 +1 @@
__author__ = 'christian'
+57
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
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)
@@ -25,7 +25,7 @@
{% for event in event_list %}
<div class="gallery grid_4">
<h3><a href="{% url 'event-photo-list' event.id %}">{{event.name}}</a></h3>
<a href="{% url 'event-photo-list' event.id %}"><img src="{{event.get_thumbnail.url}}" class="thumbnail"/></a>
<a href="{% url 'event-photo-list' event.id %}"><img src="{{event.get_thumbnail.url}}" class="thumbnail" alt="{{ event.name }}"/></a>
</div>
{% empty %}
<p>Sorry da kommt erst was hin!</p>
@@ -1,4 +1,4 @@
{% extends "events/event_site.html" %}
{% extends "events/event_detail.html" %}
{% load i18n %}
@@ -12,25 +12,6 @@
{% if event.description %}<meta property="og:description" content="{{event.description}}" />{% endif %}
{% 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 %}
{% if perms.events.delete_photo %}
{% for photo in photo_list %}
View File
+247
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
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
Binary file not shown.
File diff suppressed because it is too large Load Diff
-2563
View File
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -1,5 +1,4 @@
from os import path
from django.template.defaultfilters import slugify
gettext = lambda s: s
PROJECT_PATH = path.abspath(path.join(path.dirname(__file__), '..', '..'))
@@ -11,6 +10,7 @@ PREREQ_APPS = [
'django.contrib.auth',
'django.contrib.comments',
'django.contrib.contenttypes',
'django.contrib.humanize',
'django.contrib.messages',
'django.contrib.sessions',
'django.contrib.sites',
@@ -22,8 +22,10 @@ PROJECT_APPS = [
'aggregator',
'content',
'events',
'gallery',
'imagekit',
'membership',
'maistar_ranking',
'mahjong_ranking',
]
@@ -39,7 +41,6 @@ EMAIL_HOST_PASSWORD = "Ees6aang"
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = "webmaster@kasu.at"
LOCALE_PATHS = (path.join(PROJECT_PATH, 'kasu', 'locale/'),)
AUTH_PROFILE_MODULE = 'membership.Membership'
@@ -120,7 +121,7 @@ STATICFILES_DIRS = (
# Put strings here, like "/home/html/static" or "C:/www/django/static".
# Always use forward slashes, even on Windows.
# 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
@@ -151,7 +152,7 @@ TEMPLATE_LOADERS = (
)
TEMPLATE_DIRS = (
path.join(PROJECT_PATH, 'templates/'),
path.join(PROJECT_PATH, 'kasu/templates/'),
)
TEMPLATE_CONTEXT_PROCESSORS = (
@@ -197,7 +198,6 @@ LOGIN_ERROR_URL = '/membership/login/error/'
LOGIN_REDIRECT_URL = '/users/'
SOCIAL_AUTH_NEW_USER_REDIRECT_URL = '/users/'
SOCIAL_AUTH_FACEBOOK_KEY = '115196761917023'
SOCIAL_AUTH_FACEBOOK_SECRET = '6edf715f0506a1177b5479f8cae47566'
SOCIAL_AUTH_FACEBOOK_SCOPE = ['user_about_me', 'email']
+4 -2
View File
@@ -6,11 +6,11 @@ from base import *
DEBUG = True
TEMPLATE_DEBUG = True
INSTALLED_APPS.append('maistar_ranking')
# Load the Rosetta translation tool
try:
import rosetta # @UnusedImport
INSTALLED_APPS.append('rosetta')
except ImportError:
pass
@@ -18,7 +18,9 @@ except ImportError:
# Load the Django debug toolbar
try:
import debug_toolbar # @UnusedImport
INSTALLED_APPS.append('debug_toolbar')
MIDDLEWARE_CLASSES.append('debug_toolbar.middleware.DebugToolbarMiddleware') # @IgnorePep8
MIDDLEWARE_CLASSES.append(
'debug_toolbar.middleware.DebugToolbarMiddleware') # @IgnorePep8
except ImportError:
pass
+15 -6
View File
@@ -1,4 +1,7 @@
__author__ = "christian"
##########################################
# Settings for the production enviroment #
##########################################
__author__ = 'Christian Berg'
from base import *
# A sample logging configuration. The only tangible logging
@@ -10,18 +13,24 @@ from base import *
DEBUG = False
SESSION_COOKIE_DOMAIN = '.kasu.at' # Die ganze Domain Kasu
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 = {
'version': 1,
'disable_existing_loggers': True,
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse'
}
'require_debug_false': {'()': 'django.utils.log.RequireDebugFalse'}
},
'formatters': {
'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': {
'format': '%(levelname)s %(message)s'
+75
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,
},
}
}
+7 -3
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;
}
h1, h2, h3, h4, h5, h6 {
h1, h2, h3, h4, h5, h6, .player {
color: #bc0a19;
font-family: 'Amerika Sans', sans-serif;
font-variant: small-caps;
@@ -117,6 +117,10 @@ h1, h2, h3, h4, h5, h6 {
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 {
border: 0;
margin: 0;
@@ -356,11 +360,11 @@ ul.info li {
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 */
}
#redbox h2 {
#redbox h2:first-of-type {
margin: -1em 10px 0 0;
color: black;
}
#redbox h3 {
#redbox h2, #redbox h3 {
color: white;
}
-585
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; }
+14 -14
View File
@@ -201,11 +201,10 @@ ul.main_menu {padding:0px;}
border-radius: 10px;
background-repeat: no-repeat;
background-color: #333;
background-position: center right;
background-size: cover;
background-position: center left;
}
#jumbotron > h2 {
#jumbotron > h2, #jumbotron > h1 {
padding: 10px 5px;
font-size: 32pt;
color: #eff0ef;
@@ -240,6 +239,7 @@ ul.main_menu {padding:0px;}
border-radius: 0px 10px 10px 0px;
}
#toggle, .toggle {display: none;}
#bottom_buttonbar {
@@ -295,17 +295,6 @@ ul.main_menu {padding:0px;}
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 {
position: absolute;
right: 4px;
@@ -481,3 +470,14 @@ img.avatar {
.grid_12 {
width: 940px;
}
#recaptcha_widget_div {margin-top: -20px;}
#google_maps {
position: relative;
top: 0px;
left: 0px;
height: 280px;
padding: 10px;
border-radius: 0px 10px 10px 0px;
}
+13
View File
@@ -98,6 +98,8 @@ img {max-width: 100%; height: auto;}
background: rgba(255, 255, 255, 0.5);
}
#navigation {margin: 10px 0; padding: 0}
#navigation li {
display: inline-block;
background: #45484d url("../img/buttonbar.gif") top left repeat-x;
@@ -118,6 +120,14 @@ img {max-width: 100%; height: auto;}
height: 54px;
}
#siteheader:after {
content: ".";
clear: both;
display: block;
visibility: hidden;
height: 0px;
}
/* Dynamische Menü */
#mainnav {
display: block;
@@ -190,6 +200,9 @@ img {max-width: 100%; height: auto;}
transition: all 0.25s linear;
}
#jumbotron {background: none !important;}
#redbox {display: block;}
.main_menu>li>a:hover,.menu>li>a:focus {
box-shadow: inset 5px 0px #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