Anpassungen für das Hosting bei Djangoeurope und damit verbundenen Versionen Django 1.8 und Python 2.7

This commit is contained in:
Christian Berg
2015-08-05 18:55:48 +02:00
committed by Christian Berg
parent cb4b15b3c6
commit 37d3cb78c1
1355 changed files with 7289 additions and 6858 deletions

0
src/events/__init__.py Normal file
View File

50
src/events/admin.py Normal file
View File

@@ -0,0 +1,50 @@
"""
Created on 19.09.2011
@author: christian
"""
# import stuff we need from django
from django.contrib import admin
from imagekit.admin import AdminThumbnail
from django.utils.translation import gettext as _
from events.models import Event, Photo, Location
class EventInline(admin.TabularInline):
model = Event
fields = ('name', 'start', 'end')
verbose_name_plural = _('Event Series')
class EventAdmin(admin.ModelAdmin):
list_display = ('name', 'start', 'end', 'location',)
list_editable = ('start', 'end', 'location',)
readonly_fields = ('event_series',)
date_hierarchy = 'start'
search_fields = ('name', 'description')
list_per_page = 50
inlines = (EventInline,)
class LocationAdmin(admin.ModelAdmin):
list_display = ('name', 'street_address', 'postal_code', 'locality')
class PhotoAdmin(admin.ModelAdmin):
admin_thumbnail = AdminThumbnail(image_field='thumbnail')
fields = ('image', 'event', 'name', 'description',
('anchor_horizontal', 'anchor_vertical'),
('photographer', 'created_date'))
list_filter = ('event', 'on_startpage',)
list_display = ('admin_thumbnail', 'image', 'name', 'event',
'photographer', 'on_startpage')
list_display_links = ('image',)
list_editable = ('on_startpage', 'name', 'event', 'photographer')
# register with CMS
admin.site.register(Event, EventAdmin)
admin.site.register(Photo, PhotoAdmin)
admin.site.register(Location, LocationAdmin)

View File

@@ -0,0 +1,15 @@
# -*- encoding: UTF-8 -*-
"""
Created on 30.09.2011
@author: christian
"""
from . import models
def upcoming_events(request):
return {
'current_event': models.Event.objects.current_event(),
'next_event': models.Event.objects.next_event(),
'upcoming_events': models.Event.objects.upcoming(),
}

60
src/events/forms.py Normal file
View File

@@ -0,0 +1,60 @@
"""
Created on 03.10.2011
@author: christian
"""
from django import forms
from django.utils.translation import ugettext as _
from django.contrib.auth import get_user_model
from . import models
from 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
exclude = ('event_count', 'event_series', )

Binary file not shown.

View File

@@ -0,0 +1,302 @@
# 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: 2015-01-05 19:23+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:101 templates/events/event_detail.html:110
#: templates/events/event_form.html:9
msgid "Edit Event"
msgstr "Termin bearbeiten"
#: views.py:103 templates/events/event_form.html:9
#: templates/events/page.html:15
msgid "Add Event"
msgstr "Neuer Termin"
#: views.py:199
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_form.html:19
msgid "reset"
msgstr "Zurücksetzen"
#: templates/events/event_form.html:20
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"

181
src/events/models.py Normal file
View File

@@ -0,0 +1,181 @@
# -'- Encoding: utf-8 -*-
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 utils import COUNTRIES, OverwriteStorage
from gallery.models import Photo
from kasu import image_models
def get_upload_path(instance, filename):
"""
Generates the desired file path and filename for an uploaded Image.
With this function Django can save the uploaded images to subfolders that
also have a meaning for humans.
@param instance: an Django Object for which the Image has been uploaded.
@type instance: a instace of an models.Model sub-class.
@param filename: The filename of the uploaded image.
@type filename: String
"""
extension = filename[filename.rfind('.') + 1:]
if isinstance(instance, 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)
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(image_models.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()
super(Event, self).save(**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(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,
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)
models.signals.post_save.connect(image_models.regenerate_image_cache,
sender=Event)
models.signals.post_save.connect(image_models.regenerate_image_cache,
sender=Location)

View File

@@ -0,0 +1,76 @@
{% extends "events/page.html" %}
{% load i18n comments%}
{% block title %}
{% trans 'Event Archive' %} {% if month %}{{ month|date:'F Y' }} {% else %}{% if year %}{{year}}{% endif %}{% endif %}
{% endblock %}
{% block teaser %}
<h2>{% trans 'Event Archive' %} {% if month %}{{ month|date:'F Y' }}{% elif year %}{{year|date:'Y'}}{% endif %}</h2>
{% endblock %}
{% block redbox %}
<h2>Archive</h2>
<ul>
{% if year %}
{% for date in date_list %}
<li><a href="{% url 'event-archive' year|date:'Y' date|date:'m' %}">{{ date|date:'F' }}</a></li>
{% endfor %}
{% elif month %}
<li><a href="{% url 'event-archive' month|date:'Y' %}">{{ month|date:'Y' }}</a></li>
{% else %}
{% for date in date_list %}
<li><a href="{% url 'event-archive' date|date:'Y' %}">{{ date|date:'Y' }}</a></li>
{% endfor %}
{% endif %}
</ul>
{% endblock %}
{% block maincontent %}
{% regroup event_list by start|date:'F Y' as month_list %}
{% for month in month_list %}
<h3 class="grid_12">{{ month.grouper }}</h3>
{% for event in month.list %}
{% get_comment_count for event as comment_count %}
<a href="{{ event.get_absolute_url }}" class="grid_2"><img src="{{ event.get_thumbnail.url }}"
alt="{% trans 'Event Image' %}"
class="thumbnail"/></a>
<div class="grid_4">
<h4><a href="{{ event.get_absolute_url }}">{{ event.name }}</a></h4>
<p><img src="{{ STATIC_URL }}/icons/date.png" alt="{% trans 'Start' %}:" title="{% trans 'Start' %}">
{{ event.start|date }}
{% if event.end %}
{% trans "from" %} {{ event.start|time:'H:i' }} {% trans "to" %} {{ event.end|time:'H:i' }}
{% else %}
{{ event.start|time:'H:i' }}
{% endif %}
</p>
<p>{{event.description|truncatewords_html:20}}</p>
<ul class="info">
<li><img src="{{ STATIC_URL }}/icons/map.png" alt="{% trans 'Location' %}" title="{% trans 'Location' %}">
{{ event.location }}
</li>
<li><a href="{{event.get_absolute_url}}#comments"><img src="{{ STATIC_URL }}/icons/comments.png"
alt="{% trans 'Comments' %}"
title="{% trans 'Comments' %}"> {{ comment_count }}</a>
</li>
<li><a href="{% url 'event-photo-list' event.pk %}"><img src="{{ STATIC_URL }}/icons/camera.png"
alt="{% trans 'Photos' %}"
title="{% trans 'Photos' %}">
{{ event.photo_count }}</a></li>
<li><a href="{% url 'event-hanchan-list' event.pk %}"><img src="{{ STATIC_URL }}/icons/table.png"
alt="{% trans 'Hanchans' %}"
title="{% trans 'Hanchans' %}">
{{ event.hanchan_set.count }} {% trans 'Hanchans' %}</a></li>
</ul>
{% if perms.events.change_event %}
<p class="right"><a href="{{ event.get_edit_url }}" class="button"><img src="{{ STATIC_URL }}icons/page_edit.png"
alt="{%trans " Edit" %}"></a></p>
{% endif %}
</div>
{% if forloop.counter|divisibleby:2 %}<br class="clear"/>{% endif %}
{% endfor %}
{% endfor %}
{% endblock %}

View File

@@ -0,0 +1,144 @@
{% extends "events/page.html" %}
{% load i18n django_markdown comments %}
{% 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 %}
{% endblock %}
{% block extra_head %}
<script type="text/javascript" src="https://maps.google.com/maps/api/js?sensor=false"></script>
{% endblock %}
{% block jumbotron_background %} {{ event.get_callout.url }} {% endblock %}
{% block teaser %}
<h1>{{event.name}}</h1>
{% if event.description %}
<div id="teaser_text">{{event.description|markdown|truncatewords_html:75}}</div>
{% endif %}
{% 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_6" id="google_maps">
&nbsp;
</div>
<div class="grid_6">
<h3>{% trans 'Location' %}</h3>
<strong>{{ event.location.name }}</strong>
<address>
{{event.location.street_address}}<br />
{{event.location.postal_code}} {{event.location.locality}} <br />
{{event.location.get_country_display}}
</address>
{% 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_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" />
{% 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 %}
{% endblock %}
{% block javascript %}
var geocoder;
var map;
function codeAddress() {
var address = "{{ event.location.address }}";
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location
});
} else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}
function initialize() {
geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(-34.397, 150.644);
var mapOptions = {
zoom: 16,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("google_maps"), mapOptions);
codeAddress();
}
initialize();
{% endblock %}

View File

@@ -0,0 +1,28 @@
{% extends "events/page.html" %}
{% load i18n %}
{% block title %}{{ title }}{% endblock %}
{% block maincontent %}
<form method="post" enctype="multipart/form-data" class="grid_12">
{% csrf_token %}
<fieldset>
<legend>{% if event.pk %}{% trans "Edit Event"%}{% else %}{% trans "Add Event"%}{% endif %}</legend>
{% include "form.html" %}
{% if event.id and event.event_set.count %}
<p class="warning">
<strong>Achtung! Das ist eine Veranstaltungsreihe!</strong> Diese kann man im Moment nur im Admin-Interface vernünfig bearbeiten.<br />
Du bearbeitest hier den "Hauptevent" der Reihe ({{event.event_set.count}}). Alle Änderungen (abgesehen von Name, Start und Ende) werden von den darauf folgendem Veranstaltungen übernommen.
</strong>
</p>
{% endif %}
<p class="buttonbar">
<button type="reset"><img src="{{STATIC_URL}}icons/arrow_undo.png" alt="{% trans 'reset' %}" /> {% trans 'reset' %}</button>
<button type="submit"><img src="{{STATIC_URL}}icons/disk.png" alt="{% trans 'save' %}" /> {% trans 'save' %}</button>
</p>
</fieldset>
</form>
{% endblock %}
{% block buttonbar %}{% endblock %}

View File

@@ -0,0 +1,49 @@
{% extends "events/page.html" %}
{% load i18n comments%}
{% block title %}{% trans "Upcoming Events" %}{% endblock %}
{% block teaser%}<h2>{% trans "Upcoming Events" %}</h2>{% endblock %}
{% block maincontent %}
{% for event in event_list %}
{% ifchanged %}<h3 class="grid_12">{{ event.start|date:'F Y' }}</h3>{% endifchanged %}
{% get_comment_count for event as comment_count %}
<a href="{{ event.get_absolute_url }}" class="grid_2"><img src="{{ event.get_thumbnail.url }}" alt=" {% trans 'Event Image' %}"
class="thumbnail"/></a>
<div class="grid_4">
<h4><a href="{{ event.get_absolute_url }}">{{ event.name }}</a></h4>
<p class="strong"><img src="{{ STATIC_URL }}/icons/date.png" alt="{% trans 'Start' %}:" title="{% trans 'Start' %}">
{{ event.start|date:'SHORT_DATE_FORMAT' }}
{% if event.end %}
{% trans "from" %} {{ event.start|time:'H:i' }} {% trans "to" %} {{ event.end|time:'H:i' }}
{% else %}
{{ event.start|time:'H:i' }}
{% endif %}
</p>
<p>{{event.description|truncatewords_html:20}}</p>
<ul class="info">
<li>
<img src="{{ STATIC_URL }}/icons/map.png" alt="{% trans 'Location' %}" title="{% trans 'Location' %}">
{{ event.location }}
</li>
<li>
<img src="{{ STATIC_URL }}/icons/comments.png" alt="{% trans 'Comments' %}" title="{% trans 'Comments' %}">
<a href="{{event.get_absolute_url}}#comments">{{ comment_count }}</a>
</li>
</ul>
<p class="right">
{% if perms.events.change_event %}
<a href="{{ event.get_edit_url }}" class="button"><img src="{{ STATIC_URL }}icons/page_edit.png" alt="{%trans "
Edit" %}"></a>
{% endif %}
{% if perms.events.add_photo %}
<a href="{% url 'event-photo-list' event.pk %}" class="button"><img src="{{ STATIC_URL }}icons/image_add.png"
alt="{%trans " Upload" %}"></a>
{% endif %}
</p>
</div>
{% endfor %}
{% if page_obj.has_other_pages %}{% include 'paginator.html' %}{% endif %}
{% endblock %}

View File

@@ -0,0 +1,23 @@
{% extends "base.html" %}
{% load i18n django_markdown%}
{% 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 %}
{% endblock %}
{% block jumbotron_background %}{{ event.get_callout.url }}')}{% endblock %}
{% block teaser %}
<h2>{{event.name}}</h2>
<div id="teaser_text">
{% if event.description %}{{event.description|markdown}}{% else %}{{event.location.description|markdown}}{% endif %}
</div>
{% endblock %}

View File

@@ -0,0 +1,24 @@
{% extends "base.html" %}
{% load comments i18n %}
{% block title %}{{page.title}}{% endblock %}
{% 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="{% trans 'Add to Google Calendar' %}"></a>
{% endblock %}
{% block additional_buttonbar %}
{% if perms.events.add_event %}
<a href="{% url 'event-form' %}" class="button"><img src="{{ STATIC_URL }}icons/calendar_add.png" alt=""/> {% trans 'Add Event' %}</a>
{% endif %}
{% endblock %}
{% block content %}{{ page.content }}{% endblock %}

16
src/events/tests.py Normal file
View File

@@ -0,0 +1,16 @@
"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)

19
src/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'),
)

265
src/events/views.py Normal file
View File

@@ -0,0 +1,265 @@
# -*- 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
class EventDetailMixin(object):
def get_context_data(self, **kwargs):
context = super(EventDetailMixin, self).get_context_data(**kwargs)
if hasattr(self, 'event'):
context['event'] = self.event
else:
context['event'] = self.object.event
return context
class EventForm(PermissionRequiredMixin, generic.UpdateView):
form_class = forms.EventForm
permission_required = 'events.add_event'
def get_context_data(self, **kwargs):
context = super(EventForm, self).get_context_data(**kwargs)
if self.kwargs.get('pk'):
context['title'] = _("Edit Event")
else:
context['title'] = _("Add Event")
return context
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