Fehler bei Vergabe von Bonuspunkte korrigiert.
Kommentare für Bonuspunkte werden jetzt als Kommentar beim Spieler hinterlassen, nicht als Kommentar in der Hanchan. FIXED: 3_in_a_row counter wurde nicht zurückgesetzt wenn Bonuspunkte vergeben wurden. FIXED: Durchschnittliche Platzierung während eines Events wurde nur als Ganzzahl berechnet. Wird nun als Fießkomma berechnet und gesichert.
This commit is contained in:
@@ -5,7 +5,6 @@ Created on 19.09.2011
|
||||
"""
|
||||
# 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
|
||||
@@ -19,7 +18,7 @@ class EventInline(admin.TabularInline):
|
||||
|
||||
class EventAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'start', 'end', 'location',)
|
||||
list_editable = ('start', 'end', 'location',)
|
||||
list_editable = ('start', 'end', 'location')
|
||||
readonly_fields = ('event_series',)
|
||||
date_hierarchy = 'start'
|
||||
search_fields = ('name', 'description')
|
||||
@@ -32,12 +31,11 @@ class LocationAdmin(admin.ModelAdmin):
|
||||
|
||||
|
||||
class PhotoAdmin(admin.ModelAdmin):
|
||||
admin_thumbnail = AdminThumbnail(image_field='thumbnail')
|
||||
# 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',
|
||||
list_display = ('image', 'image', 'name', 'event',
|
||||
'photographer', 'on_startpage')
|
||||
list_display_links = ('image',)
|
||||
list_editable = ('on_startpage', 'name', 'event', 'photographer')
|
||||
|
||||
@@ -4,12 +4,30 @@ Created on 30.09.2011
|
||||
|
||||
@author: christian
|
||||
"""
|
||||
from . import models
|
||||
from django.core.cache import cache
|
||||
from .models import Event
|
||||
|
||||
|
||||
def upcoming_events(request):
|
||||
current_event = cache.get('current_event', False)
|
||||
next_event = cache.get('next_event', False)
|
||||
upcoming_events = cache.get('upcoming_events', False)
|
||||
|
||||
if current_event == False:
|
||||
current_event = Event.objects.current_event()
|
||||
cache.set('current_event', current_event, 360)
|
||||
if next_event == False:
|
||||
next_event = Event.objects.next_event()
|
||||
cache.set('next_event', next_event, 360)
|
||||
|
||||
if not upcoming_events and current_event:
|
||||
upcoming_events = Event.objects.upcoming(limit=3)
|
||||
cache.set('upcoming_events', upcoming_events, 360)
|
||||
elif not upcoming_events:
|
||||
upcoming_events = Event.objects.upcoming()[1:4]
|
||||
cache.set('upcoming_events', upcoming_events, 360)
|
||||
return {
|
||||
'current_event': models.Event.objects.current_event(),
|
||||
'next_event': models.Event.objects.next_event(),
|
||||
'upcoming_events': models.Event.objects.upcoming(),
|
||||
'current_event': current_event,
|
||||
'next_event': next_event,
|
||||
'upcoming_events': upcoming_events
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ class EditPhotoForm(forms.ModelForm):
|
||||
class Meta(object):
|
||||
model = models.Photo
|
||||
fields = ('event', 'name', 'description', 'photographer',
|
||||
'anchor_horizontal', 'anchor_vertical',
|
||||
'created_date', 'on_startpage')
|
||||
|
||||
|
||||
@@ -59,4 +58,5 @@ class EventForm(forms.ModelForm):
|
||||
model = models.Event
|
||||
exclude = ('event_count', 'event_series', )
|
||||
|
||||
EventSeriesFormset = forms.inlineformset_factory(models.Event, models.Event, fields=('start', 'end'), form=EventForm)
|
||||
EventSeriesFormset = forms.inlineformset_factory(
|
||||
models.Event, models.Event, fields=('start', 'end'), form=EventForm)
|
||||
|
||||
18
src/events/gallery_urls.py
Normal file
18
src/events/gallery_urls.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
from django.conf.urls import patterns, url
|
||||
|
||||
from .views import *
|
||||
|
||||
urlpatterns = patterns(
|
||||
'',
|
||||
url(r'^$', EventGallery.as_view(), name='event-gallery'),
|
||||
url(r'^(?P<event>[\d]+)/$', EventPhotoList.as_view(),
|
||||
name='event-photo-list'),
|
||||
url(r'^(?P<event>[\d]+)/upload/$', EventPhotoUpload.as_view(),
|
||||
name='event-photo-upload'),
|
||||
url(r'^(?P<event>[\d]+)/(?P<pk>[\d]+)/$', EventPhoto.as_view(),
|
||||
name='event-photo'),
|
||||
url(r'^delete/(?P<pk>[\d]+)/$', DeleteEventPhoto.as_view(),
|
||||
name='delete-event-photo'),
|
||||
url(r'^upload/$', EventPhotoUpload.as_view(), name='event-photo-upload'),
|
||||
)
|
||||
File diff suppressed because one or more lines are too long
@@ -18,11 +18,13 @@ class Migration(migrations.Migration):
|
||||
migrations.AddField(
|
||||
model_name='event',
|
||||
name='mahjong_season',
|
||||
field=models.PositiveSmallIntegerField(null=True, verbose_name='Mahjong Season', blank=True),
|
||||
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'),
|
||||
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'),
|
||||
),
|
||||
]
|
||||
|
||||
20
src/events/migrations/0003_auto_20150823_2232.py
Normal file
20
src/events/migrations/0003_auto_20150823_2232.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0002_auto_20150818_2139'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
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 Turnier'),
|
||||
),
|
||||
]
|
||||
91
src/events/migrations/0004_auto_20150901_2204.py
Normal file
91
src/events/migrations/0004_auto_20150901_2204.py
Normal file
@@ -0,0 +1,91 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import ckeditor.fields
|
||||
import events.models
|
||||
import easy_thumbnails.fields
|
||||
import django.db.models.deletion
|
||||
import utils
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('events', '0003_auto_20150823_2232'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Photo',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID',
|
||||
serialize=False, auto_created=True, primary_key=True)),
|
||||
('name', models.CharField(max_length=100,
|
||||
verbose_name='Name', blank=True)),
|
||||
('image', easy_thumbnails.fields.ThumbnailerImageField(
|
||||
upload_to=events.models.get_upload_path, storage=utils.OverwriteStorage(), verbose_name='Bild')),
|
||||
('description', models.TextField(max_length=300,
|
||||
verbose_name='Beschreibung', blank=True)),
|
||||
('on_startpage', models.BooleanField(default=False,
|
||||
help_text='Display this Photo on the Startpage Teaser', verbose_name='Startpage')),
|
||||
('created_date', models.DateTimeField(verbose_name='Published on')),
|
||||
('views', models.PositiveIntegerField(default=0,
|
||||
verbose_name='Number of views', editable=False)),
|
||||
],
|
||||
options={
|
||||
'ordering': ['created_date'],
|
||||
'db_table': 'events_photo',
|
||||
'verbose_name': 'Veranstaltungsbild',
|
||||
'verbose_name_plural': 'Event Images',
|
||||
'get_latest_by': 'created_date',
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='event',
|
||||
options={'ordering': (
|
||||
'start', 'end'), 'verbose_name': 'Termin', 'verbose_name_plural': 'Termine'},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='event',
|
||||
name='description',
|
||||
field=ckeditor.fields.RichTextField(
|
||||
verbose_name='Beschreibung', blank=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='event',
|
||||
name='event_series',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, blank=True, to='events.Event',
|
||||
help_text='Wenn dieser Termin zu einer Veranstaltungsreihe geh\xf6rt werden Ort, Beschreibung, Bild und Homepage von dem hier angegebenen Event \xfcbernommen.', null=True, verbose_name='Veranstaltungsreihen'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='event',
|
||||
name='image',
|
||||
field=easy_thumbnails.fields.ThumbnailerImageField(storage=utils.OverwriteStorage(
|
||||
), upload_to=events.models.get_upload_path, null=True, verbose_name='Bild', blank=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='description',
|
||||
field=ckeditor.fields.RichTextField(
|
||||
verbose_name='Beschreibung', blank=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='image',
|
||||
field=easy_thumbnails.fields.ThumbnailerImageField(storage=utils.OverwriteStorage(
|
||||
), upload_to=events.models.get_upload_path, null=True, verbose_name='Bild', blank=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='photo',
|
||||
name='event',
|
||||
field=models.ForeignKey(to='events.Event'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='photo',
|
||||
name='photographer',
|
||||
field=models.ForeignKey(to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
||||
20
src/events/migrations/0005_auto_20150907_2021.py
Normal file
20
src/events/migrations/0005_auto_20150907_2021.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0004_auto_20150901_2204'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='photo',
|
||||
name='on_startpage',
|
||||
field=models.BooleanField(
|
||||
default=False, help_text='Display this Photo on the Startpage Teaser', db_index=True, verbose_name='Startpage'),
|
||||
),
|
||||
]
|
||||
@@ -1,14 +1,17 @@
|
||||
# -'- Encoding: utf-8 -*-
|
||||
|
||||
import os
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
from django.db.models import Q
|
||||
from django.template.defaultfilters import slugify
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import ugettext as _
|
||||
from ckeditor.fields import RichTextField
|
||||
from easy_thumbnails.fields import ThumbnailerImageField
|
||||
|
||||
from utils import COUNTRIES, OverwriteStorage
|
||||
from gallery.models import Photo
|
||||
from kasu import image_models
|
||||
|
||||
|
||||
def get_upload_path(instance, filename):
|
||||
@@ -22,74 +25,98 @@ def get_upload_path(instance, filename):
|
||||
@param filename: The filename of the uploaded image.
|
||||
@type filename: String
|
||||
"""
|
||||
extension = filename[filename.rfind('.') + 1:]
|
||||
filename, extension = os.path.splitext(filename.lower())
|
||||
if isinstance(instance, Event):
|
||||
if instance.id:
|
||||
return "events/%s.%s" % (instance.id, extension)
|
||||
else:
|
||||
return "events/%s.%s" % (slugify(instance.name), extension)
|
||||
return "events/{date:%Y-%m-%d}/{name}{ext}".format(
|
||||
date=instance.start,
|
||||
name=slugify(instance.name),
|
||||
ext=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)
|
||||
return "events/locations/{name}{ext}".format(
|
||||
name=slugify(instance.name),
|
||||
ext=extension
|
||||
)
|
||||
elif isinstance(instance, Photo):
|
||||
return "events/%s/%s" % (instance.event.id, filename)
|
||||
return "events/{date:%Y-%m-%d}/{name}{ext}".format(
|
||||
date=instance.event.start,
|
||||
name=filename,
|
||||
ext=extension
|
||||
)
|
||||
|
||||
|
||||
class EventManager(models.Manager):
|
||||
|
||||
def get_queryset(self):
|
||||
return super(EventManager, self).get_queryset().select_related('location')
|
||||
|
||||
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:
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
def next_event(self):
|
||||
try:
|
||||
return self.filter(start__gt=now()).order_by('start', 'end')[0]
|
||||
except:
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
def archive(self):
|
||||
return self.filter(start__lt=now())
|
||||
|
||||
def upcoming(self, limit=3):
|
||||
def latest_events(self, num=3):
|
||||
return self.filter(start__lt=now()).order_by('-start', '-end')[:num]
|
||||
|
||||
def upcoming(self, limit=None):
|
||||
result = self.filter(start__gt=now()).order_by('start', 'end')
|
||||
if limit:
|
||||
return result[1:(limit + 1)]
|
||||
return result[0:limit]
|
||||
else:
|
||||
return result
|
||||
|
||||
|
||||
class Event(image_models.ImageModel):
|
||||
class Event(models.Model):
|
||||
name = models.CharField(_('Name'), max_length=255)
|
||||
description = models.TextField(_("Description"), blank=True)
|
||||
description = RichTextField(_("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)
|
||||
mahjong_tournament = models.BooleanField(_('Mahjong Tournament'), default=False,
|
||||
image = ThumbnailerImageField(
|
||||
_("Image"),
|
||||
upload_to=get_upload_path,
|
||||
storage=OverwriteStorage(),
|
||||
blank=True,
|
||||
null=True
|
||||
)
|
||||
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)
|
||||
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=True,
|
||||
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',)
|
||||
ordering = ('start', 'end',)
|
||||
|
||||
def __unicode__(self):
|
||||
try:
|
||||
@@ -122,23 +149,13 @@ class Event(image_models.ImageModel):
|
||||
}
|
||||
return reverse('event-form', kwargs=kwargs)
|
||||
|
||||
def get_callout(self):
|
||||
def get_image(self):
|
||||
if self.image:
|
||||
return self.callout
|
||||
elif self.photo_set.count():
|
||||
return self.photo_set.all().order_by('?')[0].callout
|
||||
return self.image
|
||||
elif self.photo_count:
|
||||
return self.photo_set.all().order_by('?')[0].image
|
||||
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
|
||||
return self.location.image
|
||||
else:
|
||||
return None
|
||||
|
||||
@@ -159,11 +176,16 @@ class Event(image_models.ImageModel):
|
||||
hanchan.save()
|
||||
|
||||
|
||||
class Location(image_models.ImageModel):
|
||||
class Location(models.Model):
|
||||
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)
|
||||
description = RichTextField(_("Description"), blank=True)
|
||||
image = ThumbnailerImageField(
|
||||
_("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)
|
||||
@@ -183,7 +205,111 @@ class Location(image_models.ImageModel):
|
||||
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)
|
||||
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(models.Model):
|
||||
name = models.CharField(_("Name"), max_length=100, blank=True)
|
||||
image = ThumbnailerImageField(_("Image"), upload_to=get_upload_path,
|
||||
storage=OverwriteStorage())
|
||||
event = models.ForeignKey('events.Event')
|
||||
description = models.TextField(
|
||||
_("Description"),
|
||||
max_length=300,
|
||||
blank=True
|
||||
)
|
||||
photographer = models.ForeignKey(settings.AUTH_USER_MODEL)
|
||||
on_startpage = models.BooleanField(
|
||||
_("Startpage"),
|
||||
default=False,
|
||||
db_index=True,
|
||||
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:
|
||||
get_latest_by = "created_date"
|
||||
ordering = ["created_date"]
|
||||
db_table = 'events_photo'
|
||||
verbose_name = _('Event Image')
|
||||
verbose_name_plural = _('Event Images')
|
||||
|
||||
def __unicode__(self):
|
||||
return os.path.basename(self.image.name)
|
||||
|
||||
def rotate(self, rotate):
|
||||
# TODO: Eine vernüftigte Methode ohne viele Abhängigkeiten finden um
|
||||
# die Bilder bei Bedarf zu drehen.
|
||||
if rotate == 'clockwise':
|
||||
pass
|
||||
elif rotate == 'counter-clockwise':
|
||||
pass
|
||||
self.save()
|
||||
|
||||
def save(self, **kwargs):
|
||||
super(Photo, self).save(**kwargs)
|
||||
self.event.save()
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse(
|
||||
'event-photo',
|
||||
kwargs={'event': self.event.id, 'pk': self.id}
|
||||
)
|
||||
|
||||
@property
|
||||
def next_photo(self):
|
||||
queryset = Photo.objects.filter(created_date__gt=self.created_date)
|
||||
queryset = queryset.order_by('created_date')
|
||||
try:
|
||||
if self.event.event_series:
|
||||
return queryset.filter(
|
||||
Q(event=self.event) |
|
||||
Q(event=self.event.event_series) |
|
||||
Q(event__event_series=self.event.event_series)
|
||||
)[0]
|
||||
else:
|
||||
return queryset.filter(
|
||||
Q(event=self.event) |
|
||||
Q(event__event_series=self.event)
|
||||
)[0]
|
||||
except IndexError:
|
||||
return None
|
||||
return self.get_next_by_created_date(event=self.event)
|
||||
|
||||
@property
|
||||
def previous_photo(self):
|
||||
queryset = Photo.objects.filter(created_date__lt=self.created_date)
|
||||
queryset = queryset.order_by('-created_date')
|
||||
try:
|
||||
if self.event.event_series:
|
||||
return queryset.filter(
|
||||
Q(event=self.event) |
|
||||
Q(event=self.event.event_series) |
|
||||
Q(event__event_series=self.event.event_series)
|
||||
)[0]
|
||||
else:
|
||||
return queryset.filter(
|
||||
Q(event=self.event) |
|
||||
Q(event__event_series=self.event)
|
||||
)[0]
|
||||
except IndexError:
|
||||
return None
|
||||
return self.get_previous_by_created_date(event=self.event)
|
||||
|
||||
11
src/events/static/js/mousetrap.js
Normal file
11
src/events/static/js/mousetrap.js
Normal file
@@ -0,0 +1,11 @@
|
||||
/* mousetrap v1.5.3 craig.is/killing/mice */
|
||||
(function(C,r,g){function t(a,b,h){a.addEventListener?a.addEventListener(b,h,!1):a.attachEvent("on"+b,h)}function x(a){if("keypress"==a.type){var b=String.fromCharCode(a.which);a.shiftKey||(b=b.toLowerCase());return b}return l[a.which]?l[a.which]:p[a.which]?p[a.which]:String.fromCharCode(a.which).toLowerCase()}function D(a){var b=[];a.shiftKey&&b.push("shift");a.altKey&&b.push("alt");a.ctrlKey&&b.push("ctrl");a.metaKey&&b.push("meta");return b}function u(a){return"shift"==a||"ctrl"==a||"alt"==a||
|
||||
"meta"==a}function y(a,b){var h,c,e,g=[];h=a;"+"===h?h=["+"]:(h=h.replace(/\+{2}/g,"+plus"),h=h.split("+"));for(e=0;e<h.length;++e)c=h[e],z[c]&&(c=z[c]),b&&"keypress"!=b&&A[c]&&(c=A[c],g.push("shift")),u(c)&&g.push(c);h=c;e=b;if(!e){if(!k){k={};for(var m in l)95<m&&112>m||l.hasOwnProperty(m)&&(k[l[m]]=m)}e=k[h]?"keydown":"keypress"}"keypress"==e&&g.length&&(e="keydown");return{key:c,modifiers:g,action:e}}function B(a,b){return null===a||a===r?!1:a===b?!0:B(a.parentNode,b)}function c(a){function b(a){a=
|
||||
a||{};var b=!1,n;for(n in q)a[n]?b=!0:q[n]=0;b||(v=!1)}function h(a,b,n,f,c,h){var g,e,l=[],m=n.type;if(!d._callbacks[a])return[];"keyup"==m&&u(a)&&(b=[a]);for(g=0;g<d._callbacks[a].length;++g)if(e=d._callbacks[a][g],(f||!e.seq||q[e.seq]==e.level)&&m==e.action){var k;(k="keypress"==m&&!n.metaKey&&!n.ctrlKey)||(k=e.modifiers,k=b.sort().join(",")===k.sort().join(","));k&&(k=f&&e.seq==f&&e.level==h,(!f&&e.combo==c||k)&&d._callbacks[a].splice(g,1),l.push(e))}return l}function g(a,b,n,f){d.stopCallback(b,
|
||||
b.target||b.srcElement,n,f)||!1!==a(b,n)||(b.preventDefault?b.preventDefault():b.returnValue=!1,b.stopPropagation?b.stopPropagation():b.cancelBubble=!0)}function e(a){"number"!==typeof a.which&&(a.which=a.keyCode);var b=x(a);b&&("keyup"==a.type&&w===b?w=!1:d.handleKey(b,D(a),a))}function l(a,c,n,f){function e(c){return function(){v=c;++q[a];clearTimeout(k);k=setTimeout(b,1E3)}}function h(c){g(n,c,a);"keyup"!==f&&(w=x(c));setTimeout(b,10)}for(var d=q[a]=0;d<c.length;++d){var p=d+1===c.length?h:e(f||
|
||||
y(c[d+1]).action);m(c[d],p,f,a,d)}}function m(a,b,c,f,e){d._directMap[a+":"+c]=b;a=a.replace(/\s+/g," ");var g=a.split(" ");1<g.length?l(a,g,b,c):(c=y(a,c),d._callbacks[c.key]=d._callbacks[c.key]||[],h(c.key,c.modifiers,{type:c.action},f,a,e),d._callbacks[c.key][f?"unshift":"push"]({callback:b,modifiers:c.modifiers,action:c.action,seq:f,level:e,combo:a}))}var d=this;a=a||r;if(!(d instanceof c))return new c(a);d.target=a;d._callbacks={};d._directMap={};var q={},k,w=!1,p=!1,v=!1;d._handleKey=function(a,
|
||||
c,e){var f=h(a,c,e),d;c={};var k=0,l=!1;for(d=0;d<f.length;++d)f[d].seq&&(k=Math.max(k,f[d].level));for(d=0;d<f.length;++d)f[d].seq?f[d].level==k&&(l=!0,c[f[d].seq]=1,g(f[d].callback,e,f[d].combo,f[d].seq)):l||g(f[d].callback,e,f[d].combo);f="keypress"==e.type&&p;e.type!=v||u(a)||f||b(c);p=l&&"keydown"==e.type};d._bindMultiple=function(a,b,c){for(var d=0;d<a.length;++d)m(a[d],b,c)};t(a,"keypress",e);t(a,"keydown",e);t(a,"keyup",e)}var l={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",18:"alt",
|
||||
20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},p={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},A={"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},z={option:"alt",command:"meta","return":"enter",
|
||||
escape:"esc",plus:"+",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},k;for(g=1;20>g;++g)l[111+g]="f"+g;for(g=0;9>=g;++g)l[g+96]=g;c.prototype.bind=function(a,b,c){a=a instanceof Array?a:[a];this._bindMultiple.call(this,a,b,c);return this};c.prototype.unbind=function(a,b){return this.bind.call(this,a,function(){},b)};c.prototype.trigger=function(a,b){if(this._directMap[a+":"+b])this._directMap[a+":"+b]({},a);return this};c.prototype.reset=function(){this._callbacks={};this._directMap=
|
||||
{};return this};c.prototype.stopCallback=function(a,b){return-1<(" "+b.className+" ").indexOf(" mousetrap ")||B(b,this.target)?!1:"INPUT"==b.tagName||"SELECT"==b.tagName||"TEXTAREA"==b.tagName||b.isContentEditable};c.prototype.handleKey=function(){return this._handleKey.apply(this,arguments)};c.init=function(){var a=c(r),b;for(b in a)"_"!==b.charAt(0)&&(c[b]=function(b){return function(){return a[b].apply(a,arguments)}}(b))};c.init();C.Mousetrap=c;"undefined"!==typeof module&&module.exports&&(module.exports=
|
||||
c);"function"===typeof define&&define.amd&&define(function(){return c})})(window,document);
|
||||
@@ -1,5 +1,5 @@
|
||||
{% extends "events/page.html" %}
|
||||
{% load i18n comments%}
|
||||
{% load i18n comments thumbnail %}
|
||||
|
||||
{% block title %}
|
||||
{% trans 'Event Archive' %} {% if month %}{{ month|date:'F Y' }} {% else %}{% if year %}{{year}}{% endif %}{% endif %}
|
||||
@@ -32,18 +32,23 @@
|
||||
<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><span class="fa fa-calendar-o" title="{% trans 'Start' %}"></span>
|
||||
{{ event.start|date }}
|
||||
<div class="grid_6">
|
||||
<a href="{{ event.get_absolute_url }}" class="thumbnail"><img src="{{ event.get_image|thumbnail_url:'thumbnail' }}"
|
||||
alt="{% trans 'Event Image' %}" width="140" height="140"/></a>
|
||||
|
||||
<h4><a href="{{ event.get_absolute_url }}">{{ event.name }}</a></h4>
|
||||
<p>
|
||||
<span class="fa fa-calendar-o" title="{% trans 'Date' %}" aria-label="{% trans 'Date' %}"></span>
|
||||
<time datetime="{{event.start|date:'c'}}">
|
||||
{{ event.start|date:'D' }}
|
||||
{{ event.start|date:'SHORT_DATE_FORMAT' }} {{hanchan.start|time:'H:i'}}
|
||||
</time>
|
||||
<span class="fa fa-clock-o" title="{% trans 'Time' %}" aria-label="{% trans 'Time' %}"></span>
|
||||
{% if event.end %}
|
||||
{% trans "from" %} {{ event.start|time:'H:i' }} {% trans "to" %} {{ event.end|time:'H:i' }}
|
||||
{% trans "from" %} {{ event.start|time:'H:i' }} {% trans "to" %} {{ event.end|time:'H:i' }}
|
||||
{% else %}
|
||||
{{ event.start|time:'H:i' }}
|
||||
{{ event.start|time:'H:i' }}
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
@@ -59,7 +64,6 @@
|
||||
<p class="right"><a href="{{ event.get_edit_url }}" class="button"><span class="fa fa-pencil"></span></a></p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if forloop.counter|divisibleby:2 %}<br class="clear"/>{% endif %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{% extends "events/page.html" %}
|
||||
{% load i18n django_markdown comments %}
|
||||
{% load i18n comments thumbnail %}
|
||||
|
||||
{% block title %}{{ event.name }}{% endblock %}
|
||||
|
||||
@@ -8,19 +8,19 @@
|
||||
<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 %}
|
||||
{% if event.description %}<meta property="og:description" content="{{event.description|striptags}}" />{% 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 jumbotron_background %} {{ event.get_image|thumbnail_url:'callout' }} {% endblock %}
|
||||
|
||||
{% block teaser %}
|
||||
<h1>{{event.name}}</h1>
|
||||
{% if event.description %}
|
||||
<div id="teaser_text">{{event.description|markdown|truncatewords_html:75}}</div>
|
||||
<div id="teaser_text">{{event.description|truncatewords_html:75|safe}}</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -48,10 +48,8 @@
|
||||
<li><a href="{% url 'event-photo-list' event.pk %}"><span class="fa fa-camera-retro"></span> {{ event.photo_count }} {% trans 'Photos' %}</a></li>
|
||||
<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.mahjong_tournament %}
|
||||
<li><a href="{% url 'event-ranking' event.id %}"><span class="fa fa-trophy"></span> {% trans "Tournament Ranking" %}</a></li>
|
||||
{% endif %}
|
||||
<li><a href="{% url 'event-ranking' event.id %}"><span
|
||||
class="fa fa-trophy"></span> {% trans "Event Ranking" %}</a></li>
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
||||
@@ -81,16 +79,30 @@
|
||||
|
||||
<div class="grid_12">
|
||||
{% if event.description %}
|
||||
{{event.description|markdown}}
|
||||
{{event.description|safe}}
|
||||
{% else %}
|
||||
{{event.location.description|markdown}}
|
||||
{{event.location.description|safe}}
|
||||
{% 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}}&z=16" target="gmaps"><img src="{{ STATIC_URL }}img/google_maps.png" alt="Google Maps" title="{% trans 'Show on Google Maps' %}" width="39" height="39"/></a>
|
||||
|
||||
<a class="button" href="http://facebook.com/sharer.php?u=http%3A%2F%2Fwww.kasu.at{{event.get_absolute_url|urlencode}}" target="_blank">
|
||||
<span class="fa fa-facebook"></span>
|
||||
{% trans 'Share on Facebook'%}
|
||||
</a>
|
||||
|
||||
<a class="button" 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;">
|
||||
<span class="fa fa-google-plus"></span>
|
||||
{% trans 'Share on Google+'%}
|
||||
</a>
|
||||
<a class="button" href="https://twitter.com/share?url=http%3A%2F%2Fwww.kasu.at{{event.get_absolute_url|urlencode}}" target='_blank'>
|
||||
<span class="fa fa-twitter"></span>
|
||||
{% trans 'Share on Twitter' %}
|
||||
</a>
|
||||
<a class="button" href="http://maps.google.com/maps?q={{event.location.address|urlencode}}&z=16" target="gmaps">
|
||||
<span class="fa fa-map"></span>
|
||||
{% trans 'Show on Google Maps' %}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<br class="clear" />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{% extends "events/page.html" %}
|
||||
{% load i18n comments%}
|
||||
{% load i18n comments thumbnail %}
|
||||
|
||||
{% block title %}{% trans "Upcoming Events" %}{% endblock %}
|
||||
{% block teaser%}<h2>{% trans "Upcoming Events" %}</h2>{% endblock %}
|
||||
@@ -10,22 +10,33 @@
|
||||
<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">
|
||||
<div class="grid_6">
|
||||
{% if perms.events.change_event %}
|
||||
<a href="{{ event.get_edit_url }}" class="button" style="float:right"><span class="fa fa-pencil"></span></a>
|
||||
{% endif %}
|
||||
{% if perms.events.add_photo %}
|
||||
<a href="{% url 'event-photo-list' event.pk %}" class="button" style="float:right"><span class="fa fa-camera-retro"></span></a>
|
||||
<a href="{{ event.get_edit_url }}" class="button" style="float:right"><span class="fa fa-pencil"></span></a>
|
||||
{% endif %}
|
||||
<a href="{{ event.get_absolute_url }}" class="thumbnail"><img
|
||||
src="{{ event.get_image|thumbnail_url:'thumbnail' }}" alt="{% trans 'Event Image' %}" width="140" height="140"/>
|
||||
</a>
|
||||
<h4><a href="{{ event.get_absolute_url }}">{{ event.name }}</a></h4>
|
||||
<ul class="info">
|
||||
<li><span class="fa fa-calendar-o" title="{% trans 'Date' %}"></span> <time datetime="{{event.start|date:'c'}}">{{ event.start|date:'SHORT_DATE_FORMAT' }}</time></li>
|
||||
<li><span class="fa fa-map-marker" title="{% trans 'Location' %}"></span> {{ event.location }}</li>
|
||||
<li><span class="fa fa-comments" title="{% trans 'Comments' %}"></span> <a href="{{event.get_absolute_url}}#comments">{{ comment_count }}</a></li>
|
||||
<li><span class="fa fa-calendar-o" title="{% trans 'Date' %}" aria-label="{% trans 'Date' %}"></span>
|
||||
<time datetime="{{event.start|date:'c'}}">
|
||||
{{ event.start|date:'D' }}
|
||||
{{ event.start|date:'SHORT_DATE_FORMAT' }}
|
||||
</time>
|
||||
</li>
|
||||
<li><span class="fa fa-clock-o" title="{% trans 'Start' %}" aria-label="{% trans 'Start' %}"></span>
|
||||
{{ event.start|time:'H:i' }}
|
||||
</li>
|
||||
|
||||
<li><span class="fa fa-map-marker" title="{% trans 'Location' %}" aria-label="{% trans 'Location' %}"></span>
|
||||
{{ event.location }}
|
||||
</li>
|
||||
<li><span class="fa fa-comments" title="{% trans 'Comments' %}" aria-label="{% trans 'Comments' %}"></span>
|
||||
<a href="{{event.get_absolute_url}}#comments">{{ comment_count }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
<p>{{event.description|truncatewords_html:20}}</p>
|
||||
<p>{{event.description|truncatewords_html:25|safe}}</p>
|
||||
</div>
|
||||
{% if forloop.counter|divisibleby:2 %}<br class="clear">{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{% extends "base.html" %}
|
||||
{% load i18n django_markdown%}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{{ event.name }}{% endblock %}
|
||||
|
||||
@@ -11,12 +11,12 @@
|
||||
{% if event.description %}<meta property="og:description" content="{{event.description}}" />{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block jumbotron_background %}{{ event.get_callout.url }}')}{% endblock %}
|
||||
{% block jumbotron_background %} {{ event.get_image|thumbnail_url:'callout' }} {% endblock %}
|
||||
|
||||
{% block teaser %}
|
||||
<h1>{{event.name}}</h1>
|
||||
<div id="teaser_text">
|
||||
{% if event.description %}{{event.description|markdown}}{% else %}{{event.location.description|markdown}}{% endif %}
|
||||
{% if event.description %}{{event.description}}{% else %}{{event.location.description}}{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
{% extends "events/event_detail.html" %}
|
||||
{% load i18n django_markdown comments %}
|
||||
{% load i18n comments %}
|
||||
|
||||
{% block title %}{{ event.name }}{% endblock %}
|
||||
|
||||
{% block teaser %}
|
||||
<h1>{{event.name}}</h1>
|
||||
{% if event.description %}
|
||||
<div id="teaser_text">{{event.description|markdown|truncatewords_html:75}}</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block event_content %}
|
||||
<h3>Hier kommt eine Tabelle rein!</h3>
|
||||
<form class="grid_12" method="post">
|
||||
|
||||
28
src/events/templates/events/photo_confirm_delete.html
Normal file
28
src/events/templates/events/photo_confirm_delete.html
Normal file
@@ -0,0 +1,28 @@
|
||||
{% extends "events/event_detail.html" %}
|
||||
{% load i18n comments thumbnail %}
|
||||
|
||||
{% block maincontent %}
|
||||
<form action="" method="post" class="grid_12">
|
||||
{% csrf_token %}
|
||||
<header>
|
||||
<h1 class="grid_12">Dieses Photo wirklich löschen?</h1>
|
||||
</header>
|
||||
<p>Sind Sie sicher, dass Sie das Bild “{{photo.name}}” löschen wollen?</p>
|
||||
<img src="{{photo.image|thumbnail_url:'display'}}" alt="{{photo.name}}" title="{{photo.name}}" class="grid_10 push_1"/>
|
||||
<br class="clear"/>
|
||||
<p> </p>
|
||||
<p class="buttonbar">
|
||||
<a class="button" href="{% url 'event-photo-list' photo.event.id %}" style="float: left;">
|
||||
<span class="fa fa-ban"></span>
|
||||
{% trans 'Cancel' %}
|
||||
</a>
|
||||
<button type="submit">
|
||||
<span class="fa fa-trash"></span>
|
||||
{% trans 'Delete' %}
|
||||
</button>
|
||||
</p>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% block buttonbar %}{% endblock %}
|
||||
|
||||
|
||||
85
src/events/templates/events/photo_detail.html
Normal file
85
src/events/templates/events/photo_detail.html
Normal file
@@ -0,0 +1,85 @@
|
||||
{% extends "events/event_detail.html" %}
|
||||
{% load i18n comments thumbnail %}
|
||||
|
||||
{% block title %} {{ photo.name }} - {{ photo.event.name }} {% endblock %}
|
||||
|
||||
{% block extra_head %}
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}/js/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}/js/mousetrap.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascript %}
|
||||
if ($('a.previous').attr('href')) {
|
||||
Mousetrap.bind('left', function() { window.location = $('a.previous').attr('href'); });
|
||||
}
|
||||
if ($('a.next').attr('href')) {
|
||||
Mousetrap.bind('right', function() { window.location = $('a.next').attr('href'); });
|
||||
}
|
||||
{% endblock %}
|
||||
|
||||
{% block teaser %}
|
||||
<h1 class="grid_12">{{event.name}} - {{ photo.name }}</h1>
|
||||
{% if event.description %}
|
||||
<div id="teaser_text">{{event.description|truncatewords_html:75}}</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block opengraph %}
|
||||
<meta property="og:type" content="photo" />
|
||||
<meta property="og:title" content="{{photo.name}} - Foto" />
|
||||
<meta property="og:url" content="http://www.kasu.at{{photo.get_absolute_url}}" />
|
||||
<meta property="og:image" content="http://www.kasu.at{{photo.thumbnail.url}}" />
|
||||
{% if photo.description %}<meta property="og:description" content="{{photo.description}}" />{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block maincontent %}
|
||||
<div id="display" class="grid_12">
|
||||
<img src="{{photo.image|thumbnail_url:'display'}}" alt="{{photo.name}}" title="{{photo.name}}"/>
|
||||
{% if photo.previous_photo %}
|
||||
<a href="{% url 'event-photo' photo.previous_photo.event.id photo.previous_photo.id %}#display" class="previous" id="previous">{% trans 'previous' %}</a>
|
||||
{% endif %}
|
||||
{% if photo.next_photo %}
|
||||
<a href="{% url 'event-photo' photo.next_photo.event.id photo.next_photo.id %}#display" class="next" id="next">Next</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="grid_12">
|
||||
<ul class="info">
|
||||
<li><span class="fa fa-user"></span> <strong>{% trans 'Photographer' %}: </strong>{{ photo.photographer }}</li>
|
||||
<li><span class="fa fa-calendar-o"></span> <strong>{% trans 'Date' %}</strong> {{ photo.created_date }}</li>
|
||||
</ul>
|
||||
<p>{{ photo.description }}</p>
|
||||
</div>
|
||||
<p class="right">
|
||||
<strong>{% trans 'share on' %}:</strong>
|
||||
<a class="button" href="http://facebook.com/sharer.php?u=http%3A%2F%2Fwww.kasu.at{{photo.get_absolute_url|urlencode}}" target="_blank" rel="nofollow">
|
||||
<span class="fa fa-twitter"></span>Facebook
|
||||
</a>
|
||||
<a class="button" href="https://m.google.com/app/plus/x/?v=compose&content={{photo.headline|urlencode}}+-+http%3A%2F%2Fwww.kasu.at/{{photo.get_absolute_url|urlencode}}" target="_blank" rel="nofollow">
|
||||
<span class="fa fa-google-plus"></span> Google+
|
||||
</a>
|
||||
<a class="button" href="https://twitter.com/share?url=http%3A%2F%2Fwww.kasu.at/{{photo.get_absolute_url|urlencode}}" target='_blank' rel="nofollow">
|
||||
<span class="fa fa-twitter"></span> Twitter
|
||||
</a>
|
||||
</p>
|
||||
{% endblock %}
|
||||
|
||||
{% block comment %}
|
||||
{% render_comment_list for photo %}
|
||||
{% render_comment_form for photo %}
|
||||
{% endblock %}
|
||||
|
||||
{% block buttonbar %}
|
||||
{% if perms.events.change_photo %}
|
||||
<form method="post" enctype="multipart/form-data" class="grid_12">
|
||||
{% csrf_token %}
|
||||
<p class="buttonbar">
|
||||
<a href="{{ photo.image.url }}" class="button" type="application/octet-stream"><span class="fa fa-download"></span> {% trans 'download' %}</a>
|
||||
<button type="submit" name="rotate" value="counter-clockwise"><span class="fa fa-undo"></span> {% trans 'Rotate counter clockwise' %}</button>
|
||||
<button type="submit" name="rotate" value="clockwise"><span class="fa fa-repeat"></span> {% trans 'Rotate clockwise' %}</button>
|
||||
<button type="submit"><span class="fa fa-check"></span> {% trans 'Save' %}</button>
|
||||
</p>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
17
src/events/templates/events/photo_gallery.html
Normal file
17
src/events/templates/events/photo_gallery.html
Normal file
@@ -0,0 +1,17 @@
|
||||
{% extends "base.html" %}
|
||||
{% load i18n thumbnail %}
|
||||
|
||||
{% block maincontent %}
|
||||
{% 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_image|thumbnail_url:'thumbnail' }}" class="thumbnail" alt="{{ event.name }}"/></a>
|
||||
</div>
|
||||
{% empty %}
|
||||
<p>Sorry da kommt erst was hin!</p>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
{% block buttonbar %}{% endblock %}
|
||||
|
||||
|
||||
45
src/events/templates/events/photo_list.html
Normal file
45
src/events/templates/events/photo_list.html
Normal file
@@ -0,0 +1,45 @@
|
||||
{% extends "events/event_detail.html" %}
|
||||
{% load i18n thumbnail %}
|
||||
|
||||
{% block title %}{{event.name}}{% endblock %}
|
||||
|
||||
{% block opengraph %}
|
||||
<meta property="og:type" content="album" />
|
||||
<meta property="og:title" content="{{event.name}}" />
|
||||
<meta property="og:url" content="http://www.kasu.at{% url 'event-photo-list' event.pk %}" />
|
||||
<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 maincontent %}
|
||||
|
||||
{% for photo in photo_list %}
|
||||
<div class="thumbnail">
|
||||
<a href="{% url 'event-photo' event.id photo.id %}"><img src="{{photo.image|thumbnail_url:'thumbnail'}}" alt=""/></a>
|
||||
{% if perms.events.delete_photo %}
|
||||
<a href="{% url 'delete-event-photo' photo.pk %}" class="button delete_image">
|
||||
<span class="fa fa-trash" aria-label="{% trans 'Delete' %}" title="{% trans 'Delete' %}"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% if perms.events.add_photo %}
|
||||
<form action="{% url 'event-photo-upload' event.id %}" method="post" enctype="multipart/form-data" class="grid_12">
|
||||
{% csrf_token %}
|
||||
<fieldset>
|
||||
<legend>Photos hochladen</legend>
|
||||
{% include "form.html"%}
|
||||
<p class="buttonbar">
|
||||
<button type="reset"><span class="fa fa-undo"></span> {% trans 'reset' %}</button>
|
||||
<button type="submit"><span class="fa fa-cloud-upload"></span> {% trans 'Upload' %}</button>
|
||||
</p>
|
||||
</fieldset>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block buttonbar %}{% endblock %}
|
||||
|
||||
|
||||
56
src/events/templates/events/photo_upload.html
Normal file
56
src/events/templates/events/photo_upload.html
Normal file
@@ -0,0 +1,56 @@
|
||||
{% extends "base.html" %}
|
||||
{% load i18n comments thumbnail %}
|
||||
|
||||
{% block maincontent %}
|
||||
{% for event in event_list %}
|
||||
{% get_comment_count for event as comment_count %}
|
||||
{% ifchanged %}<h3 class="grid_12">{{ event.start|date:'F Y' }}</h3>{% endifchanged %}
|
||||
<div style="float:left">
|
||||
<a href="{% url 'event-photo-list' event.pk %}"><img src="{{ event.get_image|thumbnail_url:'thumbnail' }}" alt="" class="thumbnail"/></a>
|
||||
<div class="grid_4" />
|
||||
<h4><a href="{% url 'event-photo-list' event.pk %}">{{ event.name }}</a></h4>
|
||||
<div class="info">
|
||||
<span class="fa fa-calendar-o" title="{% trans 'Start' %}"></span>
|
||||
{{ 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 %}
|
||||
</div>
|
||||
{% if event.description %}<p>{{event.description}}</p>{% endif %}
|
||||
<div class="info">
|
||||
<span class="fa fa-map-marker" title="{% trans 'Location' %}"></span>
|
||||
{{ event.location }}
|
||||
<span class="fa fa-comments" title="{% trans 'Comments' %}"></span>
|
||||
<a href="{{event.get_absolute_url}}#comments">{{ comment_count }} {% trans 'Comments' %}</a>
|
||||
|
||||
<span class="fa fa-camera-retro" title="{% trans 'Photos' %}"></span>
|
||||
<a href="{% url 'event-photo-list' event.pk %}">{{ event.photo_count }} {% trans 'Photos' %}</a>
|
||||
</div>
|
||||
<p style="text-align:right">
|
||||
{% if perms.events.add_photo %}
|
||||
<a href="{% url 'event-photo-list' event.pk %}" class="button">
|
||||
<span class="fa fa-cloud-upload"></span>
|
||||
{%trans "Upload" %}</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div></div>
|
||||
{% endfor %}
|
||||
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<fieldset class="grid_8 push_2">
|
||||
<legend>Photos hochladen</legend>
|
||||
{% include "form.html" %}
|
||||
<p class="buttonbar">
|
||||
<button type="submit">
|
||||
<span class="fa fa-cloud-upload"></span>
|
||||
{% trans "Upload" %}
|
||||
</button>
|
||||
</p>
|
||||
</fieldset>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ from django.test import TestCase
|
||||
|
||||
|
||||
class SimpleTest(TestCase):
|
||||
|
||||
def test_basic_addition(self):
|
||||
"""
|
||||
Tests that 1 + 1 always equals 2.
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
from django.conf.urls import patterns, url
|
||||
|
||||
from django.views.generic import RedirectView
|
||||
from .views import *
|
||||
|
||||
urlpatterns = patterns(
|
||||
'',
|
||||
url(r'^$', UpcomingEvents.as_view(), name='upcoming-events'),
|
||||
url(r'^$', RedirectView.as_view(url='/events/upcoming/', permanent=True)),
|
||||
url(r'^(?P<year>[\d]{4})/$', EventArchiveYear.as_view(),
|
||||
name='event-archive'),
|
||||
url(r'^(?P<year>[\d]{4})/(?P<month>[\d]+)/$', EventArchiveMonth.as_view(),
|
||||
@@ -18,4 +18,5 @@ urlpatterns = patterns(
|
||||
EventForm.as_view(), name='event-form'),
|
||||
url(r'^add/$', EventForm.as_view(), name='event-form'),
|
||||
url(r'^archive/$', EventArchiveIndex.as_view(), name='event-archive'),
|
||||
url(r'^upcoming/$', UpcomingEvents.as_view(), name='upcoming-events'),
|
||||
)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# Create your views here.
|
||||
from datetime import timedelta
|
||||
|
||||
from django.db.models import Q
|
||||
from django.contrib.auth.decorators import permission_required
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.urlresolvers import reverse
|
||||
@@ -13,22 +14,23 @@ 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])
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(DeleteEventPhoto, self).get_context_data()
|
||||
context['event'] = self.object.event
|
||||
return context
|
||||
|
||||
@method_decorator(permission_required('events.delete_photo'))
|
||||
def dispatch(self, *args, **kwargs):
|
||||
return super(DeleteEventPhoto, self).dispatch(*args, **kwargs)
|
||||
@@ -39,10 +41,9 @@ class EventArchiveIndex(generic.ArchiveIndexView):
|
||||
context_object_name = 'event_list'
|
||||
date_field = 'start'
|
||||
model = models.Event
|
||||
queryset = model.objects.all()
|
||||
ordering = ('-start', '-end')
|
||||
paginate_by = 15
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = generic.ArchiveIndexView.get_context_data(self, **kwargs)
|
||||
context['is_archive'] = True
|
||||
@@ -53,6 +54,7 @@ class EventArchiveMonth(generic.MonthArchiveView):
|
||||
date_field = 'start'
|
||||
make_object_list = True
|
||||
model = models.Event
|
||||
ordering = ('start', 'end')
|
||||
month_format = '%m'
|
||||
paginate_by = 15
|
||||
template_name = 'events/event_archive.html'
|
||||
@@ -64,9 +66,10 @@ class EventArchiveMonth(generic.MonthArchiveView):
|
||||
|
||||
|
||||
class EventArchiveYear(generic.YearArchiveView):
|
||||
model = models.Event
|
||||
date_field = 'start'
|
||||
make_object_list = True
|
||||
model = models.Event
|
||||
ordering = ('start', 'end')
|
||||
paginate_by = 15
|
||||
template_name = 'events/event_archive.html'
|
||||
year_format = '%Y'
|
||||
@@ -117,27 +120,13 @@ class EventForm(PermissionRequiredMixin, generic.UpdateView):
|
||||
return models.Event()
|
||||
|
||||
|
||||
class EventSeriesForm(EventDetailMixin, PermissionRequiredMixin, InlineFormSetView):
|
||||
model = models.Event
|
||||
inline_model = models.Event
|
||||
fk_name = 'event_series'
|
||||
fields = ('start', 'end')
|
||||
form_class = forms.EventForm
|
||||
extra = 3
|
||||
permission_required = 'events.add_event'
|
||||
template_name = 'events/eventseries_form.html'
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
self.event = models.Event.objects.get(pk=self.kwargs['pk'])
|
||||
if self.event.event_series:
|
||||
self.event = self.event.event_series
|
||||
return self.event
|
||||
|
||||
|
||||
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(),
|
||||
event_series__isnull=True,
|
||||
photo_count__gt=0
|
||||
)
|
||||
paginate_by = 12
|
||||
|
||||
|
||||
@@ -180,7 +169,10 @@ class EventPhoto(generic.UpdateView):
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(EventPhoto, self).get_context_data()
|
||||
event = models.Event.objects.get(id=self.kwargs['event'])
|
||||
try:
|
||||
event = models.Event.objects.get(id=self.kwargs['event'])
|
||||
except models.Event.DoesNotExist:
|
||||
event = self.object.event
|
||||
context['event'] = event
|
||||
return context
|
||||
|
||||
@@ -209,7 +201,10 @@ class EventPhotoList(generic.ListView):
|
||||
def get_queryset(self):
|
||||
try:
|
||||
self.event = models.Event.objects.get(id=self.kwargs['event'])
|
||||
return models.Photo.objects.filter(event=self.event)
|
||||
return models.Photo.objects.filter(
|
||||
Q(event=self.event) |
|
||||
Q(event__event_series=self.event)
|
||||
)
|
||||
except models.Event.DoesNotExist:
|
||||
raise Http404(_('Event does not exist'))
|
||||
|
||||
@@ -261,20 +256,28 @@ class EventPhotoUpload(generic.FormView):
|
||||
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 = ''
|
||||
created_date = self.event.start + timedelta(minutes=self.counter)
|
||||
description = ''
|
||||
return created_date, description
|
||||
|
||||
|
||||
class EventSeriesForm(EventDetailMixin, PermissionRequiredMixin, InlineFormSetView):
|
||||
model = models.Event
|
||||
inline_model = models.Event
|
||||
fk_name = 'event_series'
|
||||
fields = ('start', 'end')
|
||||
form_class = forms.EventForm
|
||||
extra = 3
|
||||
permission_required = 'events.add_event'
|
||||
template_name = 'events/eventseries_form.html'
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
self.event = models.Event.objects.get(pk=self.kwargs['pk'])
|
||||
if self.event.event_series:
|
||||
self.event = self.event.event_series
|
||||
return self.event
|
||||
|
||||
|
||||
class UpcomingEvents(generic.ListView):
|
||||
queryset = models.Event.objects.upcoming(limit=None)
|
||||
paginate_by = 16
|
||||
|
||||
Reference in New Issue
Block a user