Milestone 08-14
* Mahjong Ranking wurde stark vereinfacht um Fehler besser vorzubeugen. * Online WYSIWYG Editor auf CKEditor umgeändert, damit online bearbeiten für unbedarfte besser funktioniert. * Viele kleine Optimierungen am CSS für bessere Performance. * CSS wird jetzt aus LESS Code generiert * Für dise Arbeit wird jetzt grunt und node package management lokal verwendet.
This commit is contained in:
@@ -7,19 +7,19 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: kasu.events\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-08-16 11:34+0200\n"
|
||||
"PO-Revision-Date: 2014-12-08 16:06+0100\n"
|
||||
"Last-Translator: Christian Berg <xeniac.at@gmail.com>\n"
|
||||
"POT-Creation-Date: 2015-08-22 23:28+0200\n"
|
||||
"PO-Revision-Date: 2015-08-22 15:08+0100\n"
|
||||
"Last-Translator: Christian Berg <xeniac@posteo.at>\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"
|
||||
"X-Generator: Poedit 1.8.3\n"
|
||||
"X-Translated-Using: django-rosetta 0.7.6\n"
|
||||
|
||||
#: admin.py:17 models.py:81
|
||||
#: admin.py:17 models.py:82
|
||||
msgid "Event Series"
|
||||
msgstr "Veranstaltungsreihen"
|
||||
|
||||
@@ -35,11 +35,11 @@ msgstr "Beginn"
|
||||
msgid "end"
|
||||
msgstr "Ende"
|
||||
|
||||
#: models.py:67 models.py:161
|
||||
#: models.py:67 models.py:163
|
||||
msgid "Name"
|
||||
msgstr "Name"
|
||||
|
||||
#: models.py:68 models.py:162
|
||||
#: models.py:68 models.py:164
|
||||
msgid "Description"
|
||||
msgstr "Beschreibung"
|
||||
|
||||
@@ -53,18 +53,18 @@ msgstr "Beginn"
|
||||
msgid "End"
|
||||
msgstr "Ende"
|
||||
|
||||
#: models.py:72 models.py:165 templates/events/event_detail.html:36
|
||||
#: models.py:72 models.py:167 templates/events/event_detail.html:36
|
||||
#: templates/events/event_detail.html:72 templates/events/event_detail.html:78
|
||||
msgid "Homepage"
|
||||
msgstr "Homepage"
|
||||
|
||||
#: models.py:73 models.py:163
|
||||
#: models.py:73 models.py:165
|
||||
msgid "Image"
|
||||
msgstr "Bild"
|
||||
|
||||
#: models.py:75
|
||||
msgid "Tournament"
|
||||
msgstr "Turnier"
|
||||
msgid "Mahjong Tournament"
|
||||
msgstr "Mahjong Turnier"
|
||||
|
||||
#: models.py:76
|
||||
msgid ""
|
||||
@@ -74,7 +74,11 @@ msgstr ""
|
||||
"Diese Veranstaltung ist ein Turnier, es gelten andere Regeln für das Kyu "
|
||||
"Ranking."
|
||||
|
||||
#: models.py:82
|
||||
#: models.py:78
|
||||
msgid "Mahjong Season"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:83
|
||||
msgid ""
|
||||
"Wenn dieser Event zu einer Veranstaltungsreihe gehört werden Ort, "
|
||||
"Beschreibung, Bild und Homepage von dem hier angegebenen Event "
|
||||
@@ -83,35 +87,35 @@ msgstr ""
|
||||
"Wenn dieser Termin zu einer Veranstaltungsreihe gehört werden Ort, "
|
||||
"Beschreibung, Bild und Homepage von dem hier angegebenen Event übernommen."
|
||||
|
||||
#: models.py:88
|
||||
#: models.py:90
|
||||
msgid "Event"
|
||||
msgstr "Termin"
|
||||
|
||||
#: models.py:89
|
||||
#: models.py:91
|
||||
msgid "Events"
|
||||
msgstr "Termine"
|
||||
|
||||
#: models.py:166
|
||||
#: models.py:168
|
||||
msgid "Postal Code"
|
||||
msgstr "Postleitzahl"
|
||||
|
||||
#: models.py:167
|
||||
#: models.py:169
|
||||
msgid "Street Address"
|
||||
msgstr "Straße"
|
||||
|
||||
#: models.py:168
|
||||
#: models.py:170
|
||||
msgid "Locality"
|
||||
msgstr "Ort"
|
||||
|
||||
#: models.py:169
|
||||
#: models.py:171
|
||||
msgid "Country"
|
||||
msgstr "Land"
|
||||
|
||||
#: models.py:172
|
||||
#: models.py:174
|
||||
msgid "Venue"
|
||||
msgstr "Veranstaltungsort"
|
||||
|
||||
#: models.py:173
|
||||
#: models.py:175
|
||||
msgid "Venues"
|
||||
msgstr "Veranstaltungsorte"
|
||||
|
||||
@@ -198,10 +202,8 @@ msgid "Edit Event"
|
||||
msgstr "Termin bearbeiten"
|
||||
|
||||
#: templates/events/event_detail.html:112
|
||||
#, fuzzy
|
||||
#| msgid "Date"
|
||||
msgid "Add Dates"
|
||||
msgstr "Datum"
|
||||
msgstr "Termine hinzufügen"
|
||||
|
||||
#: templates/events/event_form.html:9 templates/events/page.html:9
|
||||
#: views.py:105
|
||||
@@ -223,7 +225,7 @@ msgstr "Bevorstehende Veranstaltungen"
|
||||
|
||||
#: templates/events/eventseries_form.html:29
|
||||
msgid "back"
|
||||
msgstr ""
|
||||
msgstr "Zurück"
|
||||
|
||||
#: views.py:214
|
||||
msgid "Event does not exist"
|
||||
|
||||
28
src/events/migrations/0002_auto_20150818_2139.py
Normal file
28
src/events/migrations/0002_auto_20150818_2139.py
Normal file
@@ -0,0 +1,28 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='event',
|
||||
name='is_tournament',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='event',
|
||||
name='mahjong_season',
|
||||
field=models.PositiveSmallIntegerField(null=True, verbose_name='Mahjong Season', blank=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='event',
|
||||
name='mahjong_tournament',
|
||||
field=models.BooleanField(default=False, help_text='Diese Veranstaltung ist ein Turnier, es gelten andere Regeln f\xfcr das Kyu Ranking.', verbose_name='Mahjong Tournament'),
|
||||
),
|
||||
]
|
||||
@@ -72,16 +72,18 @@ class Event(image_models.ImageModel):
|
||||
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 \
|
||||
mahjong_tournament = models.BooleanField(_('Mahjong Tournament'), default=False,
|
||||
help_text=_(u'This event is a tournament, different rules apply for \
|
||||
the kyu ranking.'))
|
||||
mahjong_season = models.PositiveSmallIntegerField(_('Mahjong Season'), blank=True, null=True)
|
||||
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 \
|
||||
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.'))
|
||||
Event übernommen.')
|
||||
)
|
||||
objects = EventManager()
|
||||
|
||||
class Meta(object):
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
{% if event.url %}<li><span class="fa-li fa fa-globe"></span> <strong>{% trans "Homepage" %}:</strong> <a href="{{ event.url }}">{{ event.url }}</a></li>{% endif %}
|
||||
<li><span class="fa-li fa fa-table"></span> <strong>{% trans "Hanchans" %}:</strong> <a href="{% url 'event-hanchan-list' event.pk %}" >{{ event.hanchan_set.count }}</a></li>
|
||||
<li><span class="fa-li fa fa-camera-retro"></span> <strong>{% trans 'Photos' %}:</strong> <a href="{% url 'event-photo-list' event.pk %}">{{ event.photo_count }}</a></li>
|
||||
{% if event.is_tournament %}<li><span class="fa-li fa fa-trophy"></span> <strong>{% trans "tourney" %}:</strong> <a href="{% url 'event-ranking' event.pk %}">{% trans "other rules apply here" %}</a></li>{% endif%}
|
||||
{% if event.mahjong_tournament %}<li><span class="fa-li fa fa-trophy"></span> <strong>{% trans "tourney" %}:</strong> <a href="{% url 'event-ranking' event.pk %}">{% trans "other rules apply here" %}</a></li>{% endif%}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
<li><a href="{% url 'event-hanchan-list' event.pk %}" ><span class="fa fa-table"></span> {{ event.hanchan_set.count }} {% trans "Hanchans" %}</a></li>
|
||||
<li><a href="{% url 'maistar-game-list' event.pk %}" ><span class="fa fa-glass"></span> {{ event.maistargame_set.count }} {% trans "Mai-Star Games" %}</a></li>
|
||||
|
||||
{% if event.is_tournament %}
|
||||
{% if event.mahjong_tournament %}
|
||||
<li><a href="{% url 'event-ranking' event.id %}"><span class="fa fa-trophy"></span> {% trans "Tournament Ranking" %}</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
225
src/events/views.py~
Normal file
225
src/events/views.py~
Normal file
@@ -0,0 +1,225 @@
|
||||
# Create your views here.
|
||||
from . import models, forms
|
||||
from datetime import datetime
|
||||
from django.contrib.auth.decorators import permission_required
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import redirect
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views import generic
|
||||
from utils.icalendar import Calendar, Event
|
||||
from dateutil.tz import gettz
|
||||
import pyexiv2
|
||||
|
||||
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
|
||||
paginate_by = 5
|
||||
|
||||
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(generic.UpdateView):
|
||||
template_name = 'events/event_form.html'
|
||||
form_class = forms.EventForm
|
||||
|
||||
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'):
|
||||
return models.Event.objects.get(pk=self.kwargs['pk'])
|
||||
else:
|
||||
return models.Event()
|
||||
|
||||
@method_decorator(permission_required('events.update_event'))
|
||||
def dispatch(self, *args, **kwargs):
|
||||
return super(EventForm, self).dispatch(*args, **kwargs)
|
||||
|
||||
|
||||
class EventGallery(generic.ListView):
|
||||
template_name = 'events/event_gallery.html'
|
||||
queryset = models.Event.objects.filter(start__lt=datetime.now(), photo_count__gt=0)
|
||||
|
||||
class EventListIcal(generic.View):
|
||||
'''
|
||||
Generates an returns an iCal File with all upcoming events.
|
||||
'''
|
||||
|
||||
def add_event(self, event):
|
||||
ics_event = Event()
|
||||
dtstart = event.start.replace(tzinfo=self.tzinfo)
|
||||
|
||||
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('attach', '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:
|
||||
dtend = event.end.replace(tzinfo=self.tzinfo)
|
||||
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')
|
||||
self.tzinfo = gettz('CET')
|
||||
for event in models.Event.objects.upcoming(limit=None):
|
||||
self.add_event(event)
|
||||
response.write(self.calendar.as_string())
|
||||
return response
|
||||
|
||||
|
||||
class EventPhoto(generic.UpdateView):
|
||||
form_class = forms.EditPhotoForm
|
||||
model = models.Photo
|
||||
template_name = 'events/event_photo.html'
|
||||
|
||||
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'])
|
||||
photo.save()
|
||||
#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
|
||||
template_name = 'events/event_photolist.html'
|
||||
|
||||
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})
|
||||
print self.event.get_absolute_url()
|
||||
return context
|
||||
|
||||
def get_queryset(self):
|
||||
self.event = models.Event.objects.get(id=self.kwargs['event'])
|
||||
return models.Photo.objects.filter(event=self.event)
|
||||
|
||||
class EventPhotoUpload(generic.FormView):
|
||||
form_class = forms.PhotoUploadForm
|
||||
template_name = 'events/upload_photo.html'
|
||||
|
||||
@method_decorator(permission_required('event.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):
|
||||
'''
|
||||
|
||||
'''
|
||||
event = models.Event.objects.get(id=self.request.REQUEST.get('event'))
|
||||
photographer = self.request.POST.get('photographer')
|
||||
if photographer:
|
||||
photographer = User.objects.get(id=photographer)
|
||||
else:
|
||||
photographer = self.request.user
|
||||
|
||||
for upload in self.request.FILES.getlist('upload'):
|
||||
name = upload.name
|
||||
created_date, description = self.read_exif(upload)
|
||||
photo = models.Photo(
|
||||
event=event,
|
||||
photographer=photographer,
|
||||
image=upload,
|
||||
name=name,
|
||||
created_date=created_date,
|
||||
description=description
|
||||
)
|
||||
photo.save()
|
||||
return redirect('event-photo-list', event=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 = datetime.now()
|
||||
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 = 12
|
||||
Reference in New Issue
Block a user