Eine Menge Aufräumarbeiten.
* Eine Testsuite um Mahrjong Ranking Berechnungen zu testen * Erste Arbeiten um die Workarounds aus dem "utils" Paket los zu werden. * Vieles am Code umformatiert für PEP8 conformität
This commit is contained in:
@@ -8,7 +8,6 @@ django-csp
|
|||||||
django-extra-views
|
django-extra-views
|
||||||
django-markdown
|
django-markdown
|
||||||
easy-thumbnails
|
easy-thumbnails
|
||||||
flup-py3
|
|
||||||
icalendar
|
icalendar
|
||||||
markdown
|
markdown
|
||||||
pillow
|
pillow
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
"""
|
|
||||||
Created on 19.09.2011
|
|
||||||
|
|
||||||
@author: christian
|
|
||||||
"""
|
|
||||||
# import stuff we need from django
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
class PageTabularInline(admin.TabularInline):
|
class PageTabularInline(admin.TabularInline):
|
||||||
|
""" Displays the sub-pages of an page element. """
|
||||||
fields = ('title_de', 'menu_name_de', "position",)
|
fields = ('title_de', 'menu_name_de', "position",)
|
||||||
model = models.Page
|
model = models.Page
|
||||||
sortable_field_name = "position"
|
sortable_field_name = "position"
|
||||||
|
|
||||||
|
|
||||||
class ArticleAdmin(admin.ModelAdmin):
|
class ArticleAdmin(admin.ModelAdmin):
|
||||||
|
""" Admin interface for the news-articles. """
|
||||||
prepopulated_fields = {"slug": ("headline_de",)}
|
prepopulated_fields = {"slug": ("headline_de",)}
|
||||||
list_display = ('headline', 'category', 'date_created', 'author',)
|
list_display = ('headline', 'category', 'date_created', 'author',)
|
||||||
list_editable = ('category', 'author')
|
list_editable = ('category', 'author')
|
||||||
|
|
||||||
|
|
||||||
class CategoryAdmin(admin.ModelAdmin):
|
class CategoryAdmin(admin.ModelAdmin):
|
||||||
|
""" Admin interface for categories of the news-aricles. """
|
||||||
list_display = ['name', 'slug', 'description']
|
list_display = ['name', 'slug', 'description']
|
||||||
list_display_links = ('name', 'slug',)
|
list_display_links = ('name', 'slug',)
|
||||||
prepopulated_fields = {'slug': ('name_de',)}
|
prepopulated_fields = {'slug': ('name_de',)}
|
||||||
|
|
||||||
|
|
||||||
class PageAdmin(admin.ModelAdmin):
|
class PageAdmin(admin.ModelAdmin):
|
||||||
|
"""
|
||||||
|
Admin interface for static pages that can contain HTML or PDF Content.
|
||||||
|
"""
|
||||||
prepopulated_fields = {"slug": ('menu_name_de',)}
|
prepopulated_fields = {"slug": ('menu_name_de',)}
|
||||||
inlines = [PageTabularInline, ]
|
inlines = [PageTabularInline, ]
|
||||||
list_display = ('position', 'menu_name', 'title', 'parent', 'path',)
|
list_display = ('position', 'menu_name', 'title', 'parent', 'path',)
|
||||||
@@ -54,6 +54,7 @@ class PageAdmin(admin.ModelAdmin):
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(models.Article, ArticleAdmin)
|
admin.site.register(models.Article, ArticleAdmin)
|
||||||
admin.site.register(models.Page, PageAdmin)
|
admin.site.register(models.Page, PageAdmin)
|
||||||
admin.site.register(models.Category, CategoryAdmin)
|
admin.site.register(models.Category, CategoryAdmin)
|
||||||
|
|||||||
@@ -3,11 +3,10 @@ Created on 04.10.2011
|
|||||||
|
|
||||||
@author: christian
|
@author: christian
|
||||||
"""
|
"""
|
||||||
import django.forms
|
from django import forms
|
||||||
from django.template.defaultfilters import slugify
|
from django.template.defaultfilters import slugify
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from utils.html5 import forms
|
|
||||||
from . import models
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
@@ -35,9 +34,9 @@ class ArticleForm(forms.ModelForm):
|
|||||||
class PageForm(forms.ModelForm):
|
class PageForm(forms.ModelForm):
|
||||||
error_css_class = 'error'
|
error_css_class = 'error'
|
||||||
required_css_class = 'required'
|
required_css_class = 'required'
|
||||||
content_type = django.forms.ChoiceField(
|
content_type = forms.ChoiceField(
|
||||||
choices=models.CONTENT_CHOICES,
|
choices=models.CONTENT_CHOICES,
|
||||||
widget=django.forms.RadioSelect
|
widget=forms.RadioSelect
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta(object):
|
class Meta(object):
|
||||||
@@ -47,7 +46,7 @@ class PageForm(forms.ModelForm):
|
|||||||
def clean(self):
|
def clean(self):
|
||||||
cleaned_data = super(PageForm, self).clean()
|
cleaned_data = super(PageForm, self).clean()
|
||||||
content_type = cleaned_data.get("content_type")
|
content_type = cleaned_data.get("content_type")
|
||||||
pdf_de = cleaned_data.get("pdf_de")
|
cleaned_data.get("pdf_de")
|
||||||
if content_type == "2" and not cleaned_data.get("pdf_de"):
|
if content_type == "2" and not cleaned_data.get("pdf_de"):
|
||||||
msg = _('Please upload a PDF-File to this PDF-Page.')
|
msg = _('Please upload a PDF-File to this PDF-Page.')
|
||||||
self._errors["content_type"] = self.error_class([msg])
|
self._errors["content_type"] = self.error_class([msg])
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: kasu.content\n"
|
"Project-Id-Version: kasu.content\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2016-09-28 00:25+0200\n"
|
"POT-Creation-Date: 2017-05-10 23:16+0200\n"
|
||||||
"PO-Revision-Date: 2016-09-28 00:24+0200\n"
|
"PO-Revision-Date: 2016-09-28 00:24+0200\n"
|
||||||
"Last-Translator: Christian Berg <xeniac@posteo.at>\n"
|
"Last-Translator: Christian Berg <xeniac@posteo.at>\n"
|
||||||
"Language-Team: Deutsch <>\n"
|
"Language-Team: Deutsch <>\n"
|
||||||
@@ -20,235 +20,265 @@ msgstr ""
|
|||||||
"X-Translated-Using: django-rosetta 0.7.2\n"
|
"X-Translated-Using: django-rosetta 0.7.2\n"
|
||||||
"X-Generator: Poedit 1.8.9\n"
|
"X-Generator: Poedit 1.8.9\n"
|
||||||
|
|
||||||
#: src/content/feeds.py:14
|
#: content/feeds.py:14
|
||||||
msgid "Current news from Kasu"
|
msgid "Current news from Kasu"
|
||||||
msgstr "Aktuelle Nachrichten von Kasu"
|
msgstr "Aktuelle Nachrichten von Kasu"
|
||||||
|
|
||||||
#: src/content/feeds.py:42
|
#: content/feeds.py:42
|
||||||
msgid "Latest comments on kasu.at"
|
msgid "Latest comments on kasu.at"
|
||||||
msgstr "Neueste Kommentare auf Kasu.at "
|
msgstr "Neueste Kommentare auf Kasu.at "
|
||||||
|
|
||||||
#: src/content/feeds.py:43
|
#: content/feeds.py:43
|
||||||
msgid "Kasu - latest comments"
|
msgid "Kasu - latest comments"
|
||||||
msgstr "Kasu - neue Kommentare"
|
msgstr "Kasu - neue Kommentare"
|
||||||
|
|
||||||
#: src/content/forms.py:52 src/content/models.py:204
|
#: content/forms.py:52 content/models.py:249
|
||||||
msgid "Please upload a PDF-File to this PDF-Page."
|
msgid "Please upload a PDF-File to this PDF-Page."
|
||||||
msgstr "Bitte eine PDF Datei für diese PDF Seite hochladen."
|
msgstr "Bitte eine PDF Datei für diese PDF Seite hochladen."
|
||||||
|
|
||||||
#: src/content/models.py:51
|
#: content/models.py:51
|
||||||
msgid "Headline"
|
msgid "Headline"
|
||||||
msgstr "Schlagzeile"
|
msgstr "Schlagzeile"
|
||||||
|
|
||||||
#: src/content/models.py:53
|
#: content/models.py:53
|
||||||
msgid "Content"
|
msgid "Content"
|
||||||
msgstr "Inhalt"
|
msgstr "Inhalt"
|
||||||
|
|
||||||
#: src/content/models.py:55 src/content/models.py:234
|
#: content/models.py:55 content/models.py:279
|
||||||
#: src/content/templates/content/article_detail.html:25
|
#: content/templates/content/article_detail.html:25
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Kategorie"
|
msgstr "Kategorie"
|
||||||
|
|
||||||
#: src/content/models.py:56 src/content/models.py:228
|
#: content/models.py:56 content/models.py:273
|
||||||
msgid "Image"
|
msgid "Image"
|
||||||
msgstr "Bild"
|
msgstr "Bild"
|
||||||
|
|
||||||
#: src/content/models.py:58 src/content/models.py:230
|
#: content/models.py:58 content/models.py:275
|
||||||
msgid "Slug"
|
msgid "Slug"
|
||||||
msgstr "Slug"
|
msgstr "Slug"
|
||||||
|
|
||||||
#: src/content/models.py:60
|
#: content/models.py:60 content/templates/content/article_detail.html:23
|
||||||
#: src/content/templates/content/article_detail.html:23
|
|
||||||
msgid "Author"
|
msgid "Author"
|
||||||
msgstr "Autor"
|
msgstr "Autor"
|
||||||
|
|
||||||
#: src/content/models.py:61
|
#: content/models.py:61
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr "Status"
|
msgstr "Status"
|
||||||
|
|
||||||
#: src/content/models.py:63
|
#: content/models.py:63
|
||||||
msgid "Created"
|
msgid "Created"
|
||||||
msgstr "Erstellt"
|
msgstr "Erstellt"
|
||||||
|
|
||||||
#: src/content/models.py:64
|
#: content/models.py:64
|
||||||
msgid "Modified"
|
msgid "Modified"
|
||||||
msgstr "Bearbeitet"
|
msgstr "Bearbeitet"
|
||||||
|
|
||||||
#: src/content/models.py:68
|
#: content/models.py:68
|
||||||
msgid "Article"
|
msgid "Article"
|
||||||
msgstr "Artikel"
|
msgstr "Artikel"
|
||||||
|
|
||||||
#: src/content/models.py:69
|
#: content/models.py:69
|
||||||
msgid "Articles"
|
msgid "Articles"
|
||||||
msgstr "Artikel"
|
msgstr "Artikel"
|
||||||
|
|
||||||
#: src/content/models.py:126 src/content/models.py:132
|
#: content/models.py:126 content/models.py:132
|
||||||
msgid "The short name for the menu-entry of this page"
|
msgid "The short name for the menu-entry of this page"
|
||||||
msgstr "Ein kurzer Name für den Menüeintrag"
|
msgstr "Ein kurzer Name für den Menüeintrag"
|
||||||
|
|
||||||
#: src/content/models.py:136 src/content/models.py:139
|
#: content/models.py:137 content/models.py:142
|
||||||
msgid "This title appears in the HTML header"
|
msgid "The page title as you'd like it to be seen by the public"
|
||||||
msgstr "Der Titel erscheint im HTML Header"
|
msgstr ""
|
||||||
|
|
||||||
#: src/content/models.py:140
|
#: content/models.py:144
|
||||||
msgid "slug"
|
msgid "slug"
|
||||||
msgstr "Slug"
|
msgstr "Slug"
|
||||||
|
|
||||||
#: src/content/models.py:141
|
#: content/models.py:146
|
||||||
|
msgid ""
|
||||||
|
"The name of the page as it will appear in URLs e.g http://domain.com/blog/"
|
||||||
|
"[my-slug]/"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: content/models.py:153
|
||||||
msgid "Path"
|
msgid "Path"
|
||||||
msgstr "Pfad"
|
msgstr "Pfad"
|
||||||
|
|
||||||
#: src/content/models.py:147
|
#: content/models.py:165
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Position"
|
msgstr "Position"
|
||||||
|
|
||||||
#: src/content/models.py:149
|
#: content/models.py:170
|
||||||
msgid "status"
|
msgid "status"
|
||||||
msgstr "Status"
|
msgstr "Status"
|
||||||
|
|
||||||
#: src/content/models.py:155
|
#: content/models.py:172 content/models.py:173
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Description"
|
||||||
|
msgid "search description"
|
||||||
|
msgstr "Beschreibung"
|
||||||
|
|
||||||
|
#: content/models.py:176
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Content"
|
||||||
|
msgid "content type"
|
||||||
|
msgstr "Inhalt"
|
||||||
|
|
||||||
|
#: content/models.py:181
|
||||||
msgid "enable comments"
|
msgid "enable comments"
|
||||||
msgstr "Kommentare möglich"
|
msgstr "Kommentare möglich"
|
||||||
|
|
||||||
#: src/content/models.py:156
|
#: content/models.py:186
|
||||||
msgid "Template"
|
msgid "Template"
|
||||||
msgstr "Vorlage"
|
msgstr "Vorlage"
|
||||||
|
|
||||||
#: src/content/models.py:219
|
#: content/models.py:194
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "created on"
|
||||||
|
msgid "first created at"
|
||||||
|
msgstr "erstellt am"
|
||||||
|
|
||||||
|
#: content/models.py:199
|
||||||
|
msgid "latest updated at"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: content/models.py:264
|
||||||
msgid "Page"
|
msgid "Page"
|
||||||
msgstr "Seite"
|
msgstr "Seite"
|
||||||
|
|
||||||
#: src/content/models.py:220
|
#: content/models.py:265
|
||||||
msgid "Pages"
|
msgid "Pages"
|
||||||
msgstr "Seiten"
|
msgstr "Seiten"
|
||||||
|
|
||||||
#: src/content/models.py:224 src/content/models.py:225
|
#: content/models.py:269 content/models.py:270
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Name"
|
msgstr "Name"
|
||||||
|
|
||||||
#: src/content/models.py:226 src/content/models.py:227
|
#: content/models.py:271 content/models.py:272
|
||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr "Beschreibung"
|
msgstr "Beschreibung"
|
||||||
|
|
||||||
#: src/content/models.py:235
|
#: content/models.py:280
|
||||||
msgid "Categories"
|
msgid "Categories"
|
||||||
msgstr "Kategorien"
|
msgstr "Kategorien"
|
||||||
|
|
||||||
#: src/content/templates/content/article_archive.html:5
|
#: content/templates/content/article_archive.html:5
|
||||||
#: src/content/templates/content/article_archive.html:20
|
#: content/templates/content/article_archive.html:20
|
||||||
msgid "Article Archive"
|
msgid "Article Archive"
|
||||||
msgstr "Nachrichtenarchiv"
|
msgstr "Nachrichtenarchiv"
|
||||||
|
|
||||||
#: src/content/templates/content/article_archive.html:35
|
#: content/templates/content/article_archive.html:35
|
||||||
#: src/content/templates/content/article_archive_month.html:5
|
#: content/templates/content/article_archive_month.html:5
|
||||||
#: src/content/templates/content/article_archive_year.html:7
|
#: content/templates/content/article_archive_year.html:7
|
||||||
msgid "Archive"
|
msgid "Archive"
|
||||||
msgstr "Archiv"
|
msgstr "Archiv"
|
||||||
|
|
||||||
#: src/content/templates/content/article_archive.html:52
|
#: content/templates/content/article_archive.html:52
|
||||||
msgid "All Categories"
|
msgid "All Categories"
|
||||||
msgstr "Alle Kategorien"
|
msgstr "Alle Kategorien"
|
||||||
|
|
||||||
#: src/content/templates/content/article_archive.html:67
|
#: content/templates/content/article_archive.html:67
|
||||||
msgid "created on"
|
msgid "created on"
|
||||||
msgstr "erstellt am"
|
msgstr "erstellt am"
|
||||||
|
|
||||||
#: src/content/templates/content/article_archive.html:68
|
#: content/templates/content/article_archive.html:68
|
||||||
msgid "by"
|
msgid "by"
|
||||||
msgstr "von"
|
msgstr "von"
|
||||||
|
|
||||||
#: src/content/templates/content/article_archive.html:69
|
#: content/templates/content/article_archive.html:69
|
||||||
msgid "comments"
|
msgid "comments"
|
||||||
msgstr "Kommentare"
|
msgstr "Kommentare"
|
||||||
|
|
||||||
#: src/content/templates/content/article_archive.html:73
|
#: content/templates/content/article_archive.html:73
|
||||||
msgid "Read More"
|
msgid "Read More"
|
||||||
msgstr "Mehr lesen"
|
msgstr "Mehr lesen"
|
||||||
|
|
||||||
#: src/content/templates/content/article_archive.html:76
|
#: content/templates/content/article_archive.html:76
|
||||||
msgid "We're sorry. Your search yielded no results."
|
msgid "We're sorry. Your search yielded no results."
|
||||||
msgstr "Es tut uns leid. Deine Suche ergab keine Treffer."
|
msgstr "Es tut uns leid. Deine Suche ergab keine Treffer."
|
||||||
|
|
||||||
#: src/content/templates/content/article_archive.html:94
|
#: content/templates/content/article_archive.html:94
|
||||||
msgid "Add Article"
|
msgid "Add Article"
|
||||||
msgstr "neuer Artikel "
|
msgstr "neuer Artikel "
|
||||||
|
|
||||||
#: src/content/templates/content/article_archive_month.html:7
|
#: content/templates/content/article_archive_month.html:7
|
||||||
msgid "back"
|
msgid "back"
|
||||||
msgstr "Zurück"
|
msgstr "Zurück"
|
||||||
|
|
||||||
#: src/content/templates/content/article_detail.html:24
|
#: content/templates/content/article_detail.html:24
|
||||||
msgid "Created on"
|
msgid "Created on"
|
||||||
msgstr "Erstellt am"
|
msgstr "Erstellt am"
|
||||||
|
|
||||||
#: src/content/templates/content/article_detail.html:36
|
#: content/templates/content/article_detail.html:36
|
||||||
msgid "share on"
|
msgid "share on"
|
||||||
msgstr "Teile auf"
|
msgstr "Teile auf"
|
||||||
|
|
||||||
#: src/content/templates/content/article_detail.html:51
|
#: content/templates/content/article_detail.html:51
|
||||||
#: src/content/templates/content/article_form.html:17 src/content/views.py:88
|
#: content/templates/content/article_form.html:24 content/views.py:88
|
||||||
msgid "Edit Article"
|
msgid "Edit Article"
|
||||||
msgstr "Artikel bearbeiten"
|
msgstr "Artikel bearbeiten"
|
||||||
|
|
||||||
#: src/content/templates/content/article_form.html:17 src/content/views.py:90
|
#: content/templates/content/article_form.html:24 content/views.py:90
|
||||||
msgid "Create Article"
|
msgid "Create Article"
|
||||||
msgstr "Artikel erstellen"
|
msgstr "Artikel erstellen"
|
||||||
|
|
||||||
#: src/content/templates/content/article_form.html:22
|
#: content/templates/content/article_form.html:29
|
||||||
#: src/content/templates/content/page_form.html:39
|
#: content/templates/content/page_form.html:49
|
||||||
#: src/content/templates/content/page_form.html:46
|
#: content/templates/content/page_form.html:56
|
||||||
msgid "German"
|
msgid "German"
|
||||||
msgstr "Deutsch"
|
msgstr "Deutsch"
|
||||||
|
|
||||||
#: src/content/templates/content/article_form.html:23
|
#: content/templates/content/article_form.html:30
|
||||||
#: src/content/templates/content/page_form.html:40
|
#: content/templates/content/page_form.html:50
|
||||||
#: src/content/templates/content/page_form.html:54
|
#: content/templates/content/page_form.html:64
|
||||||
msgid "English"
|
msgid "English"
|
||||||
msgstr "Englisch"
|
msgstr "Englisch"
|
||||||
|
|
||||||
#: src/content/templates/content/article_form.html:42
|
#: content/templates/content/article_form.html:49
|
||||||
#: src/content/templates/content/page_form.html:63
|
#: content/templates/content/page_form.html:73
|
||||||
msgid "reset"
|
msgid "reset"
|
||||||
msgstr "Zurücksetzen"
|
msgstr "Zurücksetzen"
|
||||||
|
|
||||||
#: src/content/templates/content/article_form.html:43
|
#: content/templates/content/article_form.html:50
|
||||||
#: src/content/templates/content/page_form.html:64
|
#: content/templates/content/page_form.html:74
|
||||||
msgid "save"
|
msgid "save"
|
||||||
msgstr "Speichern"
|
msgstr "Speichern"
|
||||||
|
|
||||||
#: src/content/templates/content/page_form.html:5
|
#: content/templates/content/page_form.html:5
|
||||||
#: src/content/templates/content/page_form.html:32
|
#: content/templates/content/page_form.html:42
|
||||||
msgid "Edit Page"
|
msgid "Edit Page"
|
||||||
msgstr "Seite bearbeiten"
|
msgstr "Seite bearbeiten"
|
||||||
|
|
||||||
#: src/content/templates/content/page_form.html:5
|
#: content/templates/content/page_form.html:5
|
||||||
#: src/content/templates/content/page_form.html:18
|
#: content/templates/content/page_form.html:28
|
||||||
#: src/content/templates/content/page_form.html:32
|
#: content/templates/content/page_form.html:42
|
||||||
msgid "Add Page"
|
msgid "Add Page"
|
||||||
msgstr "Seite hinzufügen"
|
msgstr "Seite hinzufügen"
|
||||||
|
|
||||||
#: src/content/templates/content/page_form.html:17
|
#: content/templates/content/page_form.html:27
|
||||||
msgid "Edit"
|
msgid "Edit"
|
||||||
msgstr "Bearbeiten"
|
msgstr "Bearbeiten"
|
||||||
|
|
||||||
#: src/content/templates/content/page_form.html:34
|
#: content/templates/content/page_form.html:44
|
||||||
msgid "HTML Specific"
|
msgid "HTML Specific"
|
||||||
msgstr "HTML spezifisch"
|
msgstr "HTML spezifisch"
|
||||||
|
|
||||||
#: src/content/views.py:23
|
#: content/views.py:23
|
||||||
msgid "This Category does not exist."
|
msgid "This Category does not exist."
|
||||||
msgstr "Diese Kategorie existiert nicht."
|
msgstr "Diese Kategorie existiert nicht."
|
||||||
|
|
||||||
#: src/content/views.py:157
|
#: content/views.py:157
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "No Page found matching the Path %s"
|
msgid "No Page found matching the Path %s"
|
||||||
msgstr "Keine Seite unter dem Pfad %s gefunden"
|
msgstr "Keine Seite unter dem Pfad %s gefunden"
|
||||||
|
|
||||||
#: src/content/views.py:172
|
#: content/views.py:172
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "No PDF Document found matching the Path %s"
|
msgid "No PDF Document found matching the Path %s"
|
||||||
msgstr "Kein PDF Dokument unter dem Pfad %s gefunden."
|
msgstr "Kein PDF Dokument unter dem Pfad %s gefunden."
|
||||||
|
|
||||||
|
#~ msgid "This title appears in the HTML header"
|
||||||
|
#~ msgstr "Der Titel erscheint im HTML Header"
|
||||||
|
|
||||||
#~ msgid "Share on Google+"
|
#~ msgid "Share on Google+"
|
||||||
#~ msgstr "Auf Google+ teilen"
|
#~ msgstr "Auf Google+ teilen"
|
||||||
|
|
||||||
|
|||||||
@@ -148,6 +148,6 @@ class Migration(migrations.Migration):
|
|||||||
),
|
),
|
||||||
migrations.AlterUniqueTogether(
|
migrations.AlterUniqueTogether(
|
||||||
name='page',
|
name='page',
|
||||||
unique_together=set([('slug', 'parent')]),
|
unique_together={('slug', 'parent')},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
from django.db import migrations
|
||||||
|
from django.db import models
|
||||||
import ckeditor.fields
|
import ckeditor.fields
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,46 +15,55 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='page',
|
model_name='page',
|
||||||
name='date_created',
|
name='date_created',
|
||||||
field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='first created at', editable=False, db_index=True),
|
field=models.DateTimeField(default=django.utils.timezone.now,
|
||||||
|
verbose_name='first created at', editable=False, db_index=True),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='page',
|
model_name='page',
|
||||||
name='date_modified',
|
name='date_modified',
|
||||||
field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='latest updated at', editable=False),
|
field=models.DateTimeField(
|
||||||
|
default=django.utils.timezone.now, verbose_name='latest updated at', editable=False),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='article',
|
model_name='article',
|
||||||
name='date_created',
|
name='date_created',
|
||||||
field=models.DateTimeField(auto_now_add=True, verbose_name='Erstellt'),
|
field=models.DateTimeField(
|
||||||
|
auto_now_add=True, verbose_name='Erstellt'),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='page',
|
model_name='page',
|
||||||
name='content_type',
|
name='content_type',
|
||||||
field=models.IntegerField(verbose_name='Inhaltstyp', choices=[(0, 'Django View'), (1, 'HTML'), (2, 'PDF')]),
|
field=models.IntegerField(verbose_name='Inhaltstyp', choices=[
|
||||||
|
(0, 'Django View'), (1, 'HTML'), (2, 'PDF')]),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='page',
|
model_name='page',
|
||||||
name='path',
|
name='path',
|
||||||
field=models.CharField(verbose_name='Pfad', unique=True, max_length=255, editable=False, db_index=True),
|
field=models.CharField(
|
||||||
|
verbose_name='Pfad', unique=True, max_length=255, editable=False, db_index=True),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='page',
|
model_name='page',
|
||||||
name='slug',
|
name='slug',
|
||||||
field=models.SlugField(help_text='The name of the page as it will appear in URLs e.g http://domain.com/blog/[my-slug]/', max_length=100, verbose_name='Slug'),
|
field=models.SlugField(
|
||||||
|
help_text='The name of the page as it will appear in URLs e.g http://domain.com/blog/[my-slug]/', max_length=100, verbose_name='Slug'),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='page',
|
model_name='page',
|
||||||
name='template',
|
name='template',
|
||||||
field=models.CharField(default=b'content/page.html', max_length=255, verbose_name='Vorlage'),
|
field=models.CharField(
|
||||||
|
default=b'content/page.html', max_length=255, verbose_name='Vorlage'),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='page',
|
model_name='page',
|
||||||
name='title_de',
|
name='title_de',
|
||||||
field=models.CharField(help_text="The page title as you'd like it to be seen by the public", max_length=255, verbose_name=b'Titel'),
|
field=models.CharField(
|
||||||
|
help_text="The page title as you'd like it to be seen by the public", max_length=255, verbose_name=b'Titel'),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='page',
|
model_name='page',
|
||||||
name='title_en',
|
name='title_en',
|
||||||
field=models.CharField(help_text="The page title as you'd like it to be seen by the public", max_length=255, verbose_name=b'Title', blank=True),
|
field=models.CharField(help_text="The page title as you'd like it to be seen by the public",
|
||||||
|
max_length=255, verbose_name=b'Title', blank=True),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -14,11 +14,13 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='page',
|
model_name='page',
|
||||||
name='date_created',
|
name='date_created',
|
||||||
field=models.DateTimeField(auto_now_add=True, verbose_name='first created at', db_index=True),
|
field=models.DateTimeField(
|
||||||
|
auto_now_add=True, verbose_name='first created at', db_index=True),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='page',
|
model_name='page',
|
||||||
name='date_modified',
|
name='date_modified',
|
||||||
field=models.DateTimeField(auto_now=True, verbose_name='latest updated at'),
|
field=models.DateTimeField(
|
||||||
|
auto_now=True, verbose_name='latest updated at'),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -14,11 +14,13 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='page',
|
model_name='page',
|
||||||
name='description_de',
|
name='description_de',
|
||||||
field=models.TextField(verbose_name='search description', blank=True),
|
field=models.TextField(
|
||||||
|
verbose_name='search description', blank=True),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='page',
|
model_name='page',
|
||||||
name='description_en',
|
name='description_en',
|
||||||
field=models.TextField(verbose_name='search description', blank=True),
|
field=models.TextField(
|
||||||
|
verbose_name='search description', blank=True),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from os import path
|
|
||||||
|
|
||||||
from ckeditor.fields import RichTextField
|
from ckeditor.fields import RichTextField
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
@@ -12,8 +10,7 @@ from django.utils import timezone
|
|||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import get_language, ugettext as _
|
from django.utils.translation import get_language, ugettext as _
|
||||||
|
|
||||||
from utils import STATUS_CHOICES, STATUS_WAITING, STATUS_PUBLISHED, \
|
from utils import STATUS_CHOICES, STATUS_WAITING, STATUS_PUBLISHED, CLEANER
|
||||||
cleaner
|
|
||||||
|
|
||||||
CONTENT_CHOICES = (
|
CONTENT_CHOICES = (
|
||||||
(0, u'Django View'),
|
(0, u'Django View'),
|
||||||
@@ -44,7 +41,10 @@ class ArticleManager(models.Manager):
|
|||||||
'author', 'category')
|
'author', 'category')
|
||||||
|
|
||||||
def published(self):
|
def published(self):
|
||||||
return self.filter(status=STATUS_PUBLISHED, date_created__lte=timezone.now())
|
return self.filter(
|
||||||
|
status=STATUS_PUBLISHED,
|
||||||
|
date_created__lte=timezone.now()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Article(models.Model):
|
class Article(models.Model):
|
||||||
@@ -74,8 +74,8 @@ class Article(models.Model):
|
|||||||
self.date_created = timezone.now()
|
self.date_created = timezone.now()
|
||||||
if not self.slug:
|
if not self.slug:
|
||||||
self.slug = slugify(self.headline_de)[:50]
|
self.slug = slugify(self.headline_de)[:50]
|
||||||
self.content_de = cleaner.clean_html(self.content_de)
|
self.content_de = CLEANER.clean_html(self.content_de)
|
||||||
self.content_en = cleaner.clean_html(self.content_en)
|
self.content_en = CLEANER.clean_html(self.content_en)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.headline
|
return self.headline
|
||||||
@@ -120,6 +120,7 @@ class Page(models.Model):
|
|||||||
Ist keine englische Übersetzung vorhanden, wird die deutsche Version
|
Ist keine englische Übersetzung vorhanden, wird die deutsche Version
|
||||||
angeboten.
|
angeboten.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
menu_name_de = models.CharField(
|
menu_name_de = models.CharField(
|
||||||
max_length=255,
|
max_length=255,
|
||||||
verbose_name='Menü Name',
|
verbose_name='Menü Name',
|
||||||
@@ -143,7 +144,10 @@ class Page(models.Model):
|
|||||||
slug = models.SlugField(
|
slug = models.SlugField(
|
||||||
verbose_name=_('slug'),
|
verbose_name=_('slug'),
|
||||||
max_length=100,
|
max_length=100,
|
||||||
help_text=_("The name of the page as it will appear in URLs e.g http://domain.com/blog/[my-slug]/")
|
help_text=_(
|
||||||
|
'The name of the page as it will appear in URLs e.g '
|
||||||
|
'http://domain.com/blog/[my-slug]/'
|
||||||
|
)
|
||||||
)
|
)
|
||||||
path = models.CharField(
|
path = models.CharField(
|
||||||
max_length=255,
|
max_length=255,
|
||||||
@@ -169,8 +173,10 @@ class Page(models.Model):
|
|||||||
default=STATUS_WAITING,
|
default=STATUS_WAITING,
|
||||||
verbose_name=_('status')
|
verbose_name=_('status')
|
||||||
)
|
)
|
||||||
description_de = models.TextField(verbose_name=_('search description'), blank=True)
|
description_de = models.TextField(
|
||||||
description_en = models.TextField(verbose_name=_('search description'), blank=True)
|
verbose_name=_('search description'), blank=True)
|
||||||
|
description_en = models.TextField(
|
||||||
|
verbose_name=_('search description'), blank=True)
|
||||||
content_type = models.IntegerField(
|
content_type = models.IntegerField(
|
||||||
choices=CONTENT_CHOICES,
|
choices=CONTENT_CHOICES,
|
||||||
verbose_name=_('content type'))
|
verbose_name=_('content type'))
|
||||||
@@ -213,26 +219,34 @@ class Page(models.Model):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def description(self):
|
def description(self):
|
||||||
return getattr(self, "description_%s" % get_language()) or self.description_de
|
lang_attr = "description_%s" % get_language()
|
||||||
|
return getattr(self, lang_attr, self.description_de)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def menu_name(self):
|
def menu_name(self):
|
||||||
return getattr(self,
|
lang_attr = "menu_name_%s" % get_language()
|
||||||
"menu_name_%s" % get_language()) or self.menu_name_de
|
return getattr(self, lang_attr, self.menu_name_de)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def pdf_file(self):
|
def pdf_file(self):
|
||||||
return getattr(self, "pdf_%s" % get_language()) or self.pdf_de
|
lang_attr = "pdf_%s" % get_language()
|
||||||
|
return getattr(self, lang_attr, self.pdf_de)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def title(self):
|
def title(self):
|
||||||
return getattr(self, "title_%s" % get_language()) or self.title_de
|
""" Return the translated title if available """
|
||||||
|
lang_attr = "title_%s" % get_language()
|
||||||
|
return getattr(self, lang_attr, self.title_de)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
|
"""
|
||||||
|
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
if self.parent is None:
|
if self.parent is None:
|
||||||
self.path = self.slug
|
self.path = self.slug
|
||||||
else:
|
else:
|
||||||
self.path = path.join(self.parent.path, self.slug)
|
self.path = '/'.join([self.parent.path, self.slug])
|
||||||
|
|
||||||
if self.content_type is None:
|
if self.content_type is None:
|
||||||
if self.pdf_de:
|
if self.pdf_de:
|
||||||
@@ -242,8 +256,8 @@ class Page(models.Model):
|
|||||||
else:
|
else:
|
||||||
self.content_type = 0
|
self.content_type = 0
|
||||||
if self.content_type == 1:
|
if self.content_type == 1:
|
||||||
self.content_de = cleaner.clean_html(self.content_de)
|
self.content_de = CLEANER.clean_html(self.content_de)
|
||||||
self.content_en = cleaner.clean_html(self.content_en)
|
self.content_en = CLEANER.clean_html(self.content_en)
|
||||||
elif self.content_type == 2 and not self.pdf_de.name:
|
elif self.content_type == 2 and not self.pdf_de.name:
|
||||||
raise ValidationError(
|
raise ValidationError(
|
||||||
_(u'Please upload a PDF-File to this PDF-Page.'))
|
_(u'Please upload a PDF-File to this PDF-Page.'))
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from django.contrib.sitemaps import Sitemap
|
from django.contrib.sitemaps import Sitemap
|
||||||
from .models import Article, Page
|
from .models import Article, Page
|
||||||
|
|
||||||
|
|
||||||
class ArticleSitemap(Sitemap):
|
class ArticleSitemap(Sitemap):
|
||||||
changefreq = "never"
|
changefreq = "never"
|
||||||
priority = 0.6
|
priority = 0.6
|
||||||
@@ -17,8 +18,7 @@ class PageSitemap(Sitemap):
|
|||||||
priority = 0.4
|
priority = 0.4
|
||||||
|
|
||||||
def items(self):
|
def items(self):
|
||||||
return Page.objects.all() #filter(status__gt=0)
|
return Page.objects.all() # filter(status__gt=0)
|
||||||
|
|
||||||
def lastmod(self, page):
|
def lastmod(self, page):
|
||||||
return page.date_modified
|
return page.date_modified
|
||||||
|
|
||||||
|
|||||||
@@ -49,10 +49,10 @@
|
|||||||
|
|
||||||
{% block navigation %}
|
{% block navigation %}
|
||||||
<ul id="navigation">
|
<ul id="navigation">
|
||||||
<li><a href="{{current_top_page.get_absolute_url}}" {% if not active_category %}class="active"{% endif %}>{% trans 'All Categories' %}</a></li>
|
<li><a href="{{current_top_page.get_absolute_url}}" {% if not active_category %} class="active"{% endif %}>{% trans 'All Categories' %}</a></li>
|
||||||
{% for category in categories %}
|
{% for category in categories %}
|
||||||
<li><a href="{% url 'article-archive' category=category.slug %}"
|
<li><a href="{% url 'article-archive' category=category.slug %}"
|
||||||
{% ifequal category.slug active_category.slug %}class="active"{% endifequal %}>{{ category.name }}</a></li>
|
{% ifequal category.slug active_category.slug %} class="active"{% endifequal %}>{{ category.name }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n fieldset_extras %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block extra_head %}
|
{% block extra_head %}
|
||||||
<script type="text/javascript" src="{{ STATIC_URL }}js/jquery.min.js"></script>
|
<script type="text/javascript" src="{{ STATIC_URL }}js/jquery.min.js"></script>
|
||||||
@@ -15,11 +15,7 @@ window.onload = function () {
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block maincontent %}
|
{% block maincontent %}
|
||||||
{% get_fieldset "category, image" from form as fieldset_common %}
|
<form action="" method="post" enctype="multipart/form-data">
|
||||||
{% get_fieldset "headline_en, content_en" from form as fieldset_en %}
|
|
||||||
{% get_fieldset "headline_en, content_en" from form as fieldset_en %}
|
|
||||||
|
|
||||||
<form action="" method="post" enctype="multipart/formdata">
|
|
||||||
<fieldset class="grid_12">
|
<fieldset class="grid_12">
|
||||||
<legend>{% if object.pk %}{% trans "Edit Article" %}{% else %}{% trans "Create Article" %}{% endif %}</legend>
|
<legend>{% if object.pk %}{% trans "Edit Article" %}{% else %}{% trans "Create Article" %}{% endif %}</legend>
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ window.onload = function () {
|
|||||||
<li><a href="#en">{% trans "English" %}</a></li>
|
<li><a href="#en">{% trans "English" %}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="tab_container"">
|
<div class="tab_container">
|
||||||
<section id="de" class="tab_content">
|
<section id="de" class="tab_content">
|
||||||
<fieldset class="grid_12">
|
<fieldset class="grid_12">
|
||||||
<legend>{% trans "German" %}</legend>
|
<legend>{% trans "German" %}</legend>
|
||||||
@@ -67,7 +67,7 @@ window.onload = function () {
|
|||||||
<br>
|
<br>
|
||||||
{{form.content_en}}
|
{{form.content_en}}
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<p></p>
|
<p></p>
|
||||||
<p class="buttonbar grid_12">
|
<p class="buttonbar grid_12">
|
||||||
<button type="reset"><span class="fa fa-undo"></span> {% trans 'reset' %}</button>
|
<button type="reset"><span class="fa fa-undo"></span> {% trans 'reset' %}</button>
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ body {
|
|||||||
</div>
|
</div>
|
||||||
<div id="page_footer">
|
<div id="page_footer">
|
||||||
{{ page.title }} Seite:
|
{{ page.title }} Seite:
|
||||||
<pdf:pagenumber>
|
<pdf:pagenumber />
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
Created on 03.10.2011
|
|
||||||
|
|
||||||
@author: christian
|
|
||||||
"""
|
|
||||||
from django.conf.urls import url
|
|
||||||
from .views import ImageList, PageList
|
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
url(r'^image_list.js$', ImageList.as_view(), name='content-image-list'),
|
|
||||||
url(r'^link_list.js$', PageList.as_view(), name='content-page-list'),
|
|
||||||
]
|
|
||||||
@@ -1,31 +1,48 @@
|
|||||||
# Create your views here.
|
import os
|
||||||
|
|
||||||
import django_comments as comments
|
import django_comments as comments
|
||||||
import os
|
from csp.decorators import csp_update
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.http import HttpResponse, Http404
|
from django.http import HttpResponse, Http404
|
||||||
|
from django.utils.decorators import method_decorator
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
|
|
||||||
from . import models, forms
|
|
||||||
from events.models import Photo
|
from events.models import Photo
|
||||||
from utils.mixins import PermissionRequiredMixin
|
from utils.mixins import PermissionRequiredMixin
|
||||||
|
from . import models, forms
|
||||||
|
|
||||||
|
|
||||||
class ArticleArchiveMixin(object):
|
class ArticleArchiveMixin(object):
|
||||||
|
"""
|
||||||
|
Mixin View to add common context data to Views of the news article archive.
|
||||||
|
"""
|
||||||
|
|
||||||
def get_category(self, queryset):
|
def get_category(self, queryset):
|
||||||
try:
|
"""
|
||||||
self.category = models.Category.objects.get(
|
Filter the queryset by category if one has been specified in the URL
|
||||||
slug=self.kwargs['category'])
|
|
||||||
return queryset.filter(category=self.category)
|
:param queryset: an model.Article.objects Queryset
|
||||||
except models.Category.DoesNotExist:
|
:return: an model.Article.objects Queryset filterd by category
|
||||||
raise Http404(_("This Category does not exist."))
|
"""
|
||||||
except KeyError:
|
|
||||||
|
category_slug = self.kwargs.get('category')
|
||||||
|
if not category_slug:
|
||||||
self.category = None
|
self.category = None
|
||||||
return self.queryset
|
return self.queryset
|
||||||
|
try:
|
||||||
|
self.category = models.Category.objects.get(slug=category_slug)
|
||||||
|
except models.Category.DoesNotExist:
|
||||||
|
raise Http404(_("This Category does not exist."))
|
||||||
|
return queryset.filter(category=self.category)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
"""
|
||||||
|
Adds the categories and the active category to the template context.
|
||||||
|
|
||||||
|
:return: an django.template.context
|
||||||
|
"""
|
||||||
|
|
||||||
context = super(ArticleArchiveMixin, self).get_context_data(**kwargs)
|
context = super(ArticleArchiveMixin, self).get_context_data(**kwargs)
|
||||||
context['categories'] = models.Category.objects.all()
|
context['categories'] = models.Category.objects.all()
|
||||||
context['active_category'] = self.category
|
context['active_category'] = self.category
|
||||||
@@ -33,6 +50,10 @@ class ArticleArchiveMixin(object):
|
|||||||
|
|
||||||
|
|
||||||
class ArticleArchiveIndex(ArticleArchiveMixin, generic.ArchiveIndexView):
|
class ArticleArchiveIndex(ArticleArchiveMixin, generic.ArchiveIndexView):
|
||||||
|
"""
|
||||||
|
Displays the latest news and the filters to browse the archives.
|
||||||
|
"""
|
||||||
|
|
||||||
queryset = models.Article.objects.filter(status=models.STATUS_PUBLISHED)
|
queryset = models.Article.objects.filter(status=models.STATUS_PUBLISHED)
|
||||||
date_field = 'date_created'
|
date_field = 'date_created'
|
||||||
paginate_by = 5
|
paginate_by = 5
|
||||||
@@ -40,12 +61,21 @@ class ArticleArchiveIndex(ArticleArchiveMixin, generic.ArchiveIndexView):
|
|||||||
allow_empty = True
|
allow_empty = True
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
queryset = generic.ArchiveIndexView.get_queryset(self)
|
"""
|
||||||
queryset = self.get_category(queryset)
|
Filter the Queryset by category.
|
||||||
return queryset
|
|
||||||
|
:return: models.Article.objects queryset
|
||||||
|
"""
|
||||||
|
return self.get_category(
|
||||||
|
super(ArticleArchiveIndex, self).get_queryset()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ArticleYearArchive(ArticleArchiveMixin, generic.YearArchiveView):
|
class ArticleYearArchive(ArticleArchiveMixin, generic.YearArchiveView):
|
||||||
|
"""
|
||||||
|
Displays the Articles filterd by a specific year
|
||||||
|
"""
|
||||||
|
|
||||||
queryset = models.Article.objects.filter(status=models.STATUS_PUBLISHED)
|
queryset = models.Article.objects.filter(status=models.STATUS_PUBLISHED)
|
||||||
date_field = 'date_created'
|
date_field = 'date_created'
|
||||||
paginate_by = 5
|
paginate_by = 5
|
||||||
@@ -54,12 +84,21 @@ class ArticleYearArchive(ArticleArchiveMixin, generic.YearArchiveView):
|
|||||||
allow_empty = True
|
allow_empty = True
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
queryset = generic.YearArchiveView.get_queryset(self)
|
"""
|
||||||
queryset = self.get_category(queryset)
|
Filter the Queryset by category.
|
||||||
return queryset
|
|
||||||
|
:return: models.Article.objects queryset
|
||||||
|
"""
|
||||||
|
return self.get_category(
|
||||||
|
super(ArticleYearArchive, self).get_queryset()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ArticleMonthArchive(ArticleArchiveMixin, generic.MonthArchiveView):
|
class ArticleMonthArchive(ArticleArchiveMixin, generic.MonthArchiveView):
|
||||||
|
"""
|
||||||
|
Displays the Articles filterd by a specific month
|
||||||
|
"""
|
||||||
|
|
||||||
queryset = models.Article.objects.filter(status=models.STATUS_PUBLISHED)
|
queryset = models.Article.objects.filter(status=models.STATUS_PUBLISHED)
|
||||||
date_field = 'date_created'
|
date_field = 'date_created'
|
||||||
month_format = '%m'
|
month_format = '%m'
|
||||||
@@ -68,16 +107,28 @@ class ArticleMonthArchive(ArticleArchiveMixin, generic.MonthArchiveView):
|
|||||||
allow_empty = True
|
allow_empty = True
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
queryset = generic.MonthArchiveView.get_queryset(self)
|
"""
|
||||||
queryset = self.get_category(queryset)
|
Filter the Queryset by category.
|
||||||
return queryset
|
|
||||||
|
:return: models.Article.objects queryset
|
||||||
|
"""
|
||||||
|
return self.get_category(
|
||||||
|
super(ArticleMonthArchive, self).get_queryset()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ArticleDetail(generic.DetailView):
|
class ArticleDetail(generic.DetailView):
|
||||||
|
"""
|
||||||
|
Render the news Article, but only if it got published.
|
||||||
|
"""
|
||||||
|
|
||||||
queryset = models.Article.objects.filter(status=models.STATUS_PUBLISHED)
|
queryset = models.Article.objects.filter(status=models.STATUS_PUBLISHED)
|
||||||
|
|
||||||
|
|
||||||
class ArticleForm(PermissionRequiredMixin, generic.UpdateView):
|
class ArticleForm(PermissionRequiredMixin, generic.UpdateView):
|
||||||
|
"""
|
||||||
|
View to add or edit an Article
|
||||||
|
"""
|
||||||
model = models.Article
|
model = models.Article
|
||||||
form_class = forms.ArticleForm
|
form_class = forms.ArticleForm
|
||||||
permission_required = 'content.change_article'
|
permission_required = 'content.change_article'
|
||||||
@@ -97,28 +148,11 @@ class ArticleForm(PermissionRequiredMixin, generic.UpdateView):
|
|||||||
return models.Article(author=self.request.user)
|
return models.Article(author=self.request.user)
|
||||||
|
|
||||||
|
|
||||||
class ImageList(generic.View):
|
|
||||||
# noinspection PyMethodMayBeStatic
|
|
||||||
|
|
||||||
def get(self, kwargs):
|
|
||||||
image_list = []
|
|
||||||
response = HttpResponse(content_type='text/javascript')
|
|
||||||
response.write('var tinyMCEImageList = new Array(')
|
|
||||||
os.chdir(settings.MEDIA_ROOT)
|
|
||||||
for dirpath, dirnames, filenames in os.walk(
|
|
||||||
'images'): # @UnusedVariable @IgnorePep8
|
|
||||||
filenames.sort()
|
|
||||||
for filename in filenames:
|
|
||||||
image_list.append('["%(name)s", "%(path)s"]' % {
|
|
||||||
'name': os.path.join(dirpath, filename),
|
|
||||||
'path': os.path.join(settings.MEDIA_URL, dirpath, filename)
|
|
||||||
})
|
|
||||||
response.write(', '.join(image_list))
|
|
||||||
response.write(');')
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
class PageAddForm(PermissionRequiredMixin, generic.CreateView):
|
class PageAddForm(PermissionRequiredMixin, generic.CreateView):
|
||||||
|
"""
|
||||||
|
Renders an Form to create a new page for users with conforming permissions.
|
||||||
|
"""
|
||||||
|
|
||||||
form_class = forms.PageForm
|
form_class = forms.PageForm
|
||||||
template_name = 'content/page_form.html'
|
template_name = 'content/page_form.html'
|
||||||
permission_required = 'content.add_page'
|
permission_required = 'content.add_page'
|
||||||
@@ -132,8 +166,16 @@ class PageAddForm(PermissionRequiredMixin, generic.CreateView):
|
|||||||
parent = models.Page.objects.get(path=path)
|
parent = models.Page.objects.get(path=path)
|
||||||
return {'parent': parent}
|
return {'parent': parent}
|
||||||
|
|
||||||
|
@method_decorator(csp_update(SCRIPT_SRC="'unsafe-eval'"))
|
||||||
|
def dispatch(self, *args, **kwargs):
|
||||||
|
return super(PageAddForm, self).dispatch(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class PageEditForm(PermissionRequiredMixin, generic.UpdateView):
|
class PageEditForm(PermissionRequiredMixin, generic.UpdateView):
|
||||||
|
"""
|
||||||
|
Renders an Form to edit a page for users with conforming permissions.
|
||||||
|
"""
|
||||||
|
|
||||||
form_class = forms.PageForm
|
form_class = forms.PageForm
|
||||||
permission_required = 'content.change_page'
|
permission_required = 'content.change_page'
|
||||||
|
|
||||||
@@ -145,6 +187,10 @@ class PageEditForm(PermissionRequiredMixin, generic.UpdateView):
|
|||||||
path = path[:-1]
|
path = path[:-1]
|
||||||
return models.Page.objects.get(path=path)
|
return models.Page.objects.get(path=path)
|
||||||
|
|
||||||
|
@method_decorator(csp_update(SCRIPT_SRC="'unsafe-eval'"))
|
||||||
|
def dispatch(self, *args, **kwargs):
|
||||||
|
return super(PageEditForm, self).dispatch(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class PageHtml(generic.DetailView):
|
class PageHtml(generic.DetailView):
|
||||||
|
|
||||||
@@ -184,23 +230,6 @@ class PagePdf(generic.DeleteView):
|
|||||||
raise Http404('File not Found %s.pdf' % self.kwargs['path'])
|
raise Http404('File not Found %s.pdf' % self.kwargs['path'])
|
||||||
|
|
||||||
|
|
||||||
class PageList(generic.View):
|
|
||||||
# noinspection PyMethodMayBeStatic
|
|
||||||
|
|
||||||
def get(self, kwargs):
|
|
||||||
response = HttpResponse(content_type='text/javascript')
|
|
||||||
response.write('var tinyMCELinkList = new Array(')
|
|
||||||
page_list = []
|
|
||||||
for page in models.Page.objects.filter(status=models.STATUS_PUBLISHED):
|
|
||||||
page_list.append('["%(name)s", "%(path)s"]' % {
|
|
||||||
'name': page.menu_name,
|
|
||||||
'path': page.get_absolute_url()
|
|
||||||
})
|
|
||||||
response.write(', '.join(page_list))
|
|
||||||
response.write(');')
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
class StartPage(generic.TemplateView):
|
class StartPage(generic.TemplateView):
|
||||||
template_name = 'index.html'
|
template_name = 'index.html'
|
||||||
|
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ def upcoming_events(request):
|
|||||||
next_event = cache.get('next_event', False)
|
next_event = cache.get('next_event', False)
|
||||||
upcoming_events = cache.get('upcoming_events', False)
|
upcoming_events = cache.get('upcoming_events', False)
|
||||||
|
|
||||||
if current_event == False:
|
if not current_event:
|
||||||
current_event = Event.objects.current_event()
|
current_event = Event.objects.current_event()
|
||||||
cache.set('current_event', current_event, 360)
|
cache.set('current_event', current_event, 360)
|
||||||
if next_event == False:
|
if not next_event:
|
||||||
next_event = Event.objects.next_event()
|
next_event = Event.objects.next_event()
|
||||||
cache.set('next_event', next_event, 360)
|
cache.set('next_event', next_event, 360)
|
||||||
|
|
||||||
|
|||||||
1291
src/events/fixtures/test_events.json
Normal file
1291
src/events/fixtures/test_events.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,6 @@ from django.utils.translation import ugettext as _
|
|||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
from utils.html5.widgets import DateTimeInput
|
|
||||||
|
|
||||||
|
|
||||||
user_query = get_user_model().objects.all()
|
user_query = get_user_model().objects.all()
|
||||||
@@ -47,16 +46,17 @@ class EventForm(forms.ModelForm):
|
|||||||
|
|
||||||
start = forms.DateTimeField(
|
start = forms.DateTimeField(
|
||||||
label=_('start'), required=True,
|
label=_('start'), required=True,
|
||||||
widget=DateTimeInput() # widget=SplitDateTimeWidget()
|
widget=forms.SplitHiddenDateTimeWidget()
|
||||||
)
|
)
|
||||||
end = forms.DateTimeField(
|
end = forms.DateTimeField(
|
||||||
label=_('end'), required=False,
|
label=_('end'), required=False,
|
||||||
widget=DateTimeInput() # widget=SplitDateTimeWidget()
|
widget=forms.SplitDateTimeWidget()
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta(object):
|
class Meta(object):
|
||||||
model = models.Event
|
model = models.Event
|
||||||
exclude = ('event_count', 'event_series', )
|
exclude = ('event_count', 'event_series', )
|
||||||
|
|
||||||
|
|
||||||
EventSeriesFormset = forms.inlineformset_factory(
|
EventSeriesFormset = forms.inlineformset_factory(
|
||||||
models.Event, models.Event, fields=('start', 'end'), form=EventForm)
|
models.Event, models.Event, fields=('start', 'end'), form=EventForm)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: kasu.events\n"
|
"Project-Id-Version: kasu.events\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2016-09-28 00:25+0200\n"
|
"POT-Creation-Date: 2017-05-10 23:16+0200\n"
|
||||||
"PO-Revision-Date: 2016-09-28 00:24+0200\n"
|
"PO-Revision-Date: 2016-09-28 00:24+0200\n"
|
||||||
"Last-Translator: Christian Berg <xeniac@posteo.at>\n"
|
"Last-Translator: Christian Berg <xeniac@posteo.at>\n"
|
||||||
"Language-Team: Kasu <verein@kasu.at>\n"
|
"Language-Team: Kasu <verein@kasu.at>\n"
|
||||||
@@ -19,58 +19,58 @@ msgstr ""
|
|||||||
"X-Generator: Poedit 1.8.9\n"
|
"X-Generator: Poedit 1.8.9\n"
|
||||||
"X-Translated-Using: django-rosetta 0.7.6\n"
|
"X-Translated-Using: django-rosetta 0.7.6\n"
|
||||||
|
|
||||||
#: src/events/admin.py:16 src/events/models.py:109
|
#: events/admin.py:16 events/models.py:114
|
||||||
msgid "Event Series"
|
msgid "Event Series"
|
||||||
msgstr "Veranstaltungsreihen"
|
msgstr "Veranstaltungsreihen"
|
||||||
|
|
||||||
#: src/events/forms.py:23
|
#: events/forms.py:23
|
||||||
msgid "Images"
|
msgid "Images"
|
||||||
msgstr "Bilder"
|
msgstr "Bilder"
|
||||||
|
|
||||||
#: src/events/forms.py:49
|
#: events/forms.py:49
|
||||||
msgid "start"
|
msgid "start"
|
||||||
msgstr "Beginn"
|
msgstr "Beginn"
|
||||||
|
|
||||||
#: src/events/forms.py:53
|
#: events/forms.py:53
|
||||||
msgid "end"
|
msgid "end"
|
||||||
msgstr "Ende"
|
msgstr "Ende"
|
||||||
|
|
||||||
#: src/events/models.py:82 src/events/models.py:186 src/events/models.py:228
|
#: events/models.py:84 events/models.py:207 events/models.py:260
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Name"
|
msgstr "Name"
|
||||||
|
|
||||||
#: src/events/models.py:83 src/events/models.py:187 src/events/models.py:233
|
#: events/models.py:85 events/models.py:208 events/models.py:268
|
||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr "Beschreibung"
|
msgstr "Beschreibung"
|
||||||
|
|
||||||
#: src/events/models.py:85 src/events/templates/events/event_detail.html:31
|
#: events/models.py:87 events/templates/events/event_detail.html:29
|
||||||
#: src/events/templates/events/event_detail.html:74
|
#: events/templates/events/event_detail.html:87
|
||||||
#: src/events/templates/events/event_list.html:28
|
#: events/templates/events/event_list.html:28
|
||||||
#: src/events/templates/events/photo_upload.html:13
|
#: events/templates/events/photo_upload.html:13
|
||||||
msgid "Start"
|
msgid "Start"
|
||||||
msgstr "Beginn"
|
msgstr "Beginn"
|
||||||
|
|
||||||
#: src/events/models.py:86 src/events/templates/events/event_detail.html:32
|
#: events/models.py:88 events/templates/events/event_detail.html:30
|
||||||
#: src/events/templates/events/event_detail.html:75
|
#: events/templates/events/event_detail.html:89
|
||||||
msgid "End"
|
msgid "End"
|
||||||
msgstr "Ende"
|
msgstr "Ende"
|
||||||
|
|
||||||
#: src/events/models.py:87 src/events/models.py:195
|
#: events/models.py:89 events/models.py:216
|
||||||
#: src/events/templates/events/event_detail.html:36
|
#: events/templates/events/event_detail.html:34
|
||||||
#: src/events/templates/events/event_detail.html:70
|
#: events/templates/events/event_detail.html:80
|
||||||
#: src/events/templates/events/event_detail.html:76
|
#: events/templates/events/event_detail.html:92
|
||||||
msgid "Homepage"
|
msgid "Homepage"
|
||||||
msgstr "Homepage"
|
msgstr "Homepage"
|
||||||
|
|
||||||
#: src/events/models.py:89 src/events/models.py:189 src/events/models.py:229
|
#: events/models.py:91 events/models.py:210 events/models.py:262
|
||||||
msgid "Image"
|
msgid "Image"
|
||||||
msgstr "Bild"
|
msgstr "Bild"
|
||||||
|
|
||||||
#: src/events/models.py:96
|
#: events/models.py:98
|
||||||
msgid "Mahjong Tournament"
|
msgid "Mahjong Tournament"
|
||||||
msgstr "Mahjong Turnier"
|
msgstr "Mahjong Turnier"
|
||||||
|
|
||||||
#: src/events/models.py:98
|
#: events/models.py:100
|
||||||
msgid ""
|
msgid ""
|
||||||
"This event is a tournament, different rules apply for the kyu "
|
"This event is a tournament, different rules apply for the kyu "
|
||||||
"ranking."
|
"ranking."
|
||||||
@@ -78,11 +78,11 @@ msgstr ""
|
|||||||
"Diese Veranstaltung ist ein Turnier, es gelten andere Regeln für das Kyu "
|
"Diese Veranstaltung ist ein Turnier, es gelten andere Regeln für das Kyu "
|
||||||
"Ranking."
|
"Ranking."
|
||||||
|
|
||||||
#: src/events/models.py:102
|
#: events/models.py:104
|
||||||
msgid "Mahjong Season"
|
msgid "Mahjong Season"
|
||||||
msgstr "Mahjong Saison"
|
msgstr "Mahjong Saison"
|
||||||
|
|
||||||
#: src/events/models.py:110
|
#: events/models.py:115
|
||||||
msgid ""
|
msgid ""
|
||||||
"Wenn dieser Event zu einer Veranstaltungsreihe gehört werden Ort, "
|
"Wenn dieser Event zu einer Veranstaltungsreihe gehört werden Ort, "
|
||||||
"Beschreibung, Bild und Homepage von dem hier angegebenen Event "
|
"Beschreibung, Bild und Homepage von dem hier angegebenen Event "
|
||||||
@@ -91,236 +91,244 @@ msgstr ""
|
|||||||
"Wenn dieser Termin zu einer Veranstaltungsreihe gehört werden Ort, "
|
"Wenn dieser Termin zu einer Veranstaltungsreihe gehört werden Ort, "
|
||||||
"Beschreibung, Bild und Homepage von dem hier angegebenen Event übernommen."
|
"Beschreibung, Bild und Homepage von dem hier angegebenen Event übernommen."
|
||||||
|
|
||||||
#: src/events/models.py:117
|
#: events/models.py:124 events/models.py:226 events/models.py:290
|
||||||
|
msgid "first created at"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: events/models.py:129 events/models.py:231 events/models.py:295
|
||||||
|
msgid "latest updated at"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: events/models.py:134
|
||||||
msgid "Event"
|
msgid "Event"
|
||||||
msgstr "Termin"
|
msgstr "Termin"
|
||||||
|
|
||||||
#: src/events/models.py:118
|
#: events/models.py:135
|
||||||
msgid "Events"
|
msgid "Events"
|
||||||
msgstr "Termine"
|
msgstr "Termine"
|
||||||
|
|
||||||
#: src/events/models.py:131
|
#: events/models.py:148
|
||||||
msgid "A event can't end before it had started"
|
msgid "A event can't end before it had started"
|
||||||
msgstr "Eine Veranstaltung kann nicht enden bevor sie begonnen hat"
|
msgstr "Eine Veranstaltung kann nicht enden bevor sie begonnen hat"
|
||||||
|
|
||||||
#: src/events/models.py:196
|
#: events/models.py:217
|
||||||
msgid "Postal Code"
|
msgid "Postal Code"
|
||||||
msgstr "Postleitzahl"
|
msgstr "Postleitzahl"
|
||||||
|
|
||||||
#: src/events/models.py:197
|
#: events/models.py:218
|
||||||
msgid "Street Address"
|
msgid "Street Address"
|
||||||
msgstr "Straße"
|
msgstr "Straße"
|
||||||
|
|
||||||
#: src/events/models.py:198
|
#: events/models.py:219
|
||||||
msgid "Locality"
|
msgid "Locality"
|
||||||
msgstr "Ort"
|
msgstr "Ort"
|
||||||
|
|
||||||
#: src/events/models.py:199
|
#: events/models.py:220
|
||||||
msgid "Country"
|
msgid "Country"
|
||||||
msgstr "Land"
|
msgstr "Land"
|
||||||
|
|
||||||
#: src/events/models.py:202
|
#: events/models.py:235
|
||||||
msgid "Venue"
|
msgid "Venue"
|
||||||
msgstr "Veranstaltungsort"
|
msgstr "Veranstaltungsort"
|
||||||
|
|
||||||
#: src/events/models.py:203
|
#: events/models.py:236
|
||||||
msgid "Venues"
|
msgid "Venues"
|
||||||
msgstr "Veranstaltungsorte"
|
msgstr "Veranstaltungsorte"
|
||||||
|
|
||||||
#: src/events/models.py:239
|
#: events/models.py:274
|
||||||
msgid "Startpage"
|
msgid "Startpage"
|
||||||
msgstr "Startseite"
|
msgstr "Startseite"
|
||||||
|
|
||||||
#: src/events/models.py:242
|
#: events/models.py:277
|
||||||
msgid "Display this Photo on the Startpage Teaser"
|
msgid "Display this Photo on the Startpage Teaser"
|
||||||
msgstr "Foto als Teaser auf der Startseite verwenden."
|
msgstr "Foto als Teaser auf der Startseite verwenden."
|
||||||
|
|
||||||
#: src/events/models.py:244
|
#: events/models.py:279
|
||||||
msgid "Published on"
|
msgid "Published on"
|
||||||
msgstr "Veröffentlicht am"
|
msgstr "Veröffentlicht am"
|
||||||
|
|
||||||
#: src/events/models.py:246
|
#: events/models.py:281
|
||||||
msgid "Number of views"
|
msgid "Number of views"
|
||||||
msgstr "Wie oft gesehen"
|
msgstr "Wie oft gesehen"
|
||||||
|
|
||||||
#: src/events/models.py:258 src/events/templates/events/event_archive.html:38
|
#: events/models.py:306 events/templates/events/event_archive.html:38
|
||||||
#: src/events/templates/events/event_list.html:18
|
#: events/templates/events/event_list.html:18
|
||||||
msgid "Event Image"
|
msgid "Event Image"
|
||||||
msgstr "Veranstaltungsbild"
|
msgstr "Veranstaltungsbild"
|
||||||
|
|
||||||
#: src/events/models.py:259
|
#: events/models.py:307
|
||||||
msgid "Event Images"
|
msgid "Event Images"
|
||||||
msgstr "Veranstaltungsbilder"
|
msgstr "Veranstaltungsbilder"
|
||||||
|
|
||||||
#: src/events/templates/events/event_archive.html:5
|
#: events/templates/events/event_archive.html:5
|
||||||
#: src/events/templates/events/event_archive.html:9
|
#: events/templates/events/event_archive.html:9
|
||||||
msgid "Event Archive"
|
msgid "Event Archive"
|
||||||
msgstr "Veranstaltungsarchiv"
|
msgstr "Veranstaltungsarchiv"
|
||||||
|
|
||||||
#: src/events/templates/events/event_archive.html:42
|
#: events/templates/events/event_archive.html:42
|
||||||
#: src/events/templates/events/event_detail.html:72
|
#: events/templates/events/event_detail.html:85
|
||||||
#: src/events/templates/events/event_list.html:22
|
#: events/templates/events/event_list.html:22
|
||||||
#: src/events/templates/events/photo_detail.html:48
|
#: events/templates/events/photo_detail.html:53
|
||||||
msgid "Date"
|
msgid "Date"
|
||||||
msgstr "Datum"
|
msgstr "Datum"
|
||||||
|
|
||||||
#: src/events/templates/events/event_archive.html:47
|
#: events/templates/events/event_archive.html:47
|
||||||
msgid "Time"
|
msgid "Time"
|
||||||
msgstr "Zeit"
|
msgstr "Zeit"
|
||||||
|
|
||||||
#: src/events/templates/events/event_archive.html:49
|
#: events/templates/events/event_archive.html:49
|
||||||
#: src/events/templates/events/photo_upload.html:16
|
#: events/templates/events/photo_upload.html:16
|
||||||
msgid "from"
|
msgid "from"
|
||||||
msgstr "von"
|
msgstr "von"
|
||||||
|
|
||||||
#: src/events/templates/events/event_archive.html:49
|
#: events/templates/events/event_archive.html:49
|
||||||
#: src/events/templates/events/photo_upload.html:16
|
#: events/templates/events/photo_upload.html:16
|
||||||
msgid "to"
|
msgid "to"
|
||||||
msgstr "bis"
|
msgstr "bis"
|
||||||
|
|
||||||
#: src/events/templates/events/event_archive.html:57
|
#: events/templates/events/event_archive.html:57
|
||||||
#: src/events/templates/events/event_detail.html:33
|
#: events/templates/events/event_detail.html:31
|
||||||
#: src/events/templates/events/event_detail.html:62
|
#: events/templates/events/event_detail.html:72
|
||||||
#: src/events/templates/events/event_list.html:32
|
#: events/templates/events/event_list.html:32
|
||||||
#: src/events/templates/events/photo_upload.html:23
|
#: events/templates/events/photo_upload.html:23
|
||||||
msgid "Location"
|
msgid "Location"
|
||||||
msgstr "Ort"
|
msgstr "Ort"
|
||||||
|
|
||||||
#: src/events/templates/events/event_archive.html:58
|
#: events/templates/events/event_archive.html:58
|
||||||
#: src/events/templates/events/event_list.html:35
|
#: events/templates/events/event_list.html:35
|
||||||
#: src/events/templates/events/photo_upload.html:25
|
#: events/templates/events/photo_upload.html:25
|
||||||
#: src/events/templates/events/photo_upload.html:26
|
#: events/templates/events/photo_upload.html:26
|
||||||
msgid "Comments"
|
msgid "Comments"
|
||||||
msgstr "Kommentare"
|
msgstr "Kommentare"
|
||||||
|
|
||||||
#: src/events/templates/events/event_archive.html:59
|
#: events/templates/events/event_archive.html:59
|
||||||
#: src/events/templates/events/event_detail.html:38
|
#: events/templates/events/event_detail.html:36
|
||||||
#: src/events/templates/events/event_detail.html:48
|
#: events/templates/events/event_detail.html:48
|
||||||
#: src/events/templates/events/photo_upload.html:28
|
#: events/templates/events/photo_upload.html:28
|
||||||
#: src/events/templates/events/photo_upload.html:29
|
#: events/templates/events/photo_upload.html:29
|
||||||
msgid "Photos"
|
msgid "Photos"
|
||||||
msgstr "Fotos"
|
msgstr "Fotos"
|
||||||
|
|
||||||
#: src/events/templates/events/event_archive.html:60
|
#: events/templates/events/event_archive.html:60
|
||||||
#: src/events/templates/events/event_archive.html:61
|
#: events/templates/events/event_archive.html:61
|
||||||
#: src/events/templates/events/event_detail.html:37
|
#: events/templates/events/event_detail.html:35
|
||||||
#: src/events/templates/events/event_detail.html:49
|
#: events/templates/events/event_detail.html:51
|
||||||
msgid "Hanchans"
|
msgid "Hanchans"
|
||||||
msgstr "Hanchans"
|
msgstr "Hanchans"
|
||||||
|
|
||||||
#: src/events/templates/events/event_detail.html:39
|
#: events/templates/events/event_detail.html:37
|
||||||
msgid "tourney"
|
msgid "tourney"
|
||||||
msgstr "Turnier"
|
msgstr "Turnier"
|
||||||
|
|
||||||
#: src/events/templates/events/event_detail.html:39
|
#: events/templates/events/event_detail.html:37
|
||||||
msgid "other rules apply here"
|
msgid "other rules apply here"
|
||||||
msgstr "hier gelten andere Regeln"
|
msgstr "hier gelten andere Regeln"
|
||||||
|
|
||||||
#: src/events/templates/events/event_detail.html:47
|
#: events/templates/events/event_detail.html:45
|
||||||
msgid "Info"
|
msgid "Info"
|
||||||
msgstr "Info"
|
msgstr "Info"
|
||||||
|
|
||||||
#: src/events/templates/events/event_detail.html:50
|
#: events/templates/events/event_detail.html:54
|
||||||
msgid "Mai-Star Games"
|
msgid "Mai-Star Games"
|
||||||
msgstr "Mai-Star Spiele"
|
msgstr "Mai-Star Spiele"
|
||||||
|
|
||||||
#: src/events/templates/events/event_detail.html:52
|
#: events/templates/events/event_detail.html:57
|
||||||
msgid "Event Ranking"
|
msgid "Event Ranking"
|
||||||
msgstr "Veranstaltungs Wertung"
|
msgstr "Veranstaltungs Wertung"
|
||||||
|
|
||||||
#: src/events/templates/events/event_detail.html:90
|
#: events/templates/events/event_detail.html:100
|
||||||
msgid "Share on Facebook"
|
msgid "Share on Facebook"
|
||||||
msgstr "Auf Facebook teilen"
|
msgstr "Auf Facebook teilen"
|
||||||
|
|
||||||
#: src/events/templates/events/event_detail.html:96
|
#: events/templates/events/event_detail.html:104
|
||||||
msgid "Share on Google+"
|
msgid "Share on Google+"
|
||||||
msgstr "Auf Google+ teilen"
|
msgstr "Auf Google+ teilen"
|
||||||
|
|
||||||
#: src/events/templates/events/event_detail.html:100
|
#: events/templates/events/event_detail.html:109
|
||||||
msgid "Share on Twitter"
|
msgid "Share on Twitter"
|
||||||
msgstr "Auf Twitter teilen"
|
msgstr "Auf Twitter teilen"
|
||||||
|
|
||||||
#: src/events/templates/events/event_detail.html:104
|
#: events/templates/events/event_detail.html:113
|
||||||
msgid "Show on Google Maps"
|
msgid "Show on Google Maps"
|
||||||
msgstr "Auf Google Maps zeigen"
|
msgstr "Auf Google Maps zeigen"
|
||||||
|
|
||||||
#: src/events/templates/events/event_detail.html:121
|
#: events/templates/events/event_detail.html:127
|
||||||
#: src/events/templates/events/event_form.html:9 src/events/views.py:106
|
#: events/templates/events/event_form.html:9 events/views.py:106
|
||||||
msgid "Edit Event"
|
msgid "Edit Event"
|
||||||
msgstr "Termin bearbeiten"
|
msgstr "Termin bearbeiten"
|
||||||
|
|
||||||
#: src/events/templates/events/event_detail.html:124
|
#: events/templates/events/event_detail.html:131
|
||||||
msgid "Add Dates"
|
msgid "Add Dates"
|
||||||
msgstr "Termine hinzufügen"
|
msgstr "Termine hinzufügen"
|
||||||
|
|
||||||
#: src/events/templates/events/event_form.html:9
|
#: events/templates/events/event_form.html:9
|
||||||
#: src/events/templates/events/page.html:9 src/events/views.py:108
|
#: events/templates/events/page.html:9 events/views.py:108
|
||||||
msgid "Add Event"
|
msgid "Add Event"
|
||||||
msgstr "Neuer Termin"
|
msgstr "Neuer Termin"
|
||||||
|
|
||||||
#: src/events/templates/events/event_form.html:19
|
#: events/templates/events/event_form.html:19
|
||||||
#: src/events/templates/events/photo_list.html:35
|
#: events/templates/events/photo_list.html:35
|
||||||
msgid "reset"
|
msgid "reset"
|
||||||
msgstr "Zurücksetzen"
|
msgstr "Zurücksetzen"
|
||||||
|
|
||||||
#: src/events/templates/events/event_form.html:20
|
#: events/templates/events/event_form.html:20
|
||||||
#: src/events/templates/events/eventseries_form.html:23
|
#: events/templates/events/eventseries_form.html:25
|
||||||
msgid "save"
|
msgid "save"
|
||||||
msgstr "Speichern"
|
msgstr "Speichern"
|
||||||
|
|
||||||
#: src/events/templates/events/event_list.html:4
|
#: events/templates/events/event_list.html:4
|
||||||
#: src/events/templates/events/event_list.html:5
|
#: events/templates/events/event_list.html:5
|
||||||
msgid "Upcoming Events"
|
msgid "Upcoming Events"
|
||||||
msgstr "Bevorstehende Veranstaltungen"
|
msgstr "Bevorstehende Veranstaltungen"
|
||||||
|
|
||||||
#: src/events/templates/events/eventseries_form.html:22
|
#: events/templates/events/eventseries_form.html:24
|
||||||
msgid "back"
|
msgid "back"
|
||||||
msgstr "Zurück"
|
msgstr "Zurück"
|
||||||
|
|
||||||
#: src/events/templates/events/photo_confirm_delete.html:17
|
#: events/templates/events/photo_confirm_delete.html:17
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Abbrechen"
|
msgstr "Abbrechen"
|
||||||
|
|
||||||
#: src/events/templates/events/photo_confirm_delete.html:21
|
#: events/templates/events/photo_confirm_delete.html:21
|
||||||
#: src/events/templates/events/photo_list.html:21
|
#: events/templates/events/photo_list.html:21
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Löschen"
|
msgstr "Löschen"
|
||||||
|
|
||||||
#: src/events/templates/events/photo_detail.html:39
|
#: events/templates/events/photo_detail.html:44
|
||||||
msgid "previous"
|
msgid "previous"
|
||||||
msgstr "Zurück"
|
msgstr "Zurück"
|
||||||
|
|
||||||
#: src/events/templates/events/photo_detail.html:47
|
#: events/templates/events/photo_detail.html:52
|
||||||
msgid "Photographer"
|
msgid "Photographer"
|
||||||
msgstr "Fotograf"
|
msgstr "Fotograf"
|
||||||
|
|
||||||
#: src/events/templates/events/photo_detail.html:53
|
#: events/templates/events/photo_detail.html:58
|
||||||
msgid "share on"
|
msgid "share on"
|
||||||
msgstr "Teile auf"
|
msgstr "Teile auf"
|
||||||
|
|
||||||
#: src/events/templates/events/photo_detail.html:76
|
#: events/templates/events/photo_detail.html:81
|
||||||
msgid "download"
|
msgid "download"
|
||||||
msgstr "Herunterladen"
|
msgstr "Herunterladen"
|
||||||
|
|
||||||
#: src/events/templates/events/photo_detail.html:77
|
#: events/templates/events/photo_detail.html:82
|
||||||
msgid "Rotate counter clockwise"
|
msgid "Rotate counter clockwise"
|
||||||
msgstr "mit dem Uhrzeiger drehen"
|
msgstr "mit dem Uhrzeiger drehen"
|
||||||
|
|
||||||
#: src/events/templates/events/photo_detail.html:78
|
#: events/templates/events/photo_detail.html:83
|
||||||
msgid "Rotate clockwise"
|
msgid "Rotate clockwise"
|
||||||
msgstr "gegen den Uhrzeiger drehen"
|
msgstr "gegen den Uhrzeiger drehen"
|
||||||
|
|
||||||
#: src/events/templates/events/photo_detail.html:79
|
#: events/templates/events/photo_detail.html:84
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Speichern"
|
msgstr "Speichern"
|
||||||
|
|
||||||
#: src/events/templates/events/photo_list.html:36
|
#: events/templates/events/photo_list.html:36
|
||||||
#: src/events/templates/events/photo_upload.html:35
|
#: events/templates/events/photo_upload.html:35
|
||||||
#: src/events/templates/events/photo_upload.html:49
|
#: events/templates/events/photo_upload.html:49
|
||||||
msgid "Upload"
|
msgid "Upload"
|
||||||
msgstr "Hochladen"
|
msgstr "Hochladen"
|
||||||
|
|
||||||
#: src/events/views.py:209
|
#: events/views.py:209
|
||||||
msgid "Event does not exist"
|
msgid "Event does not exist"
|
||||||
msgstr "Veranstaltung gibt es nicht"
|
msgstr "Veranstaltung gibt es nicht"
|
||||||
|
|
||||||
|
|||||||
@@ -13,12 +13,14 @@ class Migration(migrations.Migration):
|
|||||||
operations = [
|
operations = [
|
||||||
migrations.AlterModelOptions(
|
migrations.AlterModelOptions(
|
||||||
name='photo',
|
name='photo',
|
||||||
options={'ordering': ['created_date'], 'get_latest_by': 'created_date', 'verbose_name': 'Veranstaltungsbild', 'verbose_name_plural': 'Veranstaltungsbilder'},
|
options={'ordering': ['created_date'], 'get_latest_by': 'created_date',
|
||||||
|
'verbose_name': 'Veranstaltungsbild', 'verbose_name_plural': 'Veranstaltungsbilder'},
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='event',
|
model_name='event',
|
||||||
name='mahjong_season',
|
name='mahjong_season',
|
||||||
field=models.PositiveSmallIntegerField(null=True, verbose_name='Mahjong Saison', blank=True),
|
field=models.PositiveSmallIntegerField(
|
||||||
|
null=True, verbose_name='Mahjong Saison', blank=True),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='photo',
|
model_name='photo',
|
||||||
@@ -28,11 +30,13 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='photo',
|
model_name='photo',
|
||||||
name='on_startpage',
|
name='on_startpage',
|
||||||
field=models.BooleanField(default=False, help_text='Foto als Teaser auf der Startseite verwenden.', db_index=True, verbose_name='Startseite'),
|
field=models.BooleanField(
|
||||||
|
default=False, help_text='Foto als Teaser auf der Startseite verwenden.', db_index=True, verbose_name='Startseite'),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='photo',
|
model_name='photo',
|
||||||
name='views',
|
name='views',
|
||||||
field=models.PositiveIntegerField(default=0, verbose_name='Wie oft gesehen', editable=False),
|
field=models.PositiveIntegerField(
|
||||||
|
default=0, verbose_name='Wie oft gesehen', editable=False),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -16,34 +16,40 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='event',
|
model_name='event',
|
||||||
name='date_created',
|
name='date_created',
|
||||||
field=models.DateTimeField(auto_now_add=True, null=True, verbose_name='first created at', db_index=True),
|
field=models.DateTimeField(
|
||||||
|
auto_now_add=True, null=True, verbose_name='first created at', db_index=True),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='event',
|
model_name='event',
|
||||||
name='date_modified',
|
name='date_modified',
|
||||||
field=models.DateTimeField(default=datetime.datetime(2016, 10, 12, 20, 24, 39, 910492, tzinfo=utc), verbose_name='latest updated at', auto_now=True),
|
field=models.DateTimeField(default=datetime.datetime(
|
||||||
|
2016, 10, 12, 20, 24, 39, 910492, tzinfo=utc), verbose_name='latest updated at', auto_now=True),
|
||||||
preserve_default=False,
|
preserve_default=False,
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='location',
|
model_name='location',
|
||||||
name='date_created',
|
name='date_created',
|
||||||
field=models.DateTimeField(auto_now_add=True, null=True, verbose_name='first created at', db_index=True),
|
field=models.DateTimeField(
|
||||||
|
auto_now_add=True, null=True, verbose_name='first created at', db_index=True),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='location',
|
model_name='location',
|
||||||
name='date_modified',
|
name='date_modified',
|
||||||
field=models.DateTimeField(default=datetime.datetime(2016, 10, 12, 20, 24, 44, 566305, tzinfo=utc), verbose_name='latest updated at', auto_now=True),
|
field=models.DateTimeField(default=datetime.datetime(
|
||||||
|
2016, 10, 12, 20, 24, 44, 566305, tzinfo=utc), verbose_name='latest updated at', auto_now=True),
|
||||||
preserve_default=False,
|
preserve_default=False,
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='photo',
|
model_name='photo',
|
||||||
name='date_created',
|
name='date_created',
|
||||||
field=models.DateTimeField(auto_now_add=True, null=True, verbose_name='first created at', db_index=True),
|
field=models.DateTimeField(
|
||||||
|
auto_now_add=True, null=True, verbose_name='first created at', db_index=True),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='photo',
|
model_name='photo',
|
||||||
name='date_modified',
|
name='date_modified',
|
||||||
field=models.DateTimeField(default=datetime.datetime(2016, 10, 12, 20, 24, 50, 509970, tzinfo=utc), verbose_name='latest updated at', auto_now=True),
|
field=models.DateTimeField(default=datetime.datetime(
|
||||||
|
2016, 10, 12, 20, 24, 50, 509970, tzinfo=utc), verbose_name='latest updated at', auto_now=True),
|
||||||
preserve_default=False,
|
preserve_default=False,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -346,7 +346,6 @@ class Photo(models.Model):
|
|||||||
)[0]
|
)[0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
return None
|
return None
|
||||||
return self.get_next_by_created_date(event=self.event)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def previous_photo(self):
|
def previous_photo(self):
|
||||||
@@ -366,4 +365,3 @@ class Photo(models.Model):
|
|||||||
)[0]
|
)[0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
return None
|
return None
|
||||||
return self.get_previous_by_created_date(event=self.event)
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
from django.contrib.sitemaps import Sitemap
|
from django.contrib.sitemaps import Sitemap
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from .models import Event, Photo
|
from .models import Event
|
||||||
|
from .models import Photo
|
||||||
|
|
||||||
|
|
||||||
class EventSitemap(Sitemap):
|
class EventSitemap(Sitemap):
|
||||||
changefreq = "never"
|
changefreq = "never"
|
||||||
priority = 0.6
|
|
||||||
protocol = 'https'
|
protocol = 'https'
|
||||||
|
|
||||||
def items(self):
|
def items(self):
|
||||||
@@ -13,9 +13,8 @@ class EventSitemap(Sitemap):
|
|||||||
|
|
||||||
def priority(self, event):
|
def priority(self, event):
|
||||||
delta = timezone.now() - event.start
|
delta = timezone.now() - event.start
|
||||||
delta = abs(delta.days / 300.0 )
|
delta = abs(delta.days / 300.0)
|
||||||
return max(1 - delta, 0.1)
|
return max(1 - delta, 0.1)
|
||||||
|
|
||||||
def lastmod(self, event):
|
def lastmod(self, event):
|
||||||
return event.date_modified
|
return event.date_modified
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
<p class="warning">
|
<p class="warning">
|
||||||
<strong>Achtung! Das ist eine Veranstaltungsreihe!</strong> Diese kann man im Moment nur im Admin-Interface vernünfig bearbeiten.<br />
|
<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.
|
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>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p class="buttonbar">
|
<p class="buttonbar">
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
{%trans "Upload" %}</a>
|
{%trans "Upload" %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
</div></div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<form method="post" enctype="multipart/form-data">
|
<form method="post" enctype="multipart/form-data">
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ from django.db.models import Q
|
|||||||
from django.contrib.auth.decorators import permission_required
|
from django.contrib.auth.decorators import permission_required
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from extra_views import ModelFormSetView, InlineFormSetView
|
from extra_views import InlineFormSetView
|
||||||
|
from extra_views import ModelFormSetView
|
||||||
from django.http import HttpResponse, Http404
|
from django.http import HttpResponse, Http404
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,9 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from os import path
|
from os import path
|
||||||
|
|
||||||
gettext = lambda s: s
|
|
||||||
|
def gettext(s): return s
|
||||||
|
|
||||||
|
|
||||||
ADMINS = (('Max Mustermann', 'email@example.com'),)
|
ADMINS = (('Max Mustermann', 'email@example.com'),)
|
||||||
ALLOWED_HOSTS = ['.kasu.at']
|
ALLOWED_HOSTS = ['.kasu.at']
|
||||||
@@ -39,6 +41,7 @@ PREREQ_APPS = [
|
|||||||
'django.contrib.sitemaps',
|
'django.contrib.sitemaps',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
'django_comments',
|
'django_comments',
|
||||||
|
'captcha',
|
||||||
'ckeditor',
|
'ckeditor',
|
||||||
'ckeditor_uploader',
|
'ckeditor_uploader',
|
||||||
'easy_thumbnails',
|
'easy_thumbnails',
|
||||||
@@ -95,7 +98,7 @@ TEMPLATES = [
|
|||||||
'django.contrib.messages.context_processors.messages',
|
'django.contrib.messages.context_processors.messages',
|
||||||
'django.contrib.messages.context_processors.messages',
|
'django.contrib.messages.context_processors.messages',
|
||||||
'events.context_processors.upcoming_events',
|
'events.context_processors.upcoming_events',
|
||||||
'social_django.context_processors.backends',
|
'social_django.context_processors.backends',
|
||||||
'social_django.context_processors.login_redirect'
|
'social_django.context_processors.login_redirect'
|
||||||
],
|
],
|
||||||
'loaders': [
|
'loaders': [
|
||||||
@@ -108,16 +111,6 @@ TEMPLATES = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
#Settings for Security Middleware
|
|
||||||
CSP_DEFAULT_SRC = ("'self'",)
|
|
||||||
CSP_IMG_SRC = ("'self'", "'unsafe-eval'")
|
|
||||||
CSP_SCRIPT_SRC = ("'self'", "'unsafe-inline'", "'unsafe-eval'")
|
|
||||||
CSP_STYLE_SRC = ("'self'", "'unsafe-inline'")
|
|
||||||
SECURE_BROWSER_XSS_FILTER = True
|
|
||||||
SECURE_CONTENT_TYPE_NOSNIFF = True
|
|
||||||
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
|
|
||||||
SECURE_HSTS_SECONDS = 31536000
|
|
||||||
SECURE_SSL_REDIRECT = True
|
|
||||||
SESSION_COOKIE_DOMAIN = 'kasu.at' # Die ganze Domain Kasu
|
SESSION_COOKIE_DOMAIN = 'kasu.at' # Die ganze Domain Kasu
|
||||||
SESSION_COOKIE_AGE = 15768000 # Session dauer: 4 Wochen
|
SESSION_COOKIE_AGE = 15768000 # Session dauer: 4 Wochen
|
||||||
SESSION_COOKIE_SECURE = True
|
SESSION_COOKIE_SECURE = True
|
||||||
@@ -169,21 +162,21 @@ CKEDITOR_CONFIGS = {'default': {
|
|||||||
'width': '100%',
|
'width': '100%',
|
||||||
'extraPlugins': 'divarea',
|
'extraPlugins': 'divarea',
|
||||||
'toolbarGroups': """[
|
'toolbarGroups': """[
|
||||||
{ name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
|
{ name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
|
||||||
{ name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ] },
|
{ name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ] },
|
||||||
{ name: 'links' },
|
{ name: 'links' },
|
||||||
{ name: 'insert' },
|
{ name: 'insert' },
|
||||||
{ name: 'forms' },
|
{ name: 'forms' },
|
||||||
{ name: 'tools' },
|
{ name: 'tools' },
|
||||||
{ name: 'document', groups: [ 'mode', 'document', 'doctools' ] },
|
{ name: 'document', groups: [ 'mode', 'document', 'doctools' ] },
|
||||||
{ name: 'others' },
|
{ name: 'others' },
|
||||||
'/',
|
'/',
|
||||||
{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
|
{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
|
||||||
{ name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] },
|
{ name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] },
|
||||||
{ name: 'styles' },
|
{ name: 'styles' },
|
||||||
{ name: 'colors' },
|
{ name: 'colors' },
|
||||||
{ name: 'about' }
|
{ name: 'about' }
|
||||||
];"""
|
];"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,11 +184,9 @@ CKEDITOR_CONFIGS = {'default': {
|
|||||||
FACEBOOK_APP_ID = ''
|
FACEBOOK_APP_ID = ''
|
||||||
FACEBOOK_ACCESS_TOKEN = ''
|
FACEBOOK_ACCESS_TOKEN = ''
|
||||||
|
|
||||||
# Settings for the redactor WYSIWYG Editor
|
|
||||||
REDACTOR_OPTIONS = {'lang': 'de', 'linebreaks': True}
|
|
||||||
REDACTOR_UPLOAD = 'uploads/'
|
|
||||||
|
|
||||||
# crendetials for reCaptcha (set in local_settings)
|
# crendetials for reCaptcha (set in local_settings)
|
||||||
|
NOCAPTCHA = True
|
||||||
|
RECAPTCHA_USE_SSL = True
|
||||||
RECAPTCHA_PUBLIC_KEY = ''
|
RECAPTCHA_PUBLIC_KEY = ''
|
||||||
RECAPTCHA_PRIVATE_KEY = ''
|
RECAPTCHA_PRIVATE_KEY = ''
|
||||||
RECAPTCHA_THEME = 'red'
|
RECAPTCHA_THEME = 'red'
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
var idSite = 1;
|
/* Piwik */
|
||||||
var piwikTrackingApiUrl = 'https://kasu.at/piwik/piwik.php';
|
var _paq = _paq || [];
|
||||||
|
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
|
||||||
var _paq = _paq || [];
|
_paq.push(['trackPageView']);
|
||||||
_paq.push(['setTrackerUrl', piwikTrackingApiUrl]);
|
_paq.push(['enableLinkTracking']);
|
||||||
_paq.push(['setSiteId', idSite]);
|
(function() {
|
||||||
_paq.push(['trackPageView']);
|
var u="//kasu.at/piwik/";
|
||||||
_paq.push(['enableLinkTracking']);
|
_paq.push(['setTrackerUrl', u+'piwik.php']);
|
||||||
|
_paq.push(['setSiteId', '1']);
|
||||||
|
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
||||||
|
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
/* End Piwik Code */
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
{% block title %}404 - Seite nicht gefunden{% endblock %}
|
{% block title %}404 - Seite nicht gefunden{% endblock %}
|
||||||
|
|
||||||
{% block teaser %}
|
{% block teaser %}
|
||||||
<h1">404 - Nōten!</h1>
|
<h1>404 - Nōten!</h1>
|
||||||
<div id="teaser_text"><p>{% trans 'The page your requested does not exist on this server.' %}</p></div>
|
<div id="teaser_text"><p>{% trans 'The page your requested does not exist on this server.' %}</p></div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@@ -35,21 +35,7 @@
|
|||||||
<meta property="og:image" content="http://www.kasu.at/static/img/logo.png"/>
|
<meta property="og:image" content="http://www.kasu.at/static/img/logo.png"/>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block extra_head %}{% endblock %}
|
{% block extra_head %}{% endblock %}
|
||||||
<!-- Piwik -->
|
<script src="{{ STATIC_URL }}js/piwik.js"></script>
|
||||||
<script type="text/javascript">
|
|
||||||
var _paq = _paq || [];
|
|
||||||
// tracker methods like "setCustomDimension" should be called before "trackPageView"
|
|
||||||
_paq.push(['trackPageView']);
|
|
||||||
_paq.push(['enableLinkTracking']);
|
|
||||||
(function() {
|
|
||||||
var u="/piwik/";
|
|
||||||
_paq.push(['setTrackerUrl', u+'piwik.php']);
|
|
||||||
_paq.push(['setSiteId', '1']);
|
|
||||||
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
|
||||||
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
<!-- End Piwik Code -->
|
|
||||||
</head>
|
</head>
|
||||||
<body id="body" {% block itemscope %}{% endblock %}>
|
<body id="body" {% block itemscope %}{% endblock %}>
|
||||||
<header id="siteheader">
|
<header id="siteheader">
|
||||||
@@ -63,7 +49,10 @@
|
|||||||
class="{%if item.active %}active{% endif %}">{{item.menu_name}}</a>
|
class="{%if item.active %}active{% endif %}">{{item.menu_name}}</a>
|
||||||
{% if item.subpages.all %}
|
{% if item.subpages.all %}
|
||||||
<ul class="main_dropdown">
|
<ul class="main_dropdown">
|
||||||
{% for subpage in item.subpages.all %}<li><a href="{{subpage.get_absolute_url}}" {% ifequal subpage current_page %}class="active"{% endifequal %}>{{subpage.menu_name}}</a></li>{% endfor %}
|
{% for subpage in item.subpages.all %}<li><a
|
||||||
|
href="{{subpage.get_absolute_url}}"
|
||||||
|
{% ifequal subpage current_page %}class="active"{% endifequal %}>{{subpage.menu_name}}</a></li>
|
||||||
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
{% for hidden in form.hidden_fields %}{{ hidden }}{% endfor %}
|
{% for hidden in form.hidden_fields %}{{ hidden }}{% endfor %}
|
||||||
{% for field in form.visible_fields %}
|
{% for field in form.visible_fields %}
|
||||||
<div>
|
<div>
|
||||||
<label {% if field.html_name != 'recaptcha' %}for="id_{{ field.html_name}}"{% endif %} class="field_name {{ field.css_classes }}">{{ field.label}}</label>
|
<label {% if field.html_name != 'recaptcha' %} for="id_{{ field.html_name}}" {% endif %}
|
||||||
|
class="field_name {{ field.css_classes }}">{{ field.label}}</label>
|
||||||
{{ field }}
|
{{ field }}
|
||||||
{% if field.help_text and not field.field.widget.input_type %}
|
{% if field.help_text and not field.field.widget.input_type %}
|
||||||
{{field.help_text}}
|
{{field.help_text}}
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<nav class="grid_12 pagination">
|
<nav class="grid_12 pagination">
|
||||||
<a {% if page_obj.has_previous %}class="previous" href="?page={{ page_obj.previous_page_number }}"{% else %}class="previous disabled" {% endif %}>
|
<a {% if page_obj.has_previous %}
|
||||||
<span class="fa fa-arrow-left"></span>{% trans "Previous" %}
|
class="previous" href="?page={{ page_obj.previous_page_number }}"
|
||||||
|
{% else %}
|
||||||
|
class="previous disabled"
|
||||||
|
{% endif %}>
|
||||||
|
<span class="fa fa-arrow-left"></span>{% trans "Previous" %}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
{% for page in paginator.page_range %}
|
{% for page in paginator.page_range %}
|
||||||
<a {% ifequal page_obj.number page %}class="active"{% else %}href="?page={{page}}"{% endifequal %}>{{page}}</a>
|
<a {% ifequal page_obj.number page %}class="active"{% else %}href="?page={{page}}"{% endifequal %}>{{page}}</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<a {% if page_obj.has_next %}class="next" href="?page={{ page_obj.next_page_number }}"{% else %}class="next disabled"{% endif %}>
|
<a {% if page_obj.has_next %}
|
||||||
{% trans "Next" %} <span class="fa fa-arrow-right"></span>
|
class="next" href="?page={{ page_obj.next_page_number }}"
|
||||||
|
{% else %}
|
||||||
|
class="next disabled"
|
||||||
|
{% endif %}>
|
||||||
|
{% trans "Next" %} <span class="fa fa-arrow-right"></span>
|
||||||
</a>
|
</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
@@ -1,8 +1,3 @@
|
|||||||
"""
|
|
||||||
Created on 10.06.2012
|
|
||||||
|
|
||||||
@author: christian
|
|
||||||
"""
|
|
||||||
import copy
|
import copy
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
@@ -23,19 +23,21 @@ sitemaps = {
|
|||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^$', StartPage.as_view()),
|
url(r'^$', StartPage.as_view()),
|
||||||
url(r'^404/$', TemplateView.as_view(template_name='404.html')),
|
url(r'^404/$', TemplateView.as_view(template_name='404.html')),
|
||||||
url(r'^add_page/(?P<path>[\+\.\-\d\w\/]+)/$', PageAddForm.as_view(), name='add-page'),
|
url(r'^add_page/(?P<path>[\+\.\-\d\w\/]+)/$',
|
||||||
|
PageAddForm.as_view(), name='add-page'),
|
||||||
url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
||||||
url(r'^admin/', include(admin.site.urls)),
|
url(r'^admin/', include(admin.site.urls)),
|
||||||
url(r'^ckeditor/', include('ckeditor_uploader.urls')),
|
url(r'^ckeditor/', include('ckeditor_uploader.urls')),
|
||||||
url(r'^comments/', include('django_comments.urls')),
|
url(r'^comments/', include('django_comments.urls')),
|
||||||
url(r'^content/', include('content.urls')),
|
url(r'^edit_page/(?P<path>[\+\.\-\d\w\/]+)/$',
|
||||||
url(r'^edit_page/(?P<path>[\+\.\-\d\w\/]+)/$', PageEditForm.as_view(), name='edit-page'),
|
PageEditForm.as_view(), name='edit-page'),
|
||||||
url(r'^events/', include('events.urls')),
|
url(r'^events/', include('events.urls')),
|
||||||
url(r'^events.ics$', EventListIcal.as_view(), name='events-ical'),
|
url(r'^events.ics$', EventListIcal.as_view(), name='events-ical'),
|
||||||
url(r'^feeds/latest/$', LatestNews(), name='feed-latest-news'),
|
url(r'^feeds/latest/$', LatestNews(), name='feed-latest-news'),
|
||||||
url(r'^feeds/comments/$', LatestComments(), name='feed-latest-comments'),
|
url(r'^feeds/comments/$', LatestComments(), name='feed-latest-comments'),
|
||||||
url(r'^gallery/', include('events.gallery_urls')),
|
url(r'^gallery/', include('events.gallery_urls')),
|
||||||
url(r'^google25dabc1a49a9ef03.html$', TemplateView.as_view(template_name='google25dabc1a49a9ef03.html')),
|
url(r'^google25dabc1a49a9ef03.html$', TemplateView.as_view(
|
||||||
|
template_name='google25dabc1a49a9ef03.html')),
|
||||||
url(r'^i18n/', include('django.conf.urls.i18n'), name='start-page'),
|
url(r'^i18n/', include('django.conf.urls.i18n'), name='start-page'),
|
||||||
url(r'^index.html$', StartPage.as_view()),
|
url(r'^index.html$', StartPage.as_view()),
|
||||||
url(r'^manifest.json$', TemplateView.as_view(template_name='manifest.json')),
|
url(r'^manifest.json$', TemplateView.as_view(template_name='manifest.json')),
|
||||||
@@ -43,23 +45,28 @@ urlpatterns = [
|
|||||||
url(r'^news/', include('content.news_urls')),
|
url(r'^news/', include('content.news_urls')),
|
||||||
url(r'^ranking/', include('mahjong_ranking.urls')),
|
url(r'^ranking/', include('mahjong_ranking.urls')),
|
||||||
url(r'^ranking/', include('maistar_ranking.urls')),
|
url(r'^ranking/', include('maistar_ranking.urls')),
|
||||||
url(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap'),
|
url(r'^sitemap\.xml$', sitemap, {
|
||||||
|
'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap'),
|
||||||
url(r'^robots.txt$', TemplateView.as_view(template_name='robots.txt')),
|
url(r'^robots.txt$', TemplateView.as_view(template_name='robots.txt')),
|
||||||
url(r'^users/$', MembershipDetail.as_view(), name='membership-details'),
|
url(r'^users/$', MembershipDetail.as_view(), name='membership-details'),
|
||||||
url(r'^users/(?P<username>[\-\.\d\w]+)/$', MembershipDetail.as_view(), name='membership-details'),
|
url(r'^users/(?P<username>[\-\.\d\w]+)/$',
|
||||||
url(r'^(?P<path>[\-\d\w\/]+)\.html$', PageHtml.as_view(), name='view-page'),
|
MembershipDetail.as_view(), name='membership-details'),
|
||||||
|
url(r'^(?P<path>[\-\d\w\/]+)\.html$',
|
||||||
|
PageHtml.as_view(), name='view-page'),
|
||||||
url(r'^(?P<path>[\-\d\w\/]+)\.pdf$', PagePdf.as_view()),
|
url(r'^(?P<path>[\-\d\w\/]+)\.pdf$', PagePdf.as_view()),
|
||||||
url('', include('social_django.urls', namespace='social'))
|
url('', include('social_django.urls', namespace='social'))
|
||||||
]
|
]
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
from django.conf.urls.static import static
|
from django.conf.urls.static import static
|
||||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
urlpatterns += static(settings.MEDIA_URL,
|
||||||
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
document_root=settings.MEDIA_ROOT)
|
||||||
|
urlpatterns += static(settings.STATIC_URL,
|
||||||
|
document_root=settings.STATIC_ROOT)
|
||||||
|
|
||||||
if 'rosetta' in settings.INSTALLED_APPS:
|
if 'rosetta' in settings.INSTALLED_APPS:
|
||||||
urlpatterns += url(r'^rosetta/', include('rosetta.urls'))
|
urlpatterns += url(r'^rosetta/', include('rosetta.urls'))
|
||||||
|
|
||||||
if 'debug_toolbar' in settings.INSTALLED_APPS:
|
if 'debug_toolbar' in settings.INSTALLED_APPS:
|
||||||
import debug_toolbar
|
import debug_toolbar
|
||||||
urlpatterns.append(url(r'^__debug__/', include(debug_toolbar.urls)))
|
urlpatterns.append(url(r'^__debug__/', include(debug_toolbar.urls)))
|
||||||
|
|||||||
@@ -326,7 +326,7 @@ class MassMailer(object):
|
|||||||
if isinstance(recipient, USER_MODEL):
|
if isinstance(recipient, USER_MODEL):
|
||||||
self.recipients.add(recipient)
|
self.recipients.add(recipient)
|
||||||
else:
|
else:
|
||||||
self.log.warn('%s is not a User Object!', recipient)
|
self.log.warning('%s is not a User Object!', recipient)
|
||||||
|
|
||||||
def add_recipients(self, user_list):
|
def add_recipients(self, user_list):
|
||||||
for user in user_list:
|
for user in user_list:
|
||||||
@@ -334,7 +334,7 @@ class MassMailer(object):
|
|||||||
self.log.debug('Adding %s as Recipient' % user)
|
self.log.debug('Adding %s as Recipient' % user)
|
||||||
self.recipients.add(user)
|
self.recipients.add(user)
|
||||||
else:
|
else:
|
||||||
self.log.warn('%s is not a User Object!', user)
|
self.log.warning('%s is not a User Object!', user)
|
||||||
|
|
||||||
def process_mails(self):
|
def process_mails(self):
|
||||||
mail_context = Context(self.context)
|
mail_context = Context(self.context)
|
||||||
@@ -381,7 +381,7 @@ class MassMailer(object):
|
|||||||
try:
|
try:
|
||||||
mail.send()
|
mail.send()
|
||||||
except:
|
except:
|
||||||
self.log.warn("Mail failed for: %s", mail.to)
|
self.log.warning("Mail failed for: %s", mail.to)
|
||||||
else:
|
else:
|
||||||
self.log.info("Mail sent successful to: %s" % mail.to)
|
self.log.info("Mail sent successful to: %s" % mail.to)
|
||||||
self.close_smtp_connection()
|
self.close_smtp_connection()
|
||||||
|
|||||||
@@ -2,15 +2,16 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
src_path = '/var/www/virtual/kasu.at/'
|
src_path = '/home/kasu/src'
|
||||||
virtpy_path = '/var/www/virtual/kasu.at/virtenv/lib/python2.6/site-packages'
|
virtpy_path = '/home/kasu/virtualenv/lib/python3.4/site-packages'
|
||||||
|
|
||||||
if virtpy_path not in sys.path:
|
if virtpy_path not in sys.path:
|
||||||
sys.path.insert(1, virtpy_path)
|
sys.path.insert(1, virtpy_path)
|
||||||
if src_path not in sys.path:
|
if src_path not in sys.path:
|
||||||
sys.path.append(src_path)
|
sys.path.append(src_path)
|
||||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'kasu.settings.production'
|
|
||||||
|
|
||||||
import django.core.handlers.wsgi
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
application = django.core.handlers.wsgi.WSGIHandler()
|
os.environ['DJANGO_SETTINGS_MODULE'] = 'kasu.settings'
|
||||||
|
|
||||||
|
application = get_wsgi_application()
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ logger = logging.getLogger('kasu.mahjong_ranking')
|
|||||||
|
|
||||||
|
|
||||||
def set_dirty(event=None, season=None, user=None, hanchan_date=None):
|
def set_dirty(event=None, season=None, user=None, hanchan_date=None):
|
||||||
|
key_to_add = None
|
||||||
|
queue_name = None
|
||||||
|
|
||||||
if season and user:
|
if season and user:
|
||||||
key_to_add = (season, user)
|
key_to_add = (season, user)
|
||||||
queue_name = 'ladder_ranking_queue'
|
queue_name = 'ladder_ranking_queue'
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ def recalculate(modeladmin, request, queryset):
|
|||||||
for ladder_ranking in queryset:
|
for ladder_ranking in queryset:
|
||||||
set_dirty(user=ladder_ranking.user_id,
|
set_dirty(user=ladder_ranking.user_id,
|
||||||
season=ladder_ranking.season)
|
season=ladder_ranking.season)
|
||||||
|
|
||||||
|
|
||||||
recalculate.short_description = _("Recalculate")
|
recalculate.short_description = _("Recalculate")
|
||||||
|
|
||||||
|
|
||||||
@@ -33,6 +35,8 @@ def confirm(modeladmin, request, queryset):
|
|||||||
for hanchan in queryset:
|
for hanchan in queryset:
|
||||||
hanchan.confirmed = True
|
hanchan.confirmed = True
|
||||||
hanchan.save()
|
hanchan.save()
|
||||||
|
|
||||||
|
|
||||||
confirm.short_description = _("Confirm")
|
confirm.short_description = _("Confirm")
|
||||||
|
|
||||||
|
|
||||||
@@ -40,6 +44,8 @@ def unconfirm(modeladmin, request, queryset):
|
|||||||
for hanchan in queryset:
|
for hanchan in queryset:
|
||||||
hanchan.confirmed = False
|
hanchan.confirmed = False
|
||||||
hanchan.save()
|
hanchan.save()
|
||||||
|
|
||||||
|
|
||||||
unconfirm.short_description = _('Set unconfirmed')
|
unconfirm.short_description = _('Set unconfirmed')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
10320
src/mahjong_ranking/fixtures/test_event_rankings.json
Normal file
10320
src/mahjong_ranking/fixtures/test_event_rankings.json
Normal file
File diff suppressed because it is too large
Load Diff
19098
src/mahjong_ranking/fixtures/test_hanchans.json
Normal file
19098
src/mahjong_ranking/fixtures/test_hanchans.json
Normal file
File diff suppressed because it is too large
Load Diff
1118
src/mahjong_ranking/fixtures/test_kyu_dan_rankings.json
Normal file
1118
src/mahjong_ranking/fixtures/test_kyu_dan_rankings.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -6,11 +6,9 @@ Created on 04.10.2011
|
|||||||
@author: christian
|
@author: christian
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
import django.forms
|
from django import forms
|
||||||
from django.utils import timezone
|
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from utils.html5 import forms
|
|
||||||
from . import models
|
from . import models
|
||||||
|
|
||||||
USER_MODEL = get_user_model()
|
USER_MODEL = get_user_model()
|
||||||
@@ -19,7 +17,7 @@ USER_MODEL = get_user_model()
|
|||||||
class HanchanForm(forms.ModelForm):
|
class HanchanForm(forms.ModelForm):
|
||||||
error_css_class = 'error'
|
error_css_class = 'error'
|
||||||
required_css_class = 'required'
|
required_css_class = 'required'
|
||||||
start = forms.DateTimeField(label=_('start'), required=True)
|
start = forms.SplitDateTimeField(label=_('start'), required=True)
|
||||||
|
|
||||||
class Meta(object):
|
class Meta(object):
|
||||||
model = models.Hanchan
|
model = models.Hanchan
|
||||||
@@ -29,8 +27,9 @@ class HanchanForm(forms.ModelForm):
|
|||||||
'player3', 'player3_input_score',
|
'player3', 'player3_input_score',
|
||||||
'player4', 'player4_input_score',
|
'player4', 'player4_input_score',
|
||||||
'comment')
|
'comment')
|
||||||
widgets = {'event': forms.HiddenInput(),
|
widgets = {
|
||||||
'comment': forms.widgets.Textarea(attrs={'rows': 4, 'cols': 40})
|
'event': forms.HiddenInput(),
|
||||||
|
'comment': forms.widgets.Textarea(attrs={'rows': 4, 'cols': 40})
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@@ -45,7 +44,6 @@ class HanchanForm(forms.ModelForm):
|
|||||||
self.fields[player].queryset = player_queryset
|
self.fields[player].queryset = player_queryset
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class HanchanAdminForm(HanchanForm):
|
class HanchanAdminForm(HanchanForm):
|
||||||
|
|
||||||
class Meta(object):
|
class Meta(object):
|
||||||
@@ -53,12 +51,12 @@ class HanchanAdminForm(HanchanForm):
|
|||||||
fields = HanchanForm.Meta.fields + ('confirmed',)
|
fields = HanchanForm.Meta.fields + ('confirmed',)
|
||||||
|
|
||||||
|
|
||||||
class SeasonSelectForm(django.forms.Form):
|
class SeasonSelectForm(forms.Form):
|
||||||
season = django.forms.ChoiceField(label='', choices=('a', 'b', 'c'))
|
season = forms.ChoiceField(label='', choices=('a', 'b', 'c'))
|
||||||
|
|
||||||
def __init__(self, user, *args, **kwargs):
|
def __init__(self, user, *args, **kwargs):
|
||||||
super(SeasonSelectForm, self).__init__(args, kwargs)
|
super(SeasonSelectForm, self).__init__(args, kwargs)
|
||||||
season_list = models.LadderRanking.objects.filter(user=user)
|
season_list = models.LadderRanking.objects.filter(user=user)
|
||||||
season_list = season_list.select_related('user')
|
season_list = season_list.select_related('user')
|
||||||
season_list = season_list.values_list('season__id', 'season__name')
|
season_list = season_list.values_list('season__id', 'season__name')
|
||||||
self.fields['season'] = django.forms.ChoiceField(choices=season_list)
|
self.fields['season'] = forms.ChoiceField(choices=season_list)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: kasu.mahjong_ranking\n"
|
"Project-Id-Version: kasu.mahjong_ranking\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2016-09-28 00:25+0200\n"
|
"POT-Creation-Date: 2017-05-10 23:16+0200\n"
|
||||||
"PO-Revision-Date: 2016-09-28 00:24+0200\n"
|
"PO-Revision-Date: 2016-09-28 00:24+0200\n"
|
||||||
"Last-Translator: Christian Berg <xeniac.at@gmail.com>\n"
|
"Last-Translator: Christian Berg <xeniac.at@gmail.com>\n"
|
||||||
"Language-Team: Kasu <verein@kasu.at>\n"
|
"Language-Team: Kasu <verein@kasu.at>\n"
|
||||||
@@ -19,376 +19,376 @@ msgstr ""
|
|||||||
"X-Generator: Poedit 1.8.9\n"
|
"X-Generator: Poedit 1.8.9\n"
|
||||||
"X-Translated-Using: django-rosetta 0.7.6\n"
|
"X-Translated-Using: django-rosetta 0.7.6\n"
|
||||||
|
|
||||||
#: src/mahjong_ranking/admin.py:29
|
#: mahjong_ranking/admin.py:29
|
||||||
msgid "Recalculate"
|
msgid "Recalculate"
|
||||||
msgstr "Neuberechnen"
|
msgstr "Neuberechnen"
|
||||||
|
|
||||||
#: src/mahjong_ranking/admin.py:36
|
#: mahjong_ranking/admin.py:36
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Bestätigen"
|
msgstr "Bestätigen"
|
||||||
|
|
||||||
#: src/mahjong_ranking/admin.py:43
|
#: mahjong_ranking/admin.py:43
|
||||||
msgid "Set unconfirmed"
|
msgid "Set unconfirmed"
|
||||||
msgstr "Als unbestätigt markieren"
|
msgstr "Als unbestätigt markieren"
|
||||||
|
|
||||||
#: src/mahjong_ranking/forms.py:22
|
#: mahjong_ranking/forms.py:22
|
||||||
msgid "start"
|
msgid "start"
|
||||||
msgstr "Beginn"
|
msgstr "Beginn"
|
||||||
|
|
||||||
#: src/mahjong_ranking/models.py:91
|
#: mahjong_ranking/models.py:90
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:14
|
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:14
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:13
|
#: mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:13
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:15
|
#: mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:15
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:15
|
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:15
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:10
|
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:10
|
||||||
msgid "Start"
|
msgid "Start"
|
||||||
msgstr "Beginn"
|
msgstr "Beginn"
|
||||||
|
|
||||||
#: src/mahjong_ranking/models.py:92
|
#: mahjong_ranking/models.py:91
|
||||||
msgid "This is crucial to get the right Hanchans that scores"
|
msgid "This is crucial to get the right Hanchans that scores"
|
||||||
msgstr "Wichtig damit die richtigen Hanchans in die Wertung kommen."
|
msgstr "Wichtig damit die richtigen Hanchans in die Wertung kommen."
|
||||||
|
|
||||||
#: src/mahjong_ranking/models.py:97
|
#: mahjong_ranking/models.py:98
|
||||||
msgid "Player 1"
|
msgid "Player 1"
|
||||||
msgstr "Spieler 1"
|
msgstr "Spieler 1"
|
||||||
|
|
||||||
#: src/mahjong_ranking/models.py:98 src/mahjong_ranking/models.py:100
|
#: mahjong_ranking/models.py:99 mahjong_ranking/models.py:101
|
||||||
#: src/mahjong_ranking/models.py:115 src/mahjong_ranking/models.py:117
|
#: mahjong_ranking/models.py:118 mahjong_ranking/models.py:120
|
||||||
#: src/mahjong_ranking/models.py:132 src/mahjong_ranking/models.py:134
|
#: mahjong_ranking/models.py:137 mahjong_ranking/models.py:139
|
||||||
#: src/mahjong_ranking/models.py:149 src/mahjong_ranking/models.py:151
|
#: mahjong_ranking/models.py:156 mahjong_ranking/models.py:158
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:19
|
#: mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:19
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:21
|
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:21
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:16
|
#: mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:16
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:43
|
#: mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:19
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:31
|
#: mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:35
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:32
|
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:32
|
||||||
msgid "Score"
|
msgid "Score"
|
||||||
msgstr "Punkte"
|
msgstr "Punkte"
|
||||||
|
|
||||||
#: src/mahjong_ranking/models.py:110 src/mahjong_ranking/models.py:127
|
#: mahjong_ranking/models.py:111 mahjong_ranking/models.py:130
|
||||||
#: src/mahjong_ranking/models.py:144 src/mahjong_ranking/models.py:161
|
#: mahjong_ranking/models.py:149 mahjong_ranking/models.py:168
|
||||||
#: src/mahjong_ranking/models.py:163
|
#: mahjong_ranking/models.py:170
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:44
|
#: mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:20
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:18
|
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:18
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:17
|
#: mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:17
|
||||||
msgid "Comment"
|
msgid "Comment"
|
||||||
msgstr "Kommentar"
|
msgstr "Kommentar"
|
||||||
|
|
||||||
#: src/mahjong_ranking/models.py:114
|
#: mahjong_ranking/models.py:117
|
||||||
msgid "Player 2"
|
msgid "Player 2"
|
||||||
msgstr "Spieler 2"
|
msgstr "Spieler 2"
|
||||||
|
|
||||||
#: src/mahjong_ranking/models.py:131
|
#: mahjong_ranking/models.py:136
|
||||||
msgid "Player 3"
|
msgid "Player 3"
|
||||||
msgstr "Spieler 3"
|
msgstr "Spieler 3"
|
||||||
|
|
||||||
#: src/mahjong_ranking/models.py:148
|
#: mahjong_ranking/models.py:155
|
||||||
msgid "Player 4"
|
msgid "Player 4"
|
||||||
msgstr "Spieler 4"
|
msgstr "Spieler 4"
|
||||||
|
|
||||||
#: src/mahjong_ranking/models.py:164
|
#: mahjong_ranking/models.py:171
|
||||||
msgid "Has been Confirmed"
|
msgid "Has been Confirmed"
|
||||||
msgstr "Wurde bestätigt"
|
msgstr "Wurde bestätigt"
|
||||||
|
|
||||||
#: src/mahjong_ranking/models.py:166
|
#: mahjong_ranking/models.py:173
|
||||||
msgid "Only valid and confirmed Hanchans will be counted in the rating."
|
msgid "Only valid and confirmed Hanchans will be counted in the rating."
|
||||||
msgstr "Nur gültige und bestätigte Hanchans kommen in die Wertung."
|
msgstr "Nur gültige und bestätigte Hanchans kommen in die Wertung."
|
||||||
|
|
||||||
#: src/mahjong_ranking/models.py:171 src/mahjong_ranking/models.py:547
|
#: mahjong_ranking/models.py:178 mahjong_ranking/models.py:565
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/ladder_redbox.html:29
|
#: mahjong_ranking/templates/mahjong_ranking/ladder_redbox.html:29
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:63
|
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:63
|
||||||
msgid "Season"
|
msgid "Season"
|
||||||
msgstr "Saison"
|
msgstr "Saison"
|
||||||
|
|
||||||
#: src/mahjong_ranking/models.py:176
|
#: mahjong_ranking/models.py:183
|
||||||
msgid "Hanchan"
|
msgid "Hanchan"
|
||||||
msgstr "Hanchan"
|
msgstr "Hanchan"
|
||||||
|
|
||||||
#: src/mahjong_ranking/models.py:177
|
#: mahjong_ranking/models.py:184
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:17
|
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:17
|
||||||
msgid "Hanchans"
|
msgid "Hanchans"
|
||||||
msgstr "Hanchans"
|
msgstr "Hanchans"
|
||||||
|
|
||||||
#: src/mahjong_ranking/models.py:180
|
#: mahjong_ranking/models.py:187
|
||||||
msgid "Hanchan from {0:%Y-%m-%d} at {0:%H:%M} with {1}"
|
msgid "Hanchan from {0:%Y-%m-%d} at {0:%H:%M} with {1}"
|
||||||
msgstr "Hanchan vom {0:%Y-%m-%d} um {0:%H:%M} mit {1}"
|
msgstr "Hanchan vom {0:%Y-%m-%d} um {0:%H:%M} mit {1}"
|
||||||
|
|
||||||
#: src/mahjong_ranking/models.py:207
|
#: mahjong_ranking/models.py:214
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%s can't attend the same game multiple times"
|
msgid "%s can't attend the same game multiple times"
|
||||||
msgstr "%s kann an einem Spiel nicht mehrfach teilnehmen."
|
msgstr "%s kann an einem Spiel nicht mehrfach teilnehmen."
|
||||||
|
|
||||||
#: src/mahjong_ranking/models.py:215
|
#: mahjong_ranking/models.py:222
|
||||||
msgid "Games in the future may not be added, Dr. Brown"
|
msgid "Games in the future may not be added, Dr. Brown"
|
||||||
msgstr "Spiele aus der Zukunft dürfen noch nicht erfasst werden. Dr. Brown."
|
msgstr "Spiele aus der Zukunft dürfen noch nicht erfasst werden. Dr. Brown."
|
||||||
|
|
||||||
#: src/mahjong_ranking/models.py:217
|
#: mahjong_ranking/models.py:224
|
||||||
msgid "Only games during the event are allowed"
|
msgid "Only games during the event are allowed"
|
||||||
msgstr "Nur Spiele während der Veranstaltung zählen."
|
msgstr "Nur Spiele während der Veranstaltung zählen."
|
||||||
|
|
||||||
#: src/mahjong_ranking/models.py:220
|
#: mahjong_ranking/models.py:227
|
||||||
msgid "Gamescore is lower then 100.000 Pt."
|
msgid "Gamescore is lower then 100.000 Pt."
|
||||||
msgstr "Spielstand ist weniger als 100.000 Punkte"
|
msgstr "Spielstand ist weniger als 100.000 Punkte"
|
||||||
|
|
||||||
#: src/mahjong_ranking/models.py:222
|
#: mahjong_ranking/models.py:229
|
||||||
msgid "Gamescore is over 100.000 Pt."
|
msgid "Gamescore is over 100.000 Pt."
|
||||||
msgstr "Spielstand ist über 100.000 Punkte."
|
msgstr "Spielstand ist über 100.000 Punkte."
|
||||||
|
|
||||||
#: src/mahjong_ranking/models.py:344
|
#: mahjong_ranking/models.py:353
|
||||||
msgid "Kyū/Dan Ranking"
|
msgid "Kyū/Dan Ranking"
|
||||||
msgstr "Kyū/Dan Wertung"
|
msgstr "Kyū/Dan Wertung"
|
||||||
|
|
||||||
#: src/mahjong_ranking/models.py:345
|
#: mahjong_ranking/models.py:354
|
||||||
msgid "Kyū/Dan Rankings"
|
msgid "Kyū/Dan Rankings"
|
||||||
msgstr "Kyū/Dan Wertungen"
|
msgstr "Kyū/Dan Wertungen"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:7
|
#: mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:7
|
||||||
msgid "Played Hanchans"
|
msgid "Played Hanchans"
|
||||||
msgstr "Gespielte Hanchans"
|
msgstr "Gespielte Hanchans"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:18
|
#: mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:18
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:15
|
#: mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:15
|
||||||
msgid "Place"
|
msgid "Place"
|
||||||
msgstr "Platz"
|
msgstr "Platz"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:21
|
#: mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:21
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:18
|
#: mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:18
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:17
|
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:17
|
||||||
msgid "Dan Points"
|
msgid "Dan Points"
|
||||||
msgstr "Dan Punkte"
|
msgstr "Dan Punkte"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:23
|
#: mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:23
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:20
|
#: mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:20
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:16
|
#: mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:16
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:18
|
#: mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:18
|
||||||
msgid "Kyu Points"
|
msgid "Kyu Points"
|
||||||
msgstr "Kyu Punkte"
|
msgstr "Kyu Punkte"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:37
|
#: mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:37
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:4
|
#: mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:4
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:33
|
#: mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:33
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:44
|
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:44
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:33
|
#: mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:33
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:41
|
#: mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:41
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:52
|
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:52
|
||||||
msgid "Delete Hanchan"
|
msgid "Delete Hanchan"
|
||||||
msgstr "Hanchan löschen"
|
msgstr "Hanchan löschen"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:43
|
#: mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:43
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:4
|
#: mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:4
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:38
|
#: mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:14
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:47
|
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:47
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:36
|
#: mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:36
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:44
|
#: mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:44
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:55
|
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:55
|
||||||
msgid "Edit Hanchan"
|
msgid "Edit Hanchan"
|
||||||
msgstr "Hanchan bearbeiten"
|
msgstr "Hanchan bearbeiten"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:48
|
#: mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:48
|
||||||
msgid "No Hanchan has been added to this event yet."
|
msgid "No Hanchan has been added to this event yet."
|
||||||
msgstr "Für diese Veranstaltung wurde noch keine Hanchan eingetragen."
|
msgstr "Für diese Veranstaltung wurde noch keine Hanchan eingetragen."
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:54
|
#: mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:54
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:51
|
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:51
|
||||||
msgid "Edit Event"
|
msgid "Edit Event"
|
||||||
msgstr "Veranstaltung bearbeiten"
|
msgstr "Veranstaltung bearbeiten"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:55
|
#: mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:55
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:52
|
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:52
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:4
|
#: mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:4
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:38
|
#: mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:14
|
||||||
msgid "Add Hanchan"
|
msgid "Add Hanchan"
|
||||||
msgstr "Hanchan hinzufügen"
|
msgstr "Hanchan hinzufügen"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:4
|
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:4
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:5
|
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:5
|
||||||
msgid "Tournament Ranking"
|
msgid "Tournament Ranking"
|
||||||
msgstr "Turnierwertung"
|
msgstr "Turnierwertung"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:12
|
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:12
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:26
|
#: mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:30
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:23
|
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:23
|
||||||
msgid "Rank"
|
msgid "Rank"
|
||||||
msgstr "Rang"
|
msgstr "Rang"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:13
|
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:13
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:13
|
#: mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:17
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:24
|
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:24
|
||||||
msgid "Avatar"
|
msgid "Avatar"
|
||||||
msgstr "Avatar"
|
msgstr "Avatar"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:14
|
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:14
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:16
|
#: mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:20
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:25
|
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:25
|
||||||
msgid "Nickname"
|
msgid "Nickname"
|
||||||
msgstr "Spitzname"
|
msgstr "Spitzname"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:15
|
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:15
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:26
|
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:26
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Name"
|
msgstr "Name"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:16
|
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:16
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:27
|
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:27
|
||||||
msgid "Average"
|
msgid "Average"
|
||||||
msgstr "Durchschnitt"
|
msgstr "Durchschnitt"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:20
|
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:20
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:15
|
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:15
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:15
|
#: mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:15
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:16
|
#: mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:16
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:16
|
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:16
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:31
|
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:31
|
||||||
msgid "Placement"
|
msgid "Placement"
|
||||||
msgstr "Platzierung"
|
msgstr "Platzierung"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:22
|
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:22
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:33
|
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:33
|
||||||
msgid "count"
|
msgid "count"
|
||||||
msgstr "Anzahl"
|
msgstr "Anzahl"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:23
|
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:23
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:34
|
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:34
|
||||||
msgid "good"
|
msgid "good"
|
||||||
msgstr "gut"
|
msgstr "gut"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:24
|
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:24
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:35
|
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:35
|
||||||
msgid "won"
|
msgid "won"
|
||||||
msgstr "gewonnen"
|
msgstr "gewonnen"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:39
|
#: mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:39
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Abbruch"
|
msgstr "Abbruch"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:40
|
#: mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:40
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Löschen"
|
msgstr "Löschen"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:42
|
#: mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:18
|
||||||
msgid "Player"
|
msgid "Player"
|
||||||
msgstr "Spieler"
|
msgstr "Spieler"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:82
|
#: mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:58
|
||||||
msgid "Total"
|
msgid "Total"
|
||||||
msgstr "Total"
|
msgstr "Total"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:94
|
#: mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:71
|
||||||
msgid "back"
|
msgid "back"
|
||||||
msgstr "Zurück"
|
msgstr "Zurück"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:95
|
#: mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:72
|
||||||
msgid "save"
|
msgid "save"
|
||||||
msgstr "Speichern"
|
msgstr "Speichern"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:4
|
#: mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:4
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:5
|
#: mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:9
|
||||||
msgid "Player List"
|
msgid "Player List"
|
||||||
msgstr "Spieler Liste"
|
msgstr "Spieler Liste"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:21
|
#: mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:25
|
||||||
msgid "Full Name"
|
msgid "Full Name"
|
||||||
msgstr "Voller Name"
|
msgstr "Voller Name"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:36
|
#: mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:40
|
||||||
msgid "Games Total"
|
msgid "Games Total"
|
||||||
msgstr "Spiele total"
|
msgstr "Spiele total"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/ladder_redbox.html:3
|
#: mahjong_ranking/templates/mahjong_ranking/ladder_redbox.html:3
|
||||||
msgid "Latest Hanchans"
|
msgid "Latest Hanchans"
|
||||||
msgstr "Letzten Hanchans"
|
msgstr "Letzten Hanchans"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/ladder_redbox.html:15
|
#: mahjong_ranking/templates/mahjong_ranking/ladder_redbox.html:15
|
||||||
msgid "Latest Events"
|
msgid "Latest Events"
|
||||||
msgstr "Letzte Veranstaltungen"
|
msgstr "Letzte Veranstaltungen"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/ladder_redbox.html:27
|
#: mahjong_ranking/templates/mahjong_ranking/ladder_redbox.html:27
|
||||||
msgid "Ladder Archive"
|
msgid "Ladder Archive"
|
||||||
msgstr "Ladder Archiv"
|
msgstr "Ladder Archiv"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:4
|
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:4
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:5
|
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:5
|
||||||
msgid "Dan Score for"
|
msgid "Dan Score for"
|
||||||
msgstr "Dan Wertung für"
|
msgstr "Dan Wertung für"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:8
|
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:8
|
||||||
msgid "Hanchans that apply to the Dan Score"
|
msgid "Hanchans that apply to the Dan Score"
|
||||||
msgstr "Hanchans welche zur Dan Wertung zählen"
|
msgstr "Hanchans welche zur Dan Wertung zählen"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:12
|
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:12
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:13
|
#: mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:13
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:13
|
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:13
|
||||||
msgid "Date"
|
msgid "Date"
|
||||||
msgstr "Datum"
|
msgstr "Datum"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:13
|
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:13
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:12
|
#: mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:12
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:14
|
#: mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:14
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:14
|
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:14
|
||||||
msgid "Event"
|
msgid "Event"
|
||||||
msgstr "Veranstaltung"
|
msgstr "Veranstaltung"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:16
|
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:16
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:14
|
#: mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:14
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:17
|
#: mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:17
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:17
|
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:17
|
||||||
msgid "Players"
|
msgid "Players"
|
||||||
msgstr "Spieler"
|
msgstr "Spieler"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:4
|
#: mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:4
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:6
|
#: mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:6
|
||||||
msgid "Unconfirmed Hanchans from"
|
msgid "Unconfirmed Hanchans from"
|
||||||
msgstr "Nicht bestätigte Hanchans von"
|
msgstr "Nicht bestätigte Hanchans von"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:9
|
#: mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:9
|
||||||
msgid "Invalid hanchans with"
|
msgid "Invalid hanchans with"
|
||||||
msgstr "Ungültige Hanchans mit"
|
msgstr "Ungültige Hanchans mit"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:4
|
#: mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:4
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:6
|
#: mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:6
|
||||||
msgid "Kyu Score for"
|
msgid "Kyu Score for"
|
||||||
msgstr "Kyu Wertung für"
|
msgstr "Kyu Wertung für"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:9
|
#: mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:9
|
||||||
msgid "Hanchans that apply to the Kyu Score"
|
msgid "Hanchans that apply to the Kyu Score"
|
||||||
msgstr "Hanchans welche zur Kyu Wertung zählen"
|
msgstr "Hanchans welche zur Kyu Wertung zählen"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:4
|
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:4
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:5
|
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:5
|
||||||
msgid "Ladder Score for"
|
msgid "Ladder Score for"
|
||||||
msgstr "Ladder Wertung für"
|
msgstr "Ladder Wertung für"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:8
|
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:8
|
||||||
msgid "Hanchans that apply to the Ladder Score"
|
msgid "Hanchans that apply to the Ladder Score"
|
||||||
msgstr "Hanchans welche in der Ladder zählen"
|
msgstr "Hanchans welche in der Ladder zählen"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:69
|
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:69
|
||||||
msgid "Go"
|
msgid "Go"
|
||||||
msgstr "Los"
|
msgstr "Los"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:11
|
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:11
|
||||||
msgid "End"
|
msgid "End"
|
||||||
msgstr "Ende"
|
msgstr "Ende"
|
||||||
|
|
||||||
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:12
|
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:12
|
||||||
msgid "Participants"
|
msgid "Participants"
|
||||||
msgstr "Teilnehmer"
|
msgstr "Teilnehmer"
|
||||||
|
|
||||||
#: src/mahjong_ranking/views.py:97
|
#: mahjong_ranking/views.py:97
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%s has been updated successfully."
|
msgid "%s has been updated successfully."
|
||||||
msgstr "%s wurde erfolgreich aktualisiert."
|
msgstr "%s wurde erfolgreich aktualisiert."
|
||||||
|
|
||||||
#: src/mahjong_ranking/views.py:100
|
#: mahjong_ranking/views.py:100
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%s has been added successfully. You can now add a new one."
|
msgid "%s has been added successfully. You can now add a new one."
|
||||||
msgstr "%s wurde erfolgreich hinzugefügt. Du kannst eine neue eintragen."
|
msgstr "%s wurde erfolgreich hinzugefügt. Du kannst eine neue eintragen."
|
||||||
|
|
||||||
#: src/mahjong_ranking/views.py:118 src/mahjong_ranking/views.py:134
|
#: mahjong_ranking/views.py:118 mahjong_ranking/views.py:134
|
||||||
msgid "Event does not exist"
|
msgid "Event does not exist"
|
||||||
msgstr "Veranstaltung existiert nicht"
|
msgstr "Veranstaltung existiert nicht"
|
||||||
|
|
||||||
#: src/mahjong_ranking/views.py:199
|
#: mahjong_ranking/views.py:199
|
||||||
msgid "No user found matching the name {}"
|
msgid "No user found matching the name {}"
|
||||||
msgstr "Kein Benutzer mit dem Namen %s gefunden"
|
msgstr "Kein Benutzer mit dem Namen %s gefunden"
|
||||||
|
|
||||||
|
|||||||
@@ -10,31 +10,32 @@ from mahjong_ranking.models import SeasonRanking
|
|||||||
from openpyxl import Workbook
|
from openpyxl import Workbook
|
||||||
|
|
||||||
|
|
||||||
|
def geneate_seasonexcel(json_data):
|
||||||
|
wb = Workbook()
|
||||||
|
worksheet = wb.active
|
||||||
|
|
||||||
|
worksheet.append([
|
||||||
|
'Rang', 'Spitzname',
|
||||||
|
'⌀ Platz', '⌀ Punkte',
|
||||||
|
'Hanchans', 'Gut', 'Gewonnen'
|
||||||
|
])
|
||||||
|
|
||||||
|
json_data = json_data.values()
|
||||||
|
json_data = sorted(json_data, key=itemgetter('placement'))
|
||||||
|
for row in json_data:
|
||||||
|
worksheet.append([
|
||||||
|
row['placement'], row['username'],
|
||||||
|
row['avg_placement'], row['avg_score'],
|
||||||
|
row['hanchan_count'],
|
||||||
|
row['good_hanchans'], row['won_hanchans']
|
||||||
|
])
|
||||||
|
wb.save("sample.xlsx")
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = "Exports the SeasonRankings"
|
help = "Exports the SeasonRankings"
|
||||||
|
|
||||||
def geneate_seasonexcel(self, json_data):
|
|
||||||
|
|
||||||
wb = Workbook()
|
|
||||||
worksheet = wb.active
|
|
||||||
|
|
||||||
worksheet.append([
|
|
||||||
'Rang', 'Spitzname',
|
|
||||||
'⌀ Platz', '⌀ Punkte',
|
|
||||||
'Hanchans', 'Gut', 'Gewonnen'
|
|
||||||
])
|
|
||||||
|
|
||||||
json_data = json_data.values()
|
|
||||||
json_data = sorted(json_data, key=itemgetter('placement'))
|
|
||||||
for row in json_data:
|
|
||||||
worksheet.append([
|
|
||||||
row['placement'], row['username'],
|
|
||||||
row['avg_placement'], row['avg_score'],
|
|
||||||
row['hanchan_count'],
|
|
||||||
row['good_hanchans'], row['won_hanchans']
|
|
||||||
])
|
|
||||||
wb.save("sample.xlsx")
|
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
season_json = SeasonRanking.objects.json_data()
|
season_json = SeasonRanking.objects.json_data()
|
||||||
self.geneate_seasonexcel(season_json)
|
geneate_seasonexcel(season_json)
|
||||||
|
|||||||
@@ -14,4 +14,3 @@ class Command(BaseCommand):
|
|||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
for ranking in models.KyuDanRanking.objects.all():
|
for ranking in models.KyuDanRanking.objects.all():
|
||||||
ranking.recalculate()
|
ranking.recalculate()
|
||||||
|
|
||||||
|
|||||||
@@ -42,14 +42,22 @@ class HanchanManager(models.Manager):
|
|||||||
season = season or date.today().year
|
season = season or date.today().year
|
||||||
return self.confirmed_hanchans(user=user, season=season)
|
return self.confirmed_hanchans(user=user, season=season)
|
||||||
|
|
||||||
def user_hanchans(self, user, **kwargs):
|
def user_hanchans(self, user, since=None, **kwargs):
|
||||||
|
"""
|
||||||
|
|
||||||
|
:param user: User Object, or an player_id as integer
|
||||||
|
:param since: optional a date value since when you want to hanchans
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
queryset = self.filter(
|
queryset = self.filter(
|
||||||
models.Q(player1=user) | models.Q(player2=user) |
|
models.Q(player1=user) | models.Q(player2=user) |
|
||||||
models.Q(player3=user) | models.Q(player4=user)
|
models.Q(player3=user) | models.Q(player4=user)
|
||||||
)
|
)
|
||||||
queryset = queryset.select_related().order_by('-start')
|
if since:
|
||||||
|
queryset = queryset.filter(start__gte=since)
|
||||||
if kwargs:
|
if kwargs:
|
||||||
queryset = queryset.filter(**kwargs)
|
queryset = queryset.filter(**kwargs)
|
||||||
|
queryset = queryset.select_related().order_by('-start')
|
||||||
for hanchan in queryset:
|
for hanchan in queryset:
|
||||||
hanchan.get_playerdata(user)
|
hanchan.get_playerdata(user)
|
||||||
return queryset
|
return queryset
|
||||||
|
|||||||
@@ -20,9 +20,12 @@ class DenormalizationUpdateMiddleware(object):
|
|||||||
def process_response(self, request, response):
|
def process_response(self, request, response):
|
||||||
# We only do this in POST request, to speedup the responsetime.
|
# We only do this in POST request, to speedup the responsetime.
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
print('event_ranking_queue', cache.get('event_ranking_queue', set()))
|
print('event_ranking_queue', cache.get(
|
||||||
print('kyu_dan_ranking_queue', cache.get('kyu_dan_ranking_queue', set()))
|
'event_ranking_queue', set()))
|
||||||
print('ladder_ranking_queue', cache.get('ladder_ranking_queue', set()))
|
print('kyu_dan_ranking_queue', cache.get(
|
||||||
|
'kyu_dan_ranking_queue', set()))
|
||||||
|
print('ladder_ranking_queue', cache.get(
|
||||||
|
'ladder_ranking_queue', set()))
|
||||||
queue = cache.get('event_ranking_queue', set())
|
queue = cache.get('event_ranking_queue', set())
|
||||||
if len(queue) > 0:
|
if len(queue) > 0:
|
||||||
self.recalculate_event_rankings(queue)
|
self.recalculate_event_rankings(queue)
|
||||||
|
|||||||
@@ -19,21 +19,25 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='hanchan',
|
model_name='hanchan',
|
||||||
name='player1_comment',
|
name='player1_comment',
|
||||||
field=models.CharField(verbose_name='Kommentar', max_length=255, editable=False, blank=True),
|
field=models.CharField(
|
||||||
|
verbose_name='Kommentar', max_length=255, editable=False, blank=True),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='hanchan',
|
model_name='hanchan',
|
||||||
name='player2_comment',
|
name='player2_comment',
|
||||||
field=models.CharField(verbose_name='Kommentar', max_length=255, editable=False, blank=True),
|
field=models.CharField(
|
||||||
|
verbose_name='Kommentar', max_length=255, editable=False, blank=True),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='hanchan',
|
model_name='hanchan',
|
||||||
name='player3_comment',
|
name='player3_comment',
|
||||||
field=models.CharField(verbose_name='Kommentar', max_length=255, editable=False, blank=True),
|
field=models.CharField(
|
||||||
|
verbose_name='Kommentar', max_length=255, editable=False, blank=True),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='hanchan',
|
model_name='hanchan',
|
||||||
name='player4_comment',
|
name='player4_comment',
|
||||||
field=models.CharField(verbose_name='Kommentar', max_length=255, editable=False, blank=True),
|
field=models.CharField(
|
||||||
|
verbose_name='Kommentar', max_length=255, editable=False, blank=True),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -19,21 +19,25 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='hanchan',
|
model_name='hanchan',
|
||||||
name='player1_comment',
|
name='player1_comment',
|
||||||
field=models.CharField(verbose_name='Anmerkung', max_length=255, editable=False, blank=True),
|
field=models.CharField(
|
||||||
|
verbose_name='Anmerkung', max_length=255, editable=False, blank=True),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='hanchan',
|
model_name='hanchan',
|
||||||
name='player2_comment',
|
name='player2_comment',
|
||||||
field=models.CharField(verbose_name='Anmerkung', max_length=255, editable=False, blank=True),
|
field=models.CharField(
|
||||||
|
verbose_name='Anmerkung', max_length=255, editable=False, blank=True),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='hanchan',
|
model_name='hanchan',
|
||||||
name='player3_comment',
|
name='player3_comment',
|
||||||
field=models.CharField(verbose_name='Anmerkung', max_length=255, editable=False, blank=True),
|
field=models.CharField(
|
||||||
|
verbose_name='Anmerkung', max_length=255, editable=False, blank=True),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='hanchan',
|
model_name='hanchan',
|
||||||
name='player4_comment',
|
name='player4_comment',
|
||||||
field=models.CharField(verbose_name='Anmerkung', max_length=255, editable=False, blank=True),
|
field=models.CharField(
|
||||||
|
verbose_name='Anmerkung', max_length=255, editable=False, blank=True),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
# werden dürfen.
|
# werden dürfen.
|
||||||
|
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
from datetime import date
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
@@ -371,7 +370,8 @@ class KyuDanRanking(models.Model):
|
|||||||
self.wins_in_a_row = 0
|
self.wins_in_a_row = 0
|
||||||
|
|
||||||
if self.dan and self.wins_in_a_row >= 3 and self.dan < 9:
|
if self.dan and self.wins_in_a_row >= 3 and self.dan < 9:
|
||||||
logger.info('adding bonuspoints for 3 wins in a row for %s', self.user)
|
logger.info(
|
||||||
|
'adding bonuspoints for 3 wins in a row for %s', self.user)
|
||||||
new_dan_rank = self.dan + 1
|
new_dan_rank = self.dan + 1
|
||||||
new_dan_points = DAN_RANKS_DICT[new_dan_rank] + 1
|
new_dan_points = DAN_RANKS_DICT[new_dan_rank] + 1
|
||||||
bonus_points = new_dan_points - self.dan_points
|
bonus_points = new_dan_points - self.dan_points
|
||||||
@@ -379,7 +379,8 @@ class KyuDanRanking(models.Model):
|
|||||||
logger.debug("Stats for %s:", self.user)
|
logger.debug("Stats for %s:", self.user)
|
||||||
logger.debug("current dan_points: %d", self.dan_points)
|
logger.debug("current dan_points: %d", self.dan_points)
|
||||||
logger.debug("current dan: %d", self.dan)
|
logger.debug("current dan: %d", self.dan)
|
||||||
logger.debug("min required points for the next dan: %d", new_dan_points)
|
logger.debug(
|
||||||
|
"min required points for the next dan: %d", new_dan_points)
|
||||||
logger.debug("bonus points to add: %d", bonus_points)
|
logger.debug("bonus points to add: %d", bonus_points)
|
||||||
|
|
||||||
hanchan.dan_points += bonus_points
|
hanchan.dan_points += bonus_points
|
||||||
@@ -404,7 +405,8 @@ class KyuDanRanking(models.Model):
|
|||||||
).order_by('-start')
|
).order_by('-start')
|
||||||
last_hanchan_this_event = hanchans_this_event[0]
|
last_hanchan_this_event = hanchans_this_event[0]
|
||||||
if hanchan != last_hanchan_this_event:
|
if hanchan != last_hanchan_this_event:
|
||||||
return False # Das braucht nur am Ende eines Turnieres gemacht werden.
|
# Das braucht nur am Ende eines Turnieres gemacht werden.
|
||||||
|
return False
|
||||||
else:
|
else:
|
||||||
event_ranking = EventRanking.objects.get(
|
event_ranking = EventRanking.objects.get(
|
||||||
user=self.user,
|
user=self.user,
|
||||||
@@ -455,14 +457,13 @@ class KyuDanRanking(models.Model):
|
|||||||
valid_hanchans = valid_hanchans.order_by('start')
|
valid_hanchans = valid_hanchans.order_by('start')
|
||||||
if self.legacy_date:
|
if self.legacy_date:
|
||||||
valid_hanchans = valid_hanchans.filter(start__gt=self.legacy_date)
|
valid_hanchans = valid_hanchans.filter(start__gt=self.legacy_date)
|
||||||
""" TODO: Hanchan Punkte nur neu berechnen wenn sie vor hachan_start
|
""" TODO: Hanchan Punkte nur neu berechnen wenn sie vor hachan_start
|
||||||
lag. Es müssen aber alle durch die Schleife rennen, damit die Punkte
|
lag. Es müssen aber alle durch die Schleife rennen, damit die Punkte
|
||||||
richtig gezählt werden."""
|
richtig gezählt werden."""
|
||||||
if hanchan_start:
|
if hanchan_start:
|
||||||
valid_hanchans = valid_hanchans.filter(start__gte=hanchan_start)
|
valid_hanchans = valid_hanchans.filter(start__gte=hanchan_start)
|
||||||
self.hanchan_count += valid_hanchans.count()
|
self.hanchan_count += valid_hanchans.count()
|
||||||
for hanchan in valid_hanchans:
|
for hanchan in valid_hanchans:
|
||||||
logger.debug('Update Kyu/Dan points for Hanchan started on %s', str(hanchan.start))
|
|
||||||
hanchan.get_playerdata(self.user)
|
hanchan.get_playerdata(self.user)
|
||||||
hanchan.bonus_points = 0
|
hanchan.bonus_points = 0
|
||||||
hanchan.player_comment = u""
|
hanchan.player_comment = u""
|
||||||
@@ -476,6 +477,16 @@ class KyuDanRanking(models.Model):
|
|||||||
self.good_hanchans += 1 if hanchan.placement == 2 else 0
|
self.good_hanchans += 1 if hanchan.placement == 2 else 0
|
||||||
hanchan.update_playerdata(self.user)
|
hanchan.update_playerdata(self.user)
|
||||||
hanchan.save(recalculate=False)
|
hanchan.save(recalculate=False)
|
||||||
|
logger.debug(
|
||||||
|
'id: %(id)d, start: %(start)s, placement: %(placement)d, '
|
||||||
|
'score: %(score)d, kyu points: %(kyu_points)d, dan points: '
|
||||||
|
'%(dan_points)d, bonus points: %(bonus_points)d',
|
||||||
|
{'id': hanchan.pk, 'start': hanchan.start,
|
||||||
|
'placement': hanchan.placement, 'score': hanchan.game_score,
|
||||||
|
'kyu_points': hanchan.kyu_points or 0,
|
||||||
|
'dan_points': hanchan.dan_points or 0,
|
||||||
|
'bonus_points': hanchan.bonus_points or 0}
|
||||||
|
)
|
||||||
self.save(force_update=True)
|
self.save(force_update=True)
|
||||||
|
|
||||||
def update_hanchan_points(self, hanchan):
|
def update_hanchan_points(self, hanchan):
|
||||||
@@ -543,7 +554,7 @@ class KyuDanRanking(models.Model):
|
|||||||
if self.dan_points > min_points:
|
if self.dan_points > min_points:
|
||||||
self.dan = dan_rank
|
self.dan = dan_rank
|
||||||
break
|
break
|
||||||
if old_dan == None or self.dan > old_dan:
|
if old_dan is None or self.dan > old_dan:
|
||||||
self.wins_in_a_row = 0
|
self.wins_in_a_row = 0
|
||||||
elif self.kyu_points < 1:
|
elif self.kyu_points < 1:
|
||||||
self.kyu_points = 0
|
self.kyu_points = 0
|
||||||
@@ -608,7 +619,7 @@ def update_ranking(sender, instance, **kwargs):
|
|||||||
for user in (instance.player1, instance.player2, instance.player3, instance.player4):
|
for user in (instance.player1, instance.player2, instance.player3, instance.player4):
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"marking %(user)s's kyu/dan for recalculation since %(start)s",
|
"marking %(user)s's kyu/dan for recalculation since %(start)s",
|
||||||
{'user':user, 'start':str(instance.start.date())}
|
{'user': user, 'start': str(instance.start.date())}
|
||||||
)
|
)
|
||||||
set_dirty(user=user.id, hanchan_date=instance.start.date())
|
set_dirty(user=user.id, hanchan_date=instance.start.date())
|
||||||
if instance.season:
|
if instance.season:
|
||||||
@@ -622,5 +633,6 @@ def update_ranking(sender, instance, **kwargs):
|
|||||||
logger.debug("marking event %s for recalculation.", instance.event)
|
logger.debug("marking event %s for recalculation.", instance.event)
|
||||||
set_dirty(event=instance.event_id, user=user.id)
|
set_dirty(event=instance.event_id, user=user.id)
|
||||||
|
|
||||||
|
|
||||||
models.signals.pre_delete.connect(update_ranking, sender=Hanchan)
|
models.signals.pre_delete.connect(update_ranking, sender=Hanchan)
|
||||||
# models.signals.post_save.connect(update_ranking, sender=Hanchan)
|
# models.signals.post_save.connect(update_ranking, sender=Hanchan)
|
||||||
|
|||||||
@@ -29,7 +29,10 @@
|
|||||||
<label for="season">{% trans 'Season' %}</label>
|
<label for="season">{% trans 'Season' %}</label>
|
||||||
<select id="season" name="season" size="1" onChange="window.location.href = document.season_select.season.options[document.season_select.season.selectedIndex].value;">
|
<select id="season" name="season" size="1" onChange="window.location.href = document.season_select.season.options[document.season_select.season.selectedIndex].value;">
|
||||||
{% for season_link in season_list%}
|
{% for season_link in season_list%}
|
||||||
<option value="{% url 'mahjong-ladder' season_link %}" {% ifequal season season_link %}selected="selected"{% endifequal %}>{{ season_link }}</option>
|
<option
|
||||||
|
value="{% url 'mahjong-ladder' season_link %}"
|
||||||
|
{% ifequal season season_link %} selected="selected"{% endifequal %}>{{ season_link }}
|
||||||
|
</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -63,7 +63,9 @@
|
|||||||
<label for="season">{% trans 'Season' %}:</label>
|
<label for="season">{% trans 'Season' %}:</label>
|
||||||
<select id="season" name="season" size="1">
|
<select id="season" name="season" size="1">
|
||||||
{% for season_link in season_list%}
|
{% for season_link in season_list%}
|
||||||
<option value="{{ season_link }}" {% ifequal season season_link %}selected="selected"{% endifequal %}>{{ season_link }}</option>
|
<option
|
||||||
|
{% ifequal season season_link %} selected="selected"{% endifequal %}
|
||||||
|
value="{{ season_link }}">{{ season_link }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<button type="submit">{% trans 'Go' %}</button>
|
<button type="submit">{% trans 'Go' %}</button>
|
||||||
|
|||||||
@@ -4,14 +4,101 @@ when you run "manage.py test".
|
|||||||
|
|
||||||
Replace this with more appropriate tests for your application.
|
Replace this with more appropriate tests for your application.
|
||||||
"""
|
"""
|
||||||
|
import random
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
from mahjong_ranking.models import Hanchan, KyuDanRanking
|
||||||
|
|
||||||
|
|
||||||
class SimpleTest(TestCase):
|
class KyuDanTest(TestCase):
|
||||||
|
"""
|
||||||
|
Unittest to check if the hanchan calculation works against the rulebook.
|
||||||
|
"""
|
||||||
|
equal_attrs = ('dan', 'dan_points', 'kyu', 'kyu_points', 'good_hanchans',
|
||||||
|
'won_hanchans', 'hanchan_count')
|
||||||
|
|
||||||
def test_basic_addition(self):
|
fixtures = [
|
||||||
|
'test_membership.json',
|
||||||
|
'test_events.json',
|
||||||
|
'test_hanchans.json',
|
||||||
|
'test_event_rankings.json',
|
||||||
|
'test_kyu_dan_rankings.json'
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def recalc(self):
|
||||||
"""
|
"""
|
||||||
Tests that 1 + 1 always equals 2.
|
Test if a Kyu/Dan Ranking recalculation gives the same result as stored.
|
||||||
|
|
||||||
|
:return:
|
||||||
"""
|
"""
|
||||||
self.assertEqual(1 + 1, 2)
|
|
||||||
|
for ranking in KyuDanRanking.objects.all():
|
||||||
|
original = {a: getattr(ranking, a) for a in self.equal_attrs}
|
||||||
|
ranking.recalculate()
|
||||||
|
for attr in self.equal_attrs:
|
||||||
|
self.assertEqual(
|
||||||
|
original[attr],
|
||||||
|
getattr(ranking, attr),
|
||||||
|
"Recalculation was different! user: {user}, attribute: "
|
||||||
|
"{attr}, original: {original}, recalc: {recalc}".format(
|
||||||
|
user=ranking.user, attr=attr, original=original[attr],
|
||||||
|
recalc=getattr(ranking, attr))
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_partial_recalc(self):
|
||||||
|
"""
|
||||||
|
Test if partial recalclulation gives the same results.
|
||||||
|
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
for ranking in KyuDanRanking.objects.all():
|
||||||
|
original = {a: getattr(ranking, a) for a in self.equal_attrs}
|
||||||
|
confirmed_hanchans = Hanchan.objects.confirmed_hanchans(
|
||||||
|
user=ranking.user,
|
||||||
|
since=ranking.legacy_date
|
||||||
|
)
|
||||||
|
rnd = random.randrange(confirmed_hanchans.count())
|
||||||
|
since = confirmed_hanchans[rnd].start
|
||||||
|
print(since)
|
||||||
|
|
||||||
|
ranking.recalculate(hanchan_start=since)
|
||||||
|
for attr in self.equal_attrs:
|
||||||
|
self.assertEqual(
|
||||||
|
original[attr],
|
||||||
|
getattr(ranking, attr),
|
||||||
|
"partial Recalculation was different! user: {user}, "
|
||||||
|
"attribute: {attr}, original: {original}, recalc: "
|
||||||
|
"{recalc}".format(
|
||||||
|
user=ranking.user, attr=attr, original=original[attr],
|
||||||
|
recalc=getattr(ranking, attr))
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_points_sum(self):
|
||||||
|
"""
|
||||||
|
Test if the sum of the kyu / dan points equals the value in the Ranking.
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
for ranking in KyuDanRanking.objects.all():
|
||||||
|
dan_kyu = 'dan_points' if ranking.dan else 'kyu_points'
|
||||||
|
points = {
|
||||||
|
'dan_points': ranking.legacy_dan_points or 0,
|
||||||
|
'kyu_points': ranking.legacy_kyu_points or 0
|
||||||
|
}
|
||||||
|
confirmed_hanchans = Hanchan.objects.confirmed_hanchans(
|
||||||
|
user=ranking.user,
|
||||||
|
since=ranking.legacy_date
|
||||||
|
)
|
||||||
|
for hanchan in confirmed_hanchans:
|
||||||
|
hanchan.get_playerdata(ranking.user)
|
||||||
|
points[dan_kyu] += getattr(hanchan, dan_kyu) or 0
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
points[dan_kyu],
|
||||||
|
getattr(ranking, dan_kyu),
|
||||||
|
"{dan_kyu} for {player} won't compute! ranking: {ranking}, sum: {sum}".format(
|
||||||
|
dan_kyu=dan_kyu, player=ranking.user,
|
||||||
|
ranking=getattr(ranking, dan_kyu), sum=points[dan_kyu])
|
||||||
|
)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: kasu.mahjong_ranking\n"
|
"Project-Id-Version: kasu.mahjong_ranking\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2016-09-28 00:25+0200\n"
|
"POT-Creation-Date: 2017-05-10 23:16+0200\n"
|
||||||
"PO-Revision-Date: 2016-09-28 00:24+0200\n"
|
"PO-Revision-Date: 2016-09-28 00:24+0200\n"
|
||||||
"Last-Translator: Christian Berg <xeniac.at@gmail.com>\n"
|
"Last-Translator: Christian Berg <xeniac.at@gmail.com>\n"
|
||||||
"Language-Team: Kasu <verein@kasu.at>\n"
|
"Language-Team: Kasu <verein@kasu.at>\n"
|
||||||
@@ -19,208 +19,208 @@ msgstr ""
|
|||||||
"X-Generator: Poedit 1.8.9\n"
|
"X-Generator: Poedit 1.8.9\n"
|
||||||
"X-Translated-Using: django-rosetta 0.7.2\n"
|
"X-Translated-Using: django-rosetta 0.7.2\n"
|
||||||
|
|
||||||
#: src/maistar_ranking/admin.py:24
|
#: maistar_ranking/admin.py:24
|
||||||
msgid "Recalculate"
|
msgid "Recalculate"
|
||||||
msgstr "Neuberechnen"
|
msgstr "Neuberechnen"
|
||||||
|
|
||||||
#: src/maistar_ranking/forms.py:33
|
#: maistar_ranking/forms.py:33
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%s may only participate once."
|
msgid "%s may only participate once."
|
||||||
msgstr "%s darf nur einmal teilnehmen."
|
msgstr "%s darf nur einmal teilnehmen."
|
||||||
|
|
||||||
#: src/maistar_ranking/models.py:20
|
#: maistar_ranking/models.py:20
|
||||||
msgid "Comment"
|
msgid "Comment"
|
||||||
msgstr "Kommentar"
|
msgstr "Kommentar"
|
||||||
|
|
||||||
#: src/maistar_ranking/models.py:22
|
#: maistar_ranking/models.py:22
|
||||||
msgid "Player 1"
|
msgid "Player 1"
|
||||||
msgstr "Spieler 1"
|
msgstr "Spieler 1"
|
||||||
|
|
||||||
#: src/maistar_ranking/models.py:24 src/maistar_ranking/models.py:30
|
#: maistar_ranking/models.py:24 maistar_ranking/models.py:30
|
||||||
#: src/maistar_ranking/models.py:36 src/maistar_ranking/models.py:42
|
#: maistar_ranking/models.py:36 maistar_ranking/models.py:42
|
||||||
#: src/maistar_ranking/models.py:48 src/maistar_ranking/models.py:54
|
#: maistar_ranking/models.py:48 maistar_ranking/models.py:54
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/ranking_list.html:19
|
#: maistar_ranking/templates/maistar_ranking/ranking_list.html:19
|
||||||
msgid "Score"
|
msgid "Score"
|
||||||
msgstr "Punkte"
|
msgstr "Punkte"
|
||||||
|
|
||||||
#: src/maistar_ranking/models.py:28
|
#: maistar_ranking/models.py:28
|
||||||
msgid "Player 2"
|
msgid "Player 2"
|
||||||
msgstr "Spieler 2"
|
msgstr "Spieler 2"
|
||||||
|
|
||||||
#: src/maistar_ranking/models.py:34
|
#: maistar_ranking/models.py:34
|
||||||
msgid "Player 3"
|
msgid "Player 3"
|
||||||
msgstr "Spieler 3"
|
msgstr "Spieler 3"
|
||||||
|
|
||||||
#: src/maistar_ranking/models.py:40
|
#: maistar_ranking/models.py:40
|
||||||
msgid "Player 4"
|
msgid "Player 4"
|
||||||
msgstr "Spieler 4"
|
msgstr "Spieler 4"
|
||||||
|
|
||||||
#: src/maistar_ranking/models.py:46
|
#: maistar_ranking/models.py:46
|
||||||
msgid "Player 5"
|
msgid "Player 5"
|
||||||
msgstr "Spieler 5"
|
msgstr "Spieler 5"
|
||||||
|
|
||||||
#: src/maistar_ranking/models.py:52
|
#: maistar_ranking/models.py:52
|
||||||
msgid "Player 6"
|
msgid "Player 6"
|
||||||
msgstr "Spieler 6"
|
msgstr "Spieler 6"
|
||||||
|
|
||||||
#: src/maistar_ranking/models.py:58
|
#: maistar_ranking/models.py:58
|
||||||
msgid "Has been confirmed"
|
msgid "Has been confirmed"
|
||||||
msgstr "Wurde bestätigt"
|
msgstr "Wurde bestätigt"
|
||||||
|
|
||||||
#: src/maistar_ranking/models.py:60
|
#: maistar_ranking/models.py:60
|
||||||
msgid "the game only counts whe it has been confirmed"
|
msgid "the game only counts whe it has been confirmed"
|
||||||
msgstr "das Spiel zählt nur wenn es bestätigt wurde"
|
msgstr "das Spiel zählt nur wenn es bestätigt wurde"
|
||||||
|
|
||||||
#: src/maistar_ranking/models.py:63 src/maistar_ranking/models.py:148
|
#: maistar_ranking/models.py:63 maistar_ranking/models.py:148
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/player_game_list.html:6
|
#: maistar_ranking/templates/maistar_ranking/player_game_list.html:6
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/ranking_list.html:4
|
#: maistar_ranking/templates/maistar_ranking/ranking_list.html:4
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/ranking_list.html:72
|
#: maistar_ranking/templates/maistar_ranking/ranking_list.html:72
|
||||||
msgid "Season"
|
msgid "Season"
|
||||||
msgstr "Saison"
|
msgstr "Saison"
|
||||||
|
|
||||||
#: src/maistar_ranking/models.py:69
|
#: maistar_ranking/models.py:69
|
||||||
msgid "Mai-Star Game with {0} from {1:%Y-%m-%d}"
|
msgid "Mai-Star Game with {0} from {1:%Y-%m-%d}"
|
||||||
msgstr "Mai-Star Spiel mit {0} vom {1:%Y-%m-%d}"
|
msgstr "Mai-Star Spiel mit {0} vom {1:%Y-%m-%d}"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/game_form.html:5
|
#: maistar_ranking/templates/maistar_ranking/game_form.html:5
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/game_form.html:16
|
#: maistar_ranking/templates/maistar_ranking/game_form.html:16
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/game_list.html:27
|
#: maistar_ranking/templates/maistar_ranking/game_list.html:27
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/player_game_list.html:45
|
#: maistar_ranking/templates/maistar_ranking/player_game_list.html:45
|
||||||
msgid "Edit Game"
|
msgid "Edit Game"
|
||||||
msgstr "Spiel bearbeiten"
|
msgstr "Spiel bearbeiten"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/game_form.html:5
|
#: maistar_ranking/templates/maistar_ranking/game_form.html:5
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/game_form.html:16
|
#: maistar_ranking/templates/maistar_ranking/game_form.html:16
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/game_list.html:41
|
#: maistar_ranking/templates/maistar_ranking/game_list.html:41
|
||||||
msgid "Add Game"
|
msgid "Add Game"
|
||||||
msgstr "Spiel hinzufügen"
|
msgstr "Spiel hinzufügen"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/game_form.html:76
|
#: maistar_ranking/templates/maistar_ranking/game_form.html:76
|
||||||
msgid "Back"
|
msgid "Back"
|
||||||
msgstr "Zurück"
|
msgstr "Zurück"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/game_form.html:77
|
#: maistar_ranking/templates/maistar_ranking/game_form.html:77
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Speichern"
|
msgstr "Speichern"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/game_list.html:4
|
#: maistar_ranking/templates/maistar_ranking/game_list.html:4
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/player_game_list.html:6
|
#: maistar_ranking/templates/maistar_ranking/player_game_list.html:6
|
||||||
msgid "Mai-Star Games"
|
msgid "Mai-Star Games"
|
||||||
msgstr "Mai-Star Spiele"
|
msgstr "Mai-Star Spiele"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/game_list.html:7
|
#: maistar_ranking/templates/maistar_ranking/game_list.html:7
|
||||||
msgid "Played Mai-Star Games"
|
msgid "Played Mai-Star Games"
|
||||||
msgstr "Gespielte Mai-Star Spiele"
|
msgstr "Gespielte Mai-Star Spiele"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/game_list.html:11
|
#: maistar_ranking/templates/maistar_ranking/game_list.html:11
|
||||||
msgid "Game"
|
msgid "Game"
|
||||||
msgstr "Spiel"
|
msgstr "Spiel"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/game_list.html:14
|
#: maistar_ranking/templates/maistar_ranking/game_list.html:14
|
||||||
msgid "Place"
|
msgid "Place"
|
||||||
msgstr "Platz"
|
msgstr "Platz"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/game_list.html:19
|
#: maistar_ranking/templates/maistar_ranking/game_list.html:19
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/player_game_list.html:37
|
#: maistar_ranking/templates/maistar_ranking/player_game_list.html:37
|
||||||
msgid "Points"
|
msgid "Points"
|
||||||
msgstr "Punkte"
|
msgstr "Punkte"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/game_list.html:24
|
#: maistar_ranking/templates/maistar_ranking/game_list.html:24
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/player_game_list.html:42
|
#: maistar_ranking/templates/maistar_ranking/player_game_list.html:42
|
||||||
msgid "Delete Game"
|
msgid "Delete Game"
|
||||||
msgstr "Spiel löschen"
|
msgstr "Spiel löschen"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/game_list.html:33
|
#: maistar_ranking/templates/maistar_ranking/game_list.html:33
|
||||||
msgid "No Mai-Star games have been added to this event yet."
|
msgid "No Mai-Star games have been added to this event yet."
|
||||||
msgstr "Für diese Veranstaltung wurden noch keine Mai-Star Spiele erfasst."
|
msgstr "Für diese Veranstaltung wurden noch keine Mai-Star Spiele erfasst."
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/game_list.html:40
|
#: maistar_ranking/templates/maistar_ranking/game_list.html:40
|
||||||
msgid "Edit Event"
|
msgid "Edit Event"
|
||||||
msgstr "Veranstaltung bearbeiten"
|
msgstr "Veranstaltung bearbeiten"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/hanchan_confirm_delete.html:4
|
#: maistar_ranking/templates/maistar_ranking/hanchan_confirm_delete.html:4
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/hanchan_confirm_delete.html:10
|
#: maistar_ranking/templates/maistar_ranking/hanchan_confirm_delete.html:10
|
||||||
msgid "Delete game"
|
msgid "Delete game"
|
||||||
msgstr "Spiel löschen"
|
msgstr "Spiel löschen"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/hanchan_confirm_delete.html:13
|
#: maistar_ranking/templates/maistar_ranking/hanchan_confirm_delete.html:13
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Abbrechen"
|
msgstr "Abbrechen"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/hanchan_confirm_delete.html:14
|
#: maistar_ranking/templates/maistar_ranking/hanchan_confirm_delete.html:14
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Löschen"
|
msgstr "Löschen"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/page.html:5
|
#: maistar_ranking/templates/maistar_ranking/page.html:5
|
||||||
msgid "Archive"
|
msgid "Archive"
|
||||||
msgstr "Archiv"
|
msgstr "Archiv"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/page.html:7
|
#: maistar_ranking/templates/maistar_ranking/page.html:7
|
||||||
msgid "Add Event"
|
msgid "Add Event"
|
||||||
msgstr "Veranstaltung hinzufügen"
|
msgstr "Veranstaltung hinzufügen"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/player_game_list.html:4
|
#: maistar_ranking/templates/maistar_ranking/player_game_list.html:4
|
||||||
msgid "Ladder Score for"
|
msgid "Ladder Score for"
|
||||||
msgstr "Ladder Wertung für"
|
msgstr "Ladder Wertung für"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/player_game_list.html:9
|
#: maistar_ranking/templates/maistar_ranking/player_game_list.html:9
|
||||||
msgid "Mai-Star Games with"
|
msgid "Mai-Star Games with"
|
||||||
msgstr "Mai-Star Spiele mit"
|
msgstr "Mai-Star Spiele mit"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/player_game_list.html:14
|
#: maistar_ranking/templates/maistar_ranking/player_game_list.html:14
|
||||||
msgid "Date"
|
msgid "Date"
|
||||||
msgstr "Datum"
|
msgstr "Datum"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/player_game_list.html:15
|
#: maistar_ranking/templates/maistar_ranking/player_game_list.html:15
|
||||||
msgid "Event"
|
msgid "Event"
|
||||||
msgstr "Veranstaltung"
|
msgstr "Veranstaltung"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/player_game_list.html:16
|
#: maistar_ranking/templates/maistar_ranking/player_game_list.html:16
|
||||||
msgid "Players"
|
msgid "Players"
|
||||||
msgstr "Spieler"
|
msgstr "Spieler"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/ranking_list.html:4
|
#: maistar_ranking/templates/maistar_ranking/ranking_list.html:4
|
||||||
msgid "Mai-Star Ranking"
|
msgid "Mai-Star Ranking"
|
||||||
msgstr "Mai-Star Platzierung"
|
msgstr "Mai-Star Platzierung"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/ranking_list.html:10
|
#: maistar_ranking/templates/maistar_ranking/ranking_list.html:10
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/ranking_list.html:18
|
#: maistar_ranking/templates/maistar_ranking/ranking_list.html:18
|
||||||
msgid "Placement"
|
msgid "Placement"
|
||||||
msgstr "Platzierung"
|
msgstr "Platzierung"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/ranking_list.html:11
|
#: maistar_ranking/templates/maistar_ranking/ranking_list.html:11
|
||||||
msgid "Avatar"
|
msgid "Avatar"
|
||||||
msgstr "Avatar"
|
msgstr "Avatar"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/ranking_list.html:12
|
#: maistar_ranking/templates/maistar_ranking/ranking_list.html:12
|
||||||
msgid "Nickname"
|
msgid "Nickname"
|
||||||
msgstr "Spitzname"
|
msgstr "Spitzname"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/ranking_list.html:13
|
#: maistar_ranking/templates/maistar_ranking/ranking_list.html:13
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Name"
|
msgstr "Name"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/ranking_list.html:14
|
#: maistar_ranking/templates/maistar_ranking/ranking_list.html:14
|
||||||
msgid "Average"
|
msgid "Average"
|
||||||
msgstr "Durchschnitt"
|
msgstr "Durchschnitt"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/ranking_list.html:15
|
#: maistar_ranking/templates/maistar_ranking/ranking_list.html:15
|
||||||
msgid "Games"
|
msgid "Games"
|
||||||
msgstr "Spiele"
|
msgstr "Spiele"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/ranking_list.html:20
|
#: maistar_ranking/templates/maistar_ranking/ranking_list.html:20
|
||||||
msgid "count"
|
msgid "count"
|
||||||
msgstr "Anzahl"
|
msgstr "Anzahl"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/ranking_list.html:21
|
#: maistar_ranking/templates/maistar_ranking/ranking_list.html:21
|
||||||
msgid "good"
|
msgid "good"
|
||||||
msgstr "Gut"
|
msgstr "Gut"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/ranking_list.html:22
|
#: maistar_ranking/templates/maistar_ranking/ranking_list.html:22
|
||||||
msgid "won"
|
msgid "won"
|
||||||
msgstr "Gewonnen"
|
msgstr "Gewonnen"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/ranking_list.html:43
|
#: maistar_ranking/templates/maistar_ranking/ranking_list.html:43
|
||||||
msgid ""
|
msgid ""
|
||||||
"Unfortunately, nobody has it been done in the ranking.\n"
|
"Unfortunately, nobody has it been done in the ranking.\n"
|
||||||
" A player must have 6 games done, to be added to the ranking."
|
" A player must have 6 games done, to be added to the ranking."
|
||||||
@@ -229,15 +229,15 @@ msgstr ""
|
|||||||
"als 6 Spiele innerhalb einer Saison absolviert haben, werden für das "
|
"als 6 Spiele innerhalb einer Saison absolviert haben, werden für das "
|
||||||
"Endergebnis nicht gewertet."
|
"Endergebnis nicht gewertet."
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/ranking_list.html:52
|
#: maistar_ranking/templates/maistar_ranking/ranking_list.html:52
|
||||||
msgid "Latest Games"
|
msgid "Latest Games"
|
||||||
msgstr "Letzten Spiele"
|
msgstr "Letzten Spiele"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/ranking_list.html:63
|
#: maistar_ranking/templates/maistar_ranking/ranking_list.html:63
|
||||||
msgid "Latest Events"
|
msgid "Latest Events"
|
||||||
msgstr "Letzten Veranstaltungen"
|
msgstr "Letzten Veranstaltungen"
|
||||||
|
|
||||||
#: src/maistar_ranking/templates/maistar_ranking/ranking_list.html:70
|
#: maistar_ranking/templates/maistar_ranking/ranking_list.html:70
|
||||||
msgid "Ladder Archive"
|
msgid "Ladder Archive"
|
||||||
msgstr "Archiv"
|
msgstr "Archiv"
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td class="center">{{ game.event.start|date:'SHORT_DATE_FORMAT' }}</td>
|
<td class="center">{{ game.event.start|date:'SHORT_DATE_FORMAT' }}</td>
|
||||||
<td><a href="{{ game.get_absolute_url }}">{{ game.event.name }}</a></td>
|
<td><a href="{{ game.get_absolute_url }}">{{ game.event.name }}</a></td>
|
||||||
</td>
|
|
||||||
{% for player in game.player_list %}
|
{% for player in game.player_list %}
|
||||||
<td class="center">
|
<td class="center">
|
||||||
<a href="{% url 'maistar-player-games' username=player.user.username season=season %}">{{ player.user.username }}</a>
|
<a href="{% url 'maistar-player-games' username=player.user.username season=season %}">{{ player.user.username }}</a>
|
||||||
|
|||||||
@@ -72,7 +72,9 @@
|
|||||||
<label for="season">{% trans 'Season' %}</label>
|
<label for="season">{% trans 'Season' %}</label>
|
||||||
<select id="season" name="season" size="1" onChange="window.location.href = document.season_select.season.options[document.season_select.season.selectedIndex].value;">
|
<select id="season" name="season" size="1" onChange="window.location.href = document.season_select.season.options[document.season_select.season.selectedIndex].value;">
|
||||||
{% for season_link in season_list%}
|
{% for season_link in season_list%}
|
||||||
<option value="{% url 'maistar-ranking' season=season_link %}" {% ifequal season season_link %}selected="selected"{% endifequal %}>{{ season_link }}</option>
|
<option
|
||||||
|
{% ifequal season season_link %} selected="selected"{% endifequal %}
|
||||||
|
value="{% url 'maistar-ranking' season=season_link %}" >{{ season_link }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ Created on 03.10.2011
|
|||||||
"""
|
"""
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
from django.views.generic import RedirectView
|
from django.views.generic import RedirectView
|
||||||
from .views import DeleteGame, ListGames, ListPlayerGames, \
|
from .views import DeleteGame, ListGames, ListPlayerGames, \
|
||||||
ListRankings, GameForm
|
ListRankings, GameForm
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ from django.views import generic
|
|||||||
from events.models import Event
|
from events.models import Event
|
||||||
from events.views import EventDetailMixin
|
from events.views import EventDetailMixin
|
||||||
from membership.models import Membership
|
from membership.models import Membership
|
||||||
from utils.mixins import LoginRequiredMixin, PermissionRequiredMixin
|
from utils.mixins import LoginRequiredMixin
|
||||||
|
from utils.mixins import PermissionRequiredMixin
|
||||||
from mahjong_ranking.views import PlayerScore
|
from mahjong_ranking.views import PlayerScore
|
||||||
from . import forms, models
|
from . import forms, models
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class ProxyGroup(Group):
|
|||||||
|
|
||||||
class MembershipAdmin(UserAdmin):
|
class MembershipAdmin(UserAdmin):
|
||||||
# admin_thumbnail = AdminThumbnail(image_field='thumbnail')
|
# admin_thumbnail = AdminThumbnail(image_field='thumbnail')
|
||||||
list_filter = ('is_active','membership', 'confirmed')
|
list_filter = ('is_active', 'membership', 'confirmed')
|
||||||
list_display = (
|
list_display = (
|
||||||
'avatar',
|
'avatar',
|
||||||
'username',
|
'username',
|
||||||
|
|||||||
@@ -3,15 +3,18 @@ Created on 03.10.2011
|
|||||||
|
|
||||||
@author: Christian
|
@author: Christian
|
||||||
"""
|
"""
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import auth
|
from django.contrib import auth
|
||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from . import models
|
|
||||||
from utils.html5 import forms
|
|
||||||
from utils.massmailer import MassMailer
|
from utils.massmailer import MassMailer
|
||||||
|
from captcha.fields import ReCaptchaField
|
||||||
|
from . import models
|
||||||
|
|
||||||
class MembershipForm(forms.ModelForm):
|
class MembershipForm(forms.ModelForm):
|
||||||
error_css_class = 'error'
|
error_css_class = 'error'
|
||||||
@@ -65,9 +68,11 @@ class RegistrationForm(MembershipForm):
|
|||||||
requires the password to be entered twice to catch typos.
|
requires the password to be entered twice to catch typos.
|
||||||
sends an activation request per mail, to validate the eMail.
|
sends an activation request per mail, to validate the eMail.
|
||||||
"""
|
"""
|
||||||
password1 = forms.CharField(widget=forms.PasswordInput(), label=_('password'))
|
password1 = forms.CharField(
|
||||||
password2 = forms.CharField(widget=forms.PasswordInput(), label=_('password (again)'))
|
widget=forms.PasswordInput(), label=_('password'))
|
||||||
recaptcha = forms.ReCaptchaField()
|
password2 = forms.CharField(
|
||||||
|
widget=forms.PasswordInput(), label=_('password (again)'))
|
||||||
|
recaptcha = ReCaptchaField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = auth.get_user_model()
|
model = auth.get_user_model()
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: kasu.membership\n"
|
"Project-Id-Version: kasu.membership\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2016-09-28 00:25+0200\n"
|
"POT-Creation-Date: 2017-05-10 23:16+0200\n"
|
||||||
"PO-Revision-Date: 2016-09-28 00:24+0200\n"
|
"PO-Revision-Date: 2016-09-28 00:24+0200\n"
|
||||||
"Last-Translator: Christian Berg <xeniac@posteo.at>\n"
|
"Last-Translator: Christian Berg <xeniac@posteo.at>\n"
|
||||||
"Language-Team: Kasu <verein@kasu.at>\n"
|
"Language-Team: Kasu <verein@kasu.at>\n"
|
||||||
@@ -19,164 +19,162 @@ msgstr ""
|
|||||||
"X-Translated-Using: django-rosetta 0.7.2\n"
|
"X-Translated-Using: django-rosetta 0.7.2\n"
|
||||||
"X-Generator: Poedit 1.8.9\n"
|
"X-Generator: Poedit 1.8.9\n"
|
||||||
|
|
||||||
#: src/membership/admin.py:23
|
#: membership/admin.py:23
|
||||||
msgid "Activate selected User"
|
msgid "Activate selected User"
|
||||||
msgstr "Ausgewählte Benutzer freischalten"
|
msgstr "Ausgewählte Benutzer freischalten"
|
||||||
|
|
||||||
#: src/membership/admin.py:33
|
#: membership/admin.py:33
|
||||||
msgid "Cleanup selected Activation Requests"
|
msgid "Cleanup selected Activation Requests"
|
||||||
msgstr "Ausgewählte Aktivierungsanfragen bereinigen"
|
msgstr "Ausgewählte Aktivierungsanfragen bereinigen"
|
||||||
|
|
||||||
#: src/membership/admin.py:40
|
#: membership/admin.py:40
|
||||||
msgid "Group"
|
msgid "Group"
|
||||||
msgstr "Gruppe"
|
msgstr "Gruppe"
|
||||||
|
|
||||||
#: src/membership/admin.py:41
|
#: membership/admin.py:41
|
||||||
msgid "Groups"
|
msgid "Groups"
|
||||||
msgstr "Gruppen"
|
msgstr "Gruppen"
|
||||||
|
|
||||||
#: src/membership/admin.py:62 src/membership/models.py:164
|
#: membership/admin.py:62 membership/models.py:164 membership/models.py:215
|
||||||
#: src/membership/models.py:215
|
#: membership/templates/membership/register_form.html:31
|
||||||
#: src/membership/templates/membership/register_form.html:32
|
|
||||||
msgid "Membership"
|
msgid "Membership"
|
||||||
msgstr "Mitgliedschaft"
|
msgstr "Mitgliedschaft"
|
||||||
|
|
||||||
#: src/membership/admin.py:65
|
#: membership/admin.py:65
|
||||||
msgid "Permissions"
|
msgid "Permissions"
|
||||||
msgstr "Berechtigung"
|
msgstr "Berechtigung"
|
||||||
|
|
||||||
#: src/membership/admin.py:67
|
#: membership/admin.py:67
|
||||||
msgid "Important dates"
|
msgid "Important dates"
|
||||||
msgstr "Wichtige Daten"
|
msgstr "Wichtige Daten"
|
||||||
|
|
||||||
#: src/membership/forms.py:20
|
#: membership/forms.py:20
|
||||||
msgid "birthday"
|
msgid "birthday"
|
||||||
msgstr "Geburtstag"
|
msgstr "Geburtstag"
|
||||||
|
|
||||||
#: src/membership/forms.py:22
|
#: membership/forms.py:22
|
||||||
msgid "Input format: yyyy-mm-dd"
|
msgid "Input format: yyyy-mm-dd"
|
||||||
msgstr "Eingabeformat: tt.mm.jjjj"
|
msgstr "Eingabeformat: tt.mm.jjjj"
|
||||||
|
|
||||||
#: src/membership/forms.py:24
|
#: membership/forms.py:24
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
msgstr "E-Mail"
|
msgstr "E-Mail"
|
||||||
|
|
||||||
#: src/membership/forms.py:36 src/membership/forms.py:43
|
#: membership/forms.py:36 membership/forms.py:43 membership/forms.py:50
|
||||||
#: src/membership/forms.py:50
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"For your membership, we need this. Please fill out this field "
|
"For your membership, we need this. Please fill out this field "
|
||||||
"yet."
|
"yet."
|
||||||
msgstr "Diese Angabe wird für eine Mitgliedschaft benötigt, bitte ausfüllen."
|
msgstr "Diese Angabe wird für eine Mitgliedschaft benötigt, bitte ausfüllen."
|
||||||
|
|
||||||
#: src/membership/forms.py:56
|
#: membership/forms.py:56
|
||||||
msgid ""
|
msgid ""
|
||||||
"For your membership, we need this. Please fill out this field "
|
"For your membership, we need this. Please fill out this field "
|
||||||
"yet."
|
"yet."
|
||||||
msgstr "Diese Angabe wird für eine Mitgliedschaft benötigt, bitte ausfüllen."
|
msgstr "Diese Angabe wird für eine Mitgliedschaft benötigt, bitte ausfüllen."
|
||||||
|
|
||||||
#: src/membership/forms.py:68
|
#: membership/forms.py:68
|
||||||
msgid "password"
|
msgid "password"
|
||||||
msgstr "Passwort"
|
msgstr "Passwort"
|
||||||
|
|
||||||
#: src/membership/forms.py:69
|
#: membership/forms.py:69
|
||||||
msgid "password (again)"
|
msgid "password (again)"
|
||||||
msgstr "Passwort (wiederholen)"
|
msgstr "Passwort (wiederholen)"
|
||||||
|
|
||||||
#: src/membership/forms.py:92
|
#: membership/forms.py:92
|
||||||
msgid "This username is already taken. Please choose another."
|
msgid "This username is already taken. Please choose another."
|
||||||
msgstr "Diesen Benutzername ist schon vergeben. Bitte einen anderen auswählen."
|
msgstr "Diesen Benutzername ist schon vergeben. Bitte einen anderen auswählen."
|
||||||
|
|
||||||
#: src/membership/forms.py:101
|
#: membership/forms.py:101
|
||||||
msgid ""
|
msgid ""
|
||||||
"This email address is already in use. Please supply a different "
|
"This email address is already in use. Please supply a different "
|
||||||
"email address."
|
"email address."
|
||||||
msgstr "Die E-Mail Adresse wird schon verwendet. Bitte eine andere angeben."
|
msgstr "Die E-Mail Adresse wird schon verwendet. Bitte eine andere angeben."
|
||||||
|
|
||||||
#: src/membership/forms.py:110
|
#: membership/forms.py:110
|
||||||
msgid "The two password fields didn't match."
|
msgid "The two password fields didn't match."
|
||||||
msgstr "Die beiden Passwörter passen nicht."
|
msgstr "Die beiden Passwörter passen nicht."
|
||||||
|
|
||||||
#: src/membership/models.py:20
|
#: membership/models.py:20
|
||||||
msgid "Male"
|
msgid "Male"
|
||||||
msgstr "Männlich"
|
msgstr "Männlich"
|
||||||
|
|
||||||
#: src/membership/models.py:21
|
#: membership/models.py:21
|
||||||
msgid "Female"
|
msgid "Female"
|
||||||
msgstr "Weiblich"
|
msgstr "Weiblich"
|
||||||
|
|
||||||
#: src/membership/models.py:90
|
#: membership/models.py:90
|
||||||
msgid "user"
|
msgid "user"
|
||||||
msgstr "Benutzer"
|
msgstr "Benutzer"
|
||||||
|
|
||||||
#: src/membership/models.py:92
|
#: membership/models.py:92
|
||||||
msgid "activation key"
|
msgid "activation key"
|
||||||
msgstr "Aktivierungsschlüssel"
|
msgstr "Aktivierungsschlüssel"
|
||||||
|
|
||||||
#: src/membership/models.py:96
|
#: membership/models.py:96
|
||||||
msgid "pending activation"
|
msgid "pending activation"
|
||||||
msgstr "Ausstehende Aktivierung"
|
msgstr "Ausstehende Aktivierung"
|
||||||
|
|
||||||
#: src/membership/models.py:97
|
#: membership/models.py:97
|
||||||
msgid "pending activations"
|
msgid "pending activations"
|
||||||
msgstr "Wartende Aktivierungen"
|
msgstr "Wartende Aktivierungen"
|
||||||
|
|
||||||
#: src/membership/models.py:100
|
#: membership/models.py:100
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "user registration for %s"
|
msgid "user registration for %s"
|
||||||
msgstr "Benutzerregistrierung für %s"
|
msgstr "Benutzerregistrierung für %s"
|
||||||
|
|
||||||
#: src/membership/models.py:147
|
#: membership/models.py:147
|
||||||
msgid "Gender"
|
msgid "Gender"
|
||||||
msgstr "Geschlecht"
|
msgstr "Geschlecht"
|
||||||
|
|
||||||
#: src/membership/models.py:166
|
#: membership/models.py:166
|
||||||
msgid ""
|
msgid ""
|
||||||
"Yes, I confirm that I am in agreement with the statutes and would "
|
"Yes, I confirm that I am in agreement with the statutes and would "
|
||||||
"like to become a member."
|
"like to become a member."
|
||||||
msgstr "Ja, ich bin mit den Statuen einverstanden und möchte Mitglied werden."
|
msgstr "Ja, ich bin mit den Statuen einverstanden und möchte Mitglied werden."
|
||||||
|
|
||||||
#: src/membership/models.py:170
|
#: membership/models.py:170
|
||||||
msgid "Birthday Date"
|
msgid "Birthday Date"
|
||||||
msgstr "Geburtstag"
|
msgstr "Geburtstag"
|
||||||
|
|
||||||
#: src/membership/models.py:174
|
#: membership/models.py:174
|
||||||
msgid "Telephone"
|
msgid "Telephone"
|
||||||
msgstr "Telefon"
|
msgstr "Telefon"
|
||||||
|
|
||||||
#: src/membership/models.py:180
|
#: membership/models.py:180
|
||||||
msgid "Address"
|
msgid "Address"
|
||||||
msgstr "Adresse"
|
msgstr "Adresse"
|
||||||
|
|
||||||
#: src/membership/models.py:186
|
#: membership/models.py:186
|
||||||
msgid "Postcode"
|
msgid "Postcode"
|
||||||
msgstr "Postleitzahl"
|
msgstr "Postleitzahl"
|
||||||
|
|
||||||
#: src/membership/models.py:191
|
#: membership/models.py:191
|
||||||
msgid "Town/City"
|
msgid "Town/City"
|
||||||
msgstr "Ort"
|
msgstr "Ort"
|
||||||
|
|
||||||
#: src/membership/models.py:199
|
#: membership/models.py:199
|
||||||
msgid "Paid until"
|
msgid "Paid until"
|
||||||
msgstr "Bezahlt bis"
|
msgstr "Bezahlt bis"
|
||||||
|
|
||||||
#: src/membership/models.py:205
|
#: membership/models.py:205
|
||||||
msgid "Confirmed"
|
msgid "Confirmed"
|
||||||
msgstr "Bestätigt"
|
msgstr "Bestätigt"
|
||||||
|
|
||||||
#: src/membership/models.py:207
|
#: membership/models.py:207
|
||||||
msgid "This person has paid the membership fee."
|
msgid "This person has paid the membership fee."
|
||||||
msgstr "Diese Person hat ihre Mitgliedschaft bezahlt"
|
msgstr "Diese Person hat ihre Mitgliedschaft bezahlt"
|
||||||
|
|
||||||
#: src/membership/models.py:216
|
#: membership/models.py:216
|
||||||
msgid "Memberships"
|
msgid "Memberships"
|
||||||
msgstr "Mitgliedschaften"
|
msgstr "Mitgliedschaften"
|
||||||
|
|
||||||
#: src/membership/templates/membership/email/activation_email.txt:2
|
#: membership/templates/membership/email/activation_email.txt:2
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Welcome %(user)s,"
|
msgid "Welcome %(user)s,"
|
||||||
msgstr "Herzlich willkommen %(user)s,"
|
msgstr "Herzlich willkommen %(user)s,"
|
||||||
|
|
||||||
#: src/membership/templates/membership/email/activation_email.txt:4
|
#: membership/templates/membership/email/activation_email.txt:4
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"We received an account request on %(site.domain)s for your email address.\n"
|
"We received an account request on %(site.domain)s for your email address.\n"
|
||||||
@@ -187,7 +185,7 @@ msgstr ""
|
|||||||
"Solltest du diesen Account aktivieren wollen, klicke bitte auf den unten "
|
"Solltest du diesen Account aktivieren wollen, klicke bitte auf den unten "
|
||||||
"stehenden Link, oder kopiere diesen in die Adresszeile deines Browsers:"
|
"stehenden Link, oder kopiere diesen in die Adresszeile deines Browsers:"
|
||||||
|
|
||||||
#: src/membership/templates/membership/email/activation_email.txt:9
|
#: membership/templates/membership/email/activation_email.txt:9
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"If you do not want to open an account on %(site.domain)s, please ignore this "
|
"If you do not want to open an account on %(site.domain)s, please ignore this "
|
||||||
@@ -198,7 +196,7 @@ msgstr ""
|
|||||||
"Mail bitte.\n"
|
"Mail bitte.\n"
|
||||||
"Die Zugangsdaten werden dann in ein paar Tagen automatisch gelöscht."
|
"Die Zugangsdaten werden dann in ein paar Tagen automatisch gelöscht."
|
||||||
|
|
||||||
#: src/membership/templates/membership/email/activation_email.txt:12
|
#: membership/templates/membership/email/activation_email.txt:12
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Best Regards,\n"
|
"Best Regards,\n"
|
||||||
@@ -207,166 +205,166 @@ msgstr ""
|
|||||||
"mit den besten Wünschen\n"
|
"mit den besten Wünschen\n"
|
||||||
"Das Team von %(site.domain)s"
|
"Das Team von %(site.domain)s"
|
||||||
|
|
||||||
#: src/membership/templates/membership/email/password_reset_email.html:2
|
#: membership/templates/membership/email/password_reset_email.html:2
|
||||||
msgid "You're receiving this e-mail because you requested a password reset"
|
msgid "You're receiving this e-mail because you requested a password reset"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Du hast diese E-Mail erhalten, weil jemand die das Passwort zurücksetzen "
|
"Du hast diese E-Mail erhalten, weil jemand die das Passwort zurücksetzen "
|
||||||
"möchte. "
|
"möchte. "
|
||||||
|
|
||||||
#: src/membership/templates/membership/email/password_reset_email.html:3
|
#: membership/templates/membership/email/password_reset_email.html:3
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "for your user account at %(site_name)s"
|
msgid "for your user account at %(site_name)s"
|
||||||
msgstr "Für deinen Benutzerzugang auf %(site_name)s"
|
msgstr "Für deinen Benutzerzugang auf %(site_name)s"
|
||||||
|
|
||||||
#: src/membership/templates/membership/email/password_reset_email.html:5
|
#: membership/templates/membership/email/password_reset_email.html:5
|
||||||
msgid "Please go to the following page and choose a new password:"
|
msgid "Please go to the following page and choose a new password:"
|
||||||
msgstr "Bitte gehe auf folgende Seite und wähle ein neues Passwort aus:"
|
msgstr "Bitte gehe auf folgende Seite und wähle ein neues Passwort aus:"
|
||||||
|
|
||||||
#: src/membership/templates/membership/email/password_reset_email.html:9
|
#: membership/templates/membership/email/password_reset_email.html:9
|
||||||
msgid "Your username, in case you've forgotten:"
|
msgid "Your username, in case you've forgotten:"
|
||||||
msgstr "Dein Benutzername, für den Fall das du diesen vergessen hast:"
|
msgstr "Dein Benutzername, für den Fall das du diesen vergessen hast:"
|
||||||
|
|
||||||
#: src/membership/templates/membership/email/password_reset_email.html:11
|
#: membership/templates/membership/email/password_reset_email.html:11
|
||||||
msgid "Thanks for using our site!"
|
msgid "Thanks for using our site!"
|
||||||
msgstr "Danke das du unsere Seite verwendest!"
|
msgstr "Danke das du unsere Seite verwendest!"
|
||||||
|
|
||||||
#: src/membership/templates/membership/email/password_reset_email.html:13
|
#: membership/templates/membership/email/password_reset_email.html:13
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The %(site_name)s team"
|
msgid "The %(site_name)s team"
|
||||||
msgstr "Das %(site_name)s Team"
|
msgstr "Das %(site_name)s Team"
|
||||||
|
|
||||||
#: src/membership/templates/membership/email/password_reset_subject.txt:2
|
#: membership/templates/membership/email/password_reset_subject.txt:2
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Password reset on %(site_name)s"
|
msgid "Password reset on %(site_name)s"
|
||||||
msgstr "Passwort auf %(site_name)s zurücksetzen"
|
msgstr "Passwort auf %(site_name)s zurücksetzen"
|
||||||
|
|
||||||
#: src/membership/templates/membership/hanchan_table.html:5
|
#: membership/templates/membership/hanchan_table.html:5
|
||||||
msgid "Start"
|
msgid "Start"
|
||||||
msgstr "Beginn"
|
msgstr "Beginn"
|
||||||
|
|
||||||
#: src/membership/templates/membership/hanchan_table.html:6
|
#: membership/templates/membership/hanchan_table.html:6
|
||||||
msgid "Event"
|
msgid "Event"
|
||||||
msgstr "Termin"
|
msgstr "Termin"
|
||||||
|
|
||||||
#: src/membership/templates/membership/hanchan_table.html:7
|
#: membership/templates/membership/hanchan_table.html:7
|
||||||
msgid "Players"
|
msgid "Players"
|
||||||
msgstr "Spieler"
|
msgstr "Spieler"
|
||||||
|
|
||||||
#: src/membership/templates/membership/hanchan_table.html:8
|
#: membership/templates/membership/hanchan_table.html:8
|
||||||
msgid "Kyu Points"
|
msgid "Kyu Points"
|
||||||
msgstr "Kyū Punkte"
|
msgstr "Kyū Punkte"
|
||||||
|
|
||||||
#: src/membership/templates/membership/hanchan_table.html:9
|
#: membership/templates/membership/hanchan_table.html:9
|
||||||
msgid "Dan Points"
|
msgid "Dan Points"
|
||||||
msgstr "Dan Punkte"
|
msgstr "Dan Punkte"
|
||||||
|
|
||||||
#: src/membership/templates/membership/hanchan_table.html:10
|
#: membership/templates/membership/hanchan_table.html:10
|
||||||
msgid "Bonus Points"
|
msgid "Bonus Points"
|
||||||
msgstr "Bonus Punkte"
|
msgstr "Bonus Punkte"
|
||||||
|
|
||||||
#: src/membership/templates/membership/hanchan_table.html:11
|
#: membership/templates/membership/hanchan_table.html:11
|
||||||
msgid "Comment"
|
msgid "Comment"
|
||||||
msgstr "Anmerkung"
|
msgstr "Anmerkung"
|
||||||
|
|
||||||
#: src/membership/templates/membership/hanchan_table.html:26
|
#: membership/templates/membership/hanchan_table.html:26
|
||||||
msgid "This Hanchan does not validate"
|
msgid "This Hanchan does not validate"
|
||||||
msgstr "Diese Hanchan ist ungültig"
|
msgstr "Diese Hanchan ist ungültig"
|
||||||
|
|
||||||
#: src/membership/templates/membership/membership_detail.html:6
|
#: membership/templates/membership/membership_detail.html:6
|
||||||
msgid "profile for"
|
msgid "profile for"
|
||||||
msgstr "Profil für"
|
msgstr "Profil für"
|
||||||
|
|
||||||
#: src/membership/templates/membership/membership_detail.html:10
|
#: membership/templates/membership/membership_detail.html:10
|
||||||
msgid "Ladder Hanchans"
|
msgid "Ladder Hanchans"
|
||||||
msgstr "Ladder Hanchans"
|
msgstr "Ladder Hanchans"
|
||||||
|
|
||||||
#: src/membership/templates/membership/membership_detail.html:11
|
#: membership/templates/membership/membership_detail.html:11
|
||||||
msgid "Kyu Hanchans"
|
msgid "Kyu Hanchans"
|
||||||
msgstr "Kyū Hanchans"
|
msgstr "Kyū Hanchans"
|
||||||
|
|
||||||
#: src/membership/templates/membership/membership_detail.html:12
|
#: membership/templates/membership/membership_detail.html:12
|
||||||
msgid "Dan Hanchans"
|
msgid "Dan Hanchans"
|
||||||
msgstr "Dan Hanchans"
|
msgstr "Dan Hanchans"
|
||||||
|
|
||||||
#: src/membership/templates/membership/membership_detail.html:13
|
#: membership/templates/membership/membership_detail.html:13
|
||||||
msgid "Invalid Hanchans"
|
msgid "Invalid Hanchans"
|
||||||
msgstr "Ungültige Hanchans"
|
msgstr "Ungültige Hanchans"
|
||||||
|
|
||||||
#: src/membership/templates/membership/membership_detail.html:14
|
#: membership/templates/membership/membership_detail.html:14
|
||||||
msgid "Mai-Star Games"
|
msgid "Mai-Star Games"
|
||||||
msgstr "Mai-Star Spiele"
|
msgstr "Mai-Star Spiele"
|
||||||
|
|
||||||
#: src/membership/templates/membership/membership_detail.html:20
|
#: membership/templates/membership/membership_detail.html:20
|
||||||
msgid "Profile Image"
|
msgid "Profile Image"
|
||||||
msgstr "Profilbild"
|
msgstr "Profilbild"
|
||||||
|
|
||||||
#: src/membership/templates/membership/membership_detail.html:28
|
#: membership/templates/membership/membership_detail.html:28
|
||||||
msgid "Member Since"
|
msgid "Member Since"
|
||||||
msgstr "Mitglied seit"
|
msgstr "Mitglied seit"
|
||||||
|
|
||||||
#: src/membership/templates/membership/membership_detail.html:29
|
#: membership/templates/membership/membership_detail.html:29
|
||||||
msgid "Last Login"
|
msgid "Last Login"
|
||||||
msgstr "Letzte Anmeldung"
|
msgstr "Letzte Anmeldung"
|
||||||
|
|
||||||
#: src/membership/templates/membership/membership_detail.html:38
|
#: membership/templates/membership/membership_detail.html:38
|
||||||
#: src/membership/templates/membership/membership_detail.html:40
|
#: membership/templates/membership/membership_detail.html:40
|
||||||
msgid "Points"
|
msgid "Points"
|
||||||
msgstr "Punkte"
|
msgstr "Punkte"
|
||||||
|
|
||||||
#: src/membership/templates/membership/membership_detail.html:42
|
#: membership/templates/membership/membership_detail.html:42
|
||||||
msgid "Games Total"
|
msgid "Games Total"
|
||||||
msgstr "Spiele gesamt"
|
msgstr "Spiele gesamt"
|
||||||
|
|
||||||
#: src/membership/templates/membership/membership_detail.html:43
|
#: membership/templates/membership/membership_detail.html:43
|
||||||
#: src/membership/templates/membership/membership_detail.html:45
|
#: membership/templates/membership/membership_detail.html:45
|
||||||
msgid "Won"
|
msgid "Won"
|
||||||
msgstr "Gewonnen"
|
msgstr "Gewonnen"
|
||||||
|
|
||||||
#: src/membership/templates/membership/membership_detail.html:43
|
#: membership/templates/membership/membership_detail.html:43
|
||||||
#: src/membership/templates/membership/membership_detail.html:45
|
#: membership/templates/membership/membership_detail.html:45
|
||||||
msgid "Good"
|
msgid "Good"
|
||||||
msgstr "Gut"
|
msgstr "Gut"
|
||||||
|
|
||||||
#: src/membership/templates/membership/membership_detail.html:45
|
#: membership/templates/membership/membership_detail.html:45
|
||||||
msgid "Current Season"
|
msgid "Current Season"
|
||||||
msgstr "Aktuelle Saison"
|
msgstr "Aktuelle Saison"
|
||||||
|
|
||||||
#: src/membership/templates/membership/membership_detail.html:55
|
#: membership/templates/membership/membership_detail.html:55
|
||||||
msgid "Edit Profile"
|
msgid "Edit Profile"
|
||||||
msgstr "Profil bearbeiten"
|
msgstr "Profil bearbeiten"
|
||||||
|
|
||||||
#: src/membership/templates/membership/membership_detail.html:59
|
#: membership/templates/membership/membership_detail.html:59
|
||||||
#: src/membership/templates/registration/password_change_form.html:23
|
#: membership/templates/registration/password_change_form.html:23
|
||||||
msgid "Change Password"
|
msgid "Change Password"
|
||||||
msgstr "Passwort ändern"
|
msgstr "Passwort ändern"
|
||||||
|
|
||||||
#: src/membership/templates/membership/membership_detail.html:63
|
#: membership/templates/membership/membership_detail.html:63
|
||||||
#: src/membership/templates/membership/membership_detail.html:67
|
#: membership/templates/membership/membership_detail.html:67
|
||||||
#: src/membership/templates/membership/membership_detail.html:71
|
#: membership/templates/membership/membership_detail.html:71
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Associate with %(name)s"
|
msgid "Associate with %(name)s"
|
||||||
msgstr "Verbinde mit %(name)s"
|
msgstr "Verbinde mit %(name)s"
|
||||||
|
|
||||||
#: src/membership/templates/membership/membership_form.html:4
|
#: membership/templates/membership/membership_form.html:4
|
||||||
#: src/membership/templates/membership/membership_form.html:6
|
#: membership/templates/membership/membership_form.html:6
|
||||||
#: src/membership/templates/membership/membership_form.html:11
|
#: membership/templates/membership/membership_form.html:11
|
||||||
msgid "Edit Userprofile"
|
msgid "Edit Userprofile"
|
||||||
msgstr "Profil bearbeiten"
|
msgstr "Profil bearbeiten"
|
||||||
|
|
||||||
#: src/membership/templates/membership/membership_form.html:15
|
#: membership/templates/membership/membership_form.html:15
|
||||||
msgid "Reset"
|
msgid "Reset"
|
||||||
msgstr "Zurücksetzen"
|
msgstr "Zurücksetzen"
|
||||||
|
|
||||||
#: src/membership/templates/membership/membership_form.html:16
|
#: membership/templates/membership/membership_form.html:16
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Speichern"
|
msgstr "Speichern"
|
||||||
|
|
||||||
#: src/membership/templates/membership/register_form.html:5
|
#: membership/templates/membership/register_form.html:4
|
||||||
#: src/membership/templates/membership/register_form.html:7
|
#: membership/templates/membership/register_form.html:6
|
||||||
msgid "Registration"
|
msgid "Registration"
|
||||||
msgstr "Registrieren"
|
msgstr "Registrieren"
|
||||||
|
|
||||||
#: src/membership/templates/membership/register_form.html:9
|
#: membership/templates/membership/register_form.html:8
|
||||||
msgid ""
|
msgid ""
|
||||||
"After you've provided your account data, you'll receive\n"
|
"After you've provided your account data, you'll receive\n"
|
||||||
" an email asking you to verify your email address. You have to click on "
|
" an email asking you to verify your email address. You have to click on "
|
||||||
@@ -380,46 +378,62 @@ msgstr ""
|
|||||||
"Bitte klicke auf den Link in dieser E-Mail zur Verifizierung, erst dann ist "
|
"Bitte klicke auf den Link in dieser E-Mail zur Verifizierung, erst dann ist "
|
||||||
"die Anmeldung möglich."
|
"die Anmeldung möglich."
|
||||||
|
|
||||||
#: src/membership/templates/membership/register_form.html:20
|
#: membership/templates/membership/register_form.html:19
|
||||||
msgid "name"
|
msgid "name"
|
||||||
msgstr "Name"
|
msgstr "Name"
|
||||||
|
|
||||||
#: src/membership/templates/membership/register_form.html:26
|
#: membership/templates/membership/register_form.html:25
|
||||||
#: src/membership/templates/registration/login.html:6
|
#: membership/templates/registration/login.html:41
|
||||||
#: src/membership/templates/registration/login.html:8
|
|
||||||
#: src/membership/templates/registration/login.html:37
|
|
||||||
msgid "login"
|
msgid "login"
|
||||||
msgstr "Anmelden"
|
msgstr "Anmelden"
|
||||||
|
|
||||||
#: src/membership/templates/membership/register_form.html:39
|
#: membership/templates/membership/register_form.html:38
|
||||||
msgid "reset"
|
msgid "reset"
|
||||||
msgstr "Zurücksetzen"
|
msgstr "Zurücksetzen"
|
||||||
|
|
||||||
#: src/membership/templates/membership/register_form.html:41
|
#: membership/templates/membership/register_form.html:40
|
||||||
#: src/membership/templates/registration/login.html:31
|
#: membership/templates/registration/login.html:35
|
||||||
msgid "register"
|
msgid "register"
|
||||||
msgstr "Registrieren"
|
msgstr "Registrieren"
|
||||||
|
|
||||||
#: src/membership/templates/membership/register_successful.html:5
|
#: membership/templates/membership/register_successful.html:5
|
||||||
#: src/membership/templates/membership/register_successful.html:7
|
#: membership/templates/membership/register_successful.html:7
|
||||||
#: src/membership/templates/membership/register_successful.html:10
|
#: membership/templates/membership/register_successful.html:10
|
||||||
msgid "Activation sent"
|
msgid "Activation sent"
|
||||||
msgstr "Aktivierung wurde zugesendet"
|
msgstr "Aktivierung wurde zugesendet"
|
||||||
|
|
||||||
#: src/membership/templates/registration/login.html:15
|
#: membership/templates/registration/login.html:4
|
||||||
|
#: membership/templates/registration/login.html:11
|
||||||
|
#: membership/templates/registration/login.html:53
|
||||||
|
#: membership/templates/registration/password_reset_complete.html:13
|
||||||
|
msgid "Login"
|
||||||
|
msgstr "Anmelden"
|
||||||
|
|
||||||
|
#: membership/templates/registration/login.html:17
|
||||||
msgid "Have you already registered?"
|
msgid "Have you already registered?"
|
||||||
msgstr "Bereits registriert?"
|
msgstr "Bereits registriert?"
|
||||||
|
|
||||||
#: src/membership/templates/registration/login.html:16
|
#: membership/templates/registration/login.html:18
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid ""
|
||||||
|
#| "\n"
|
||||||
|
#| "<p>As a registered member you can:</p>\n"
|
||||||
|
#| "<ul>\n"
|
||||||
|
#| " <li>leave comments on this page.</li>\n"
|
||||||
|
#| " <li>subscribe to our Newsletter</li>\n"
|
||||||
|
#| " <li>apply to a membership to our club</li>\n"
|
||||||
|
#| " <li>club-members have access to our ranking-system</li>\n"
|
||||||
|
#| "</ul>\n"
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
"<p>As a registered member you can:</p>\n"
|
" <p>As a registered member you can:</p>\n"
|
||||||
"<ul>\n"
|
" <ul>\n"
|
||||||
" <li>leave comments on this page.</li>\n"
|
" <li>leave comments on this page.</li>\n"
|
||||||
" <li>subscribe to our Newsletter</li>\n"
|
" <li>subscribe to our Newsletter</li>\n"
|
||||||
" <li>apply to a membership to our club</li>\n"
|
" <li>apply to a membership to our club</li>\n"
|
||||||
" <li>club-members have access to our ranking-system</li>\n"
|
" <li>club-members have access to our ranking-system</li>\n"
|
||||||
"</ul>\n"
|
" </ul>\n"
|
||||||
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"<p>Als registrierter auf dieser Seite kannst du:</p>\n"
|
"<p>Als registrierter auf dieser Seite kannst du:</p>\n"
|
||||||
@@ -431,13 +445,21 @@ msgstr ""
|
|||||||
"li>\n"
|
"li>\n"
|
||||||
"</ul>\n"
|
"</ul>\n"
|
||||||
|
|
||||||
#: src/membership/templates/registration/login.html:25
|
#: membership/templates/registration/login.html:27
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid ""
|
||||||
|
#| "\n"
|
||||||
|
#| "<p>You can register here with your Google, or Facebook account.\n"
|
||||||
|
#| "If you don't own such an account, or do not want to use it for "
|
||||||
|
#| "authentication,\n"
|
||||||
|
#| "you can fill out our registration form.</p>\n"
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
"<p>You can register here with your Google, or Facebook account.\n"
|
" <p>You can register here with your Google, or Facebook account.\n"
|
||||||
"If you don't own such an account, or do not want to use it for "
|
" If you don't own such an account, or do not want to use it for\n"
|
||||||
"authentication,\n"
|
" authentication,\n"
|
||||||
"you can fill out our registration form.</p>\n"
|
" you can fill out our registration form.</p>\n"
|
||||||
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"<p>Du kannst dich auch über deinen Facebook, Google, oder Twitter Account "
|
"<p>Du kannst dich auch über deinen Facebook, Google, oder Twitter Account "
|
||||||
@@ -445,52 +467,51 @@ msgstr ""
|
|||||||
"Wenn du so etwas nicht besitzt, oder nicht verwenden möchtest, \n"
|
"Wenn du so etwas nicht besitzt, oder nicht verwenden möchtest, \n"
|
||||||
"kannst du auch das Registrierungsformular ausfüllen.</p>\n"
|
"kannst du auch das Registrierungsformular ausfüllen.</p>\n"
|
||||||
|
|
||||||
#: src/membership/templates/registration/login.html:41
|
#: membership/templates/registration/login.html:45
|
||||||
msgid "Your username and password didn't match. Please try again."
|
#, fuzzy
|
||||||
|
#| msgid "Your username and password didn't match. Please try again."
|
||||||
|
msgid ""
|
||||||
|
"Your username and password didn't match. Please try\n"
|
||||||
|
" again."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Benutzername und Passwort stimmen nicht überein. Bitte noch einmal versuchen."
|
"Benutzername und Passwort stimmen nicht überein. Bitte noch einmal versuchen."
|
||||||
|
|
||||||
#: src/membership/templates/registration/login.html:44
|
#: membership/templates/registration/login.html:50
|
||||||
msgid "Forgot your Password?"
|
msgid "Forgot your Password?"
|
||||||
msgstr "Passwort vergessen?"
|
msgstr "Passwort vergessen?"
|
||||||
|
|
||||||
#: src/membership/templates/registration/login.html:46
|
#: membership/templates/registration/login.html:60
|
||||||
#: src/membership/templates/registration/password_reset_complete.html:13
|
|
||||||
msgid "Login"
|
|
||||||
msgstr "Anmelden"
|
|
||||||
|
|
||||||
#: src/membership/templates/registration/login.html:52
|
|
||||||
msgid "or login with an existing Account"
|
msgid "or login with an existing Account"
|
||||||
msgstr "oder über einen existierenden Account anmelden"
|
msgstr "oder über einen existierenden Account anmelden"
|
||||||
|
|
||||||
#: src/membership/templates/registration/login.html:53
|
#: membership/templates/registration/login.html:63
|
||||||
msgid "Login with Facebook"
|
msgid "Login with Facebook"
|
||||||
msgstr "Über Facebook anmelden"
|
msgstr "Über Facebook anmelden"
|
||||||
|
|
||||||
#: src/membership/templates/registration/login.html:54
|
#: membership/templates/registration/login.html:66
|
||||||
msgid "Login with Twitter"
|
msgid "Login with Twitter"
|
||||||
msgstr "Über Twitter anmelden"
|
msgstr "Über Twitter anmelden"
|
||||||
|
|
||||||
#: src/membership/templates/registration/login.html:55
|
#: membership/templates/registration/login.html:69
|
||||||
msgid "Login with Google"
|
msgid "Login with Google"
|
||||||
msgstr "Über Google Anmelden"
|
msgstr "Über Google Anmelden"
|
||||||
|
|
||||||
#: src/membership/templates/registration/password_change_done.html:4
|
#: membership/templates/registration/password_change_done.html:4
|
||||||
#: src/membership/templates/registration/password_change_done.html:7
|
#: membership/templates/registration/password_change_done.html:7
|
||||||
msgid "Password change successful"
|
msgid "Password change successful"
|
||||||
msgstr "Benutzerprofil erfolgreich geändert."
|
msgstr "Benutzerprofil erfolgreich geändert."
|
||||||
|
|
||||||
#: src/membership/templates/registration/password_change_done.html:8
|
#: membership/templates/registration/password_change_done.html:8
|
||||||
msgid "Your password was changed."
|
msgid "Your password was changed."
|
||||||
msgstr "Passwort geändet"
|
msgstr "Passwort geändet"
|
||||||
|
|
||||||
#: src/membership/templates/registration/password_change_form.html:4
|
#: membership/templates/registration/password_change_form.html:4
|
||||||
#: src/membership/templates/registration/password_change_form.html:9
|
#: membership/templates/registration/password_change_form.html:9
|
||||||
#: src/membership/templates/registration/password_change_form.html:16
|
#: membership/templates/registration/password_change_form.html:16
|
||||||
msgid "Password change"
|
msgid "Password change"
|
||||||
msgstr "Passwort wechseln"
|
msgstr "Passwort wechseln"
|
||||||
|
|
||||||
#: src/membership/templates/registration/password_change_form.html:10
|
#: membership/templates/registration/password_change_form.html:10
|
||||||
msgid ""
|
msgid ""
|
||||||
"Please enter your old password, for security's sake, and then enter your new "
|
"Please enter your old password, for security's sake, and then enter your new "
|
||||||
"password twice so we can verify you typed it in correctly."
|
"password twice so we can verify you typed it in correctly."
|
||||||
@@ -498,23 +519,23 @@ msgstr ""
|
|||||||
"Zur Sicherheit bitte altes Passwort einmal und das gewünschte neue Passwort "
|
"Zur Sicherheit bitte altes Passwort einmal und das gewünschte neue Passwort "
|
||||||
"zweimal angeben, so können Tippfehler abgefangen werden."
|
"zweimal angeben, so können Tippfehler abgefangen werden."
|
||||||
|
|
||||||
#: src/membership/templates/registration/password_reset_complete.html:4
|
#: membership/templates/registration/password_reset_complete.html:4
|
||||||
#: src/membership/templates/registration/password_reset_complete.html:6
|
#: membership/templates/registration/password_reset_complete.html:6
|
||||||
#: src/membership/templates/registration/password_reset_complete.html:9
|
#: membership/templates/registration/password_reset_complete.html:9
|
||||||
msgid "Password reset complete"
|
msgid "Password reset complete"
|
||||||
msgstr "Das Rücksetzen des Passwortes ist abgeschlossen."
|
msgstr "Das Rücksetzen des Passwortes ist abgeschlossen."
|
||||||
|
|
||||||
#: src/membership/templates/registration/password_reset_complete.html:10
|
#: membership/templates/registration/password_reset_complete.html:10
|
||||||
msgid "Your password has been set. You may go ahead and log in now."
|
msgid "Your password has been set. You may go ahead and log in now."
|
||||||
msgstr "Das Passwort wurde gesetzt, Du kannst dich nun damit anmelden."
|
msgstr "Das Passwort wurde gesetzt, Du kannst dich nun damit anmelden."
|
||||||
|
|
||||||
#: src/membership/templates/registration/password_reset_confirm.html:4
|
#: membership/templates/registration/password_reset_confirm.html:4
|
||||||
#: src/membership/templates/registration/password_reset_confirm.html:6
|
#: membership/templates/registration/password_reset_confirm.html:6
|
||||||
#: src/membership/templates/registration/password_reset_confirm.html:15
|
#: membership/templates/registration/password_reset_confirm.html:15
|
||||||
msgid "Enter new password"
|
msgid "Enter new password"
|
||||||
msgstr "Neues Passwort eingeben"
|
msgstr "Neues Passwort eingeben"
|
||||||
|
|
||||||
#: src/membership/templates/registration/password_reset_confirm.html:12
|
#: membership/templates/registration/password_reset_confirm.html:12
|
||||||
msgid ""
|
msgid ""
|
||||||
"Please enter your new password twice so we can verify you typed it in "
|
"Please enter your new password twice so we can verify you typed it in "
|
||||||
"correctly."
|
"correctly."
|
||||||
@@ -522,15 +543,15 @@ msgstr ""
|
|||||||
"Bitte das Passwort zweimal eingeben, um sicher zu stellen das es korrekt "
|
"Bitte das Passwort zweimal eingeben, um sicher zu stellen das es korrekt "
|
||||||
"eingetippt wurde."
|
"eingetippt wurde."
|
||||||
|
|
||||||
#: src/membership/templates/registration/password_reset_confirm.html:18
|
#: membership/templates/registration/password_reset_confirm.html:18
|
||||||
msgid "Change my password"
|
msgid "Change my password"
|
||||||
msgstr "Passwort ändern"
|
msgstr "Passwort ändern"
|
||||||
|
|
||||||
#: src/membership/templates/registration/password_reset_confirm.html:26
|
#: membership/templates/registration/password_reset_confirm.html:26
|
||||||
msgid "Password reset unsuccessful"
|
msgid "Password reset unsuccessful"
|
||||||
msgstr "Passwort rücksetzen fehlgeschlagen"
|
msgstr "Passwort rücksetzen fehlgeschlagen"
|
||||||
|
|
||||||
#: src/membership/templates/registration/password_reset_confirm.html:27
|
#: membership/templates/registration/password_reset_confirm.html:27
|
||||||
msgid ""
|
msgid ""
|
||||||
"The password reset link was invalid, possibly because it has already been "
|
"The password reset link was invalid, possibly because it has already been "
|
||||||
"used. Please request a new password reset."
|
"used. Please request a new password reset."
|
||||||
@@ -538,22 +559,22 @@ msgstr ""
|
|||||||
"Der Link für die Rücksetzung des Passwortes war ungültig, vermutlich wurde "
|
"Der Link für die Rücksetzung des Passwortes war ungültig, vermutlich wurde "
|
||||||
"er schon einmal benutzt. Bitte eine neue Rücksetzung beantragen."
|
"er schon einmal benutzt. Bitte eine neue Rücksetzung beantragen."
|
||||||
|
|
||||||
#: src/membership/templates/registration/password_reset_done.html:4
|
#: membership/templates/registration/password_reset_done.html:4
|
||||||
#: src/membership/templates/registration/password_reset_done.html:6
|
#: membership/templates/registration/password_reset_done.html:6
|
||||||
#: src/membership/templates/registration/password_reset_done.html:12
|
#: membership/templates/registration/password_reset_done.html:12
|
||||||
msgid "Password reset successful"
|
msgid "Password reset successful"
|
||||||
msgstr "Passwort erfolgreich zurückgesetzt."
|
msgstr "Passwort erfolgreich zurückgesetzt."
|
||||||
|
|
||||||
#: src/membership/templates/registration/password_reset_form.html:4
|
#: membership/templates/registration/password_reset_form.html:4
|
||||||
#: src/membership/templates/registration/password_reset_form.html:6
|
#: membership/templates/registration/password_reset_form.html:6
|
||||||
msgid "Password reset"
|
msgid "Password reset"
|
||||||
msgstr "Passwort zurücksetzen"
|
msgstr "Passwort zurücksetzen"
|
||||||
|
|
||||||
#: src/membership/templates/registration/password_reset_form.html:21
|
#: membership/templates/registration/password_reset_form.html:21
|
||||||
msgid "Transmit"
|
msgid "Transmit"
|
||||||
msgstr "Übermitteln"
|
msgstr "Übermitteln"
|
||||||
|
|
||||||
#: src/membership/views.py:58
|
#: membership/views.py:58
|
||||||
msgid ""
|
msgid ""
|
||||||
"Activation successful. You can now login anytime with you username "
|
"Activation successful. You can now login anytime with you username "
|
||||||
"and password."
|
"and password."
|
||||||
@@ -561,11 +582,11 @@ msgstr ""
|
|||||||
"Die Aktivierung war erfolgreich. Du kannst dich ab jetzt jederzeit mit "
|
"Die Aktivierung war erfolgreich. Du kannst dich ab jetzt jederzeit mit "
|
||||||
"deinem Benutzernamen und Passwort anmelden."
|
"deinem Benutzernamen und Passwort anmelden."
|
||||||
|
|
||||||
#: src/membership/views.py:78
|
#: membership/views.py:78
|
||||||
msgid "User Profile changed successfully"
|
msgid "User Profile changed successfully"
|
||||||
msgstr "Benutzerprofil erfolgreich geändert."
|
msgstr "Benutzerprofil erfolgreich geändert."
|
||||||
|
|
||||||
#: src/membership/views.py:92
|
#: membership/views.py:92
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "No %(verbose_name)s found matching the query"
|
msgid "No %(verbose_name)s found matching the query"
|
||||||
msgstr "Kein %(verbose_name)s gefunden welche der Anfrage entspricht"
|
msgstr "Kein %(verbose_name)s gefunden welche der Anfrage entspricht"
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
from django.db import migrations
|
||||||
|
from django.db import models
|
||||||
import django.contrib.auth.models
|
import django.contrib.auth.models
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
from django.db import migrations
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
from django.db import migrations
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
from django.db import migrations
|
||||||
|
from django.db import models
|
||||||
import membership.models
|
import membership.models
|
||||||
import utils
|
import utils
|
||||||
import easy_thumbnails.fields
|
import easy_thumbnails.fields
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='membership',
|
model_name='membership',
|
||||||
name='gender',
|
name='gender',
|
||||||
field=models.CharField(blank=True, max_length=1, null=True, verbose_name='Geschlecht', choices=[(b'm', 'M\xe4nnlich'), (b'f', 'Weiblich')]),
|
field=models.CharField(blank=True, max_length=1, null=True, verbose_name='Geschlecht', choices=[
|
||||||
|
(b'm', 'M\xe4nnlich'), (b'f', 'Weiblich')]),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -65,8 +65,9 @@ class ActivationManager(models.Manager):
|
|||||||
creates a PendingActivation instance with an random activation key.
|
creates a PendingActivation instance with an random activation key.
|
||||||
@param user: the user that requests activation.
|
@param user: the user that requests activation.
|
||||||
"""
|
"""
|
||||||
salt = str(random.random())
|
salt = str(user.pk * random.random()) + \
|
||||||
activation_key = hashlib.sha1(salt + user.username).hexdigest()
|
user.registration_date.isoformat()
|
||||||
|
activation_key = hashlib.sha1(salt.encode('utf-8')).hexdigest()
|
||||||
|
|
||||||
return self.create(user=user, activation_key=activation_key)
|
return self.create(user=user, activation_key=activation_key)
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<img class="grid_4" src="" alt="" />
|
<img class="grid_4" src="" alt="" />
|
||||||
<ul class="grid_8">
|
<ul class="grid_8">
|
||||||
<li><strong>Der Aktivierungs Link ist nicht korrekt.</strong> Bitte kopiere die ganze Zeile aus der E-Mail in die Adressleiste.</li>
|
<li><strong>Der Aktivierungs Link ist nicht korrekt.</strong> Bitte kopiere die ganze Zeile aus der E-Mail in die Adressleiste.</li>
|
||||||
<li><strong>Der Aktivierungs Schlüssel ist abgelaufen.</strong> Dieser ist nur {{ expiration_days }} Tage gültig.In diesem Fall fülle das <a href="{% url 'membership-register' %}">Registrierungs Formular</a> bitte erneut aus.</p></li>
|
<li><strong>Der Aktivierungs Schlüssel ist abgelaufen.</strong> Dieser ist nur {{ expiration_days }} Tage gültig.In diesem Fall fülle das <a href="{% url 'membership-register' %}">Registrierungs Formular</a> bitte erneut aus.</li>
|
||||||
<li><strong>Der Account wurde schon aktiviert.</strong> Dies passiert sehr schnell, veruche zuerst dich mit deinen Daten <a href="{% url 'login' %}">anzumelden</a>. Sollte das nicht funktionieren, kannst du dir ja mal <a href="{% url 'password_reset' %}">neue Zugangsdaten zuschicken</a> lassen.</li>
|
<li><strong>Der Account wurde schon aktiviert.</strong> Dies passiert sehr schnell, veruche zuerst dich mit deinen Daten <a href="{% url 'login' %}">anzumelden</a>. Sollte das nicht funktionieren, kannst du dir ja mal <a href="{% url 'password_reset' %}">neue Zugangsdaten zuschicken</a> lassen.</li>
|
||||||
<li><strong>Ein obskurer Fehler ist aufgetreten.</strong> In diesem Fall, nimm bitte Kontakt mit dem Webadmin auf.</li>
|
<li><strong>Ein obskurer Fehler ist aufgetreten.</strong> In diesem Fall, nimm bitte Kontakt mit dem Webadmin auf.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
{% load i18n fieldset_extras %}
|
{% load i18n fieldset_extras %}
|
||||||
|
|
||||||
{% block title %}{% trans "Registration"%}{% endblock %}
|
{% block title %}{% trans "Registration"%}{% endblock %}
|
||||||
|
|
||||||
{% block teaser%}
|
{% block teaser%}
|
||||||
<h1>{% trans "Registration"%}</h1>
|
<h1>{% trans "Registration"%}</h1>
|
||||||
<div id="teaser_text">
|
<div id="teaser_text">
|
||||||
@@ -41,5 +42,4 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@@ -25,6 +25,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ Created on 03.10.2011
|
|||||||
@author: christian
|
@author: christian
|
||||||
"""
|
"""
|
||||||
import django.contrib.auth.views as auth_views
|
import django.contrib.auth.views as auth_views
|
||||||
from django.conf.urls import url, include
|
from django.conf.urls import include
|
||||||
|
from django.conf.urls import url
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
|
|||||||
@@ -12,10 +12,14 @@ from mahjong_ranking.models import KyuDanRanking, SeasonRanking
|
|||||||
from utils import mixins
|
from utils import mixins
|
||||||
from . import forms, models
|
from . import forms, models
|
||||||
RECAPTCHA_CSP = {
|
RECAPTCHA_CSP = {
|
||||||
'SCRIPT_SRC': ['https://www.google.com/recaptcha/', 'https://www.gstatic.com/recaptcha/'],
|
'SCRIPT_SRC': (
|
||||||
'FRAME_SRC': 'https://www.google.com/recaptcha/',
|
'https://www.google.com/recaptcha/',
|
||||||
'STYLE_SRC': "'unsafe-inline'"
|
'https://www.gstatic.com/recaptcha/'
|
||||||
|
),
|
||||||
|
'CHILD_SRC': ('https://www.google.com/recaptcha/',)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ActivateRegistration(generic.DetailView):
|
class ActivateRegistration(generic.DetailView):
|
||||||
"""
|
"""
|
||||||
Activates the Registration of an User and logs him in
|
Activates the Registration of an User and logs him in
|
||||||
|
|||||||
@@ -11,13 +11,14 @@ from .html_cleaner import HtmlCleaner
|
|||||||
from .massmailer import MassMailer
|
from .massmailer import MassMailer
|
||||||
|
|
||||||
|
|
||||||
|
CLEANER = HtmlCleaner()
|
||||||
STATUS_REJECTED, STATUS_WAITING, STATUS_PUBLISHED = -1, 0, 1
|
STATUS_REJECTED, STATUS_WAITING, STATUS_PUBLISHED = -1, 0, 1
|
||||||
STATUS_CHOICES = (
|
STATUS_CHOICES = (
|
||||||
(STATUS_REJECTED, _('Rejected')),
|
(STATUS_REJECTED, _('Rejected')),
|
||||||
(STATUS_WAITING, _('Waiting...')),
|
(STATUS_WAITING, _('Waiting...')),
|
||||||
(STATUS_PUBLISHED, _('Published')),
|
(STATUS_PUBLISHED, _('Published')),
|
||||||
)
|
)
|
||||||
cleaner = HtmlCleaner()
|
|
||||||
|
|
||||||
|
|
||||||
class OverwriteStorage(FileSystemStorage):
|
class OverwriteStorage(FileSystemStorage):
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
"""
|
|
||||||
Created on 24.11.2011
|
|
||||||
|
|
||||||
@author: christian
|
|
||||||
"""
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
from django import forms
|
|
||||||
|
|
||||||
|
|
||||||
class DateInput(forms.widgets.DateInput):
|
|
||||||
input_type = 'date'
|
|
||||||
attrs = {'class': 'dateinput'}
|
|
||||||
|
|
||||||
def __init__(self, attrs=None, **kwargs):
|
|
||||||
forms.widgets.DateInput.__init__(self,
|
|
||||||
attrs=attrs,
|
|
||||||
format='%Y-%m-%d',
|
|
||||||
**kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class NumberInput(forms.widgets.Input):
|
|
||||||
input_type = 'number'
|
|
||||||
|
|
||||||
|
|
||||||
class TimeInput(forms.widgets.Select):
|
|
||||||
|
|
||||||
def __init__(self, attrs=None, ):
|
|
||||||
timeset = datetime.datetime(2000, 1, 1, 0, 0)
|
|
||||||
choices = [('', '-------')]
|
|
||||||
while timeset < datetime.datetime(2000, 1, 2, 0, 0):
|
|
||||||
choices.append((
|
|
||||||
timeset.strftime('%H:%M:%S'),
|
|
||||||
timeset.strftime('%H:%M')
|
|
||||||
))
|
|
||||||
timeset += datetime.timedelta(minutes=30)
|
|
||||||
forms.widgets.Select.__init__(self, attrs=attrs, choices=choices)
|
|
||||||
|
|
||||||
def render(self, name, value, attrs=None, choices=()):
|
|
||||||
return forms.widgets.Select.render(self, name, value, attrs=attrs,
|
|
||||||
choices=choices)
|
|
||||||
|
|
||||||
|
|
||||||
class SplitDateTimeWidget(forms.widgets.MultiWidget):
|
|
||||||
"""
|
|
||||||
A Widget that splits datetime input into two <input type="text"> boxes.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, attrs=None, date_format='%Y-%m-%d'):
|
|
||||||
widgets = (
|
|
||||||
DateInput(attrs=attrs, format=date_format),
|
|
||||||
TimeInput(attrs=attrs)
|
|
||||||
)
|
|
||||||
super(SplitDateTimeWidget, self).__init__(widgets, attrs)
|
|
||||||
|
|
||||||
def decompress(self, value):
|
|
||||||
if value:
|
|
||||||
return [value.date(), value.time()]
|
|
||||||
return [None, None]
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
from . import base
|
|
||||||
|
|
||||||
registry = base.LookupRegistry()
|
|
||||||
|
|
||||||
|
|
||||||
def url_autodiscover():
|
|
||||||
import copy
|
|
||||||
from django.conf import settings
|
|
||||||
from django.utils.importlib import import_module
|
|
||||||
from django.utils.module_loading import module_has_submodule
|
|
||||||
|
|
||||||
for app in settings.INSTALLED_APPS:
|
|
||||||
mod = import_module(app)
|
|
||||||
# Attempt to import the app's lookups module.
|
|
||||||
try:
|
|
||||||
before_import_registry = copy.copy(registry._registry)
|
|
||||||
import_module('%s.lookups' % app)
|
|
||||||
except:
|
|
||||||
registry._registry = before_import_registry
|
|
||||||
|
|
||||||
if module_has_submodule(mod, 'lookups'):
|
|
||||||
raise
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
import re
|
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.core.serializers.json import DjangoJSONEncoder
|
|
||||||
from django.http import HttpResponse
|
|
||||||
from django.utils.encoding import smart_text, force_text
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
import json
|
|
||||||
except ImportError:
|
|
||||||
from django.utils import simplejson as json
|
|
||||||
|
|
||||||
|
|
||||||
class LookupBase(object):
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def name(cls):
|
|
||||||
app_name = cls.__module__.split('.')[-2].lower()
|
|
||||||
class_name = cls.__name__.lower()
|
|
||||||
name = u'%s-%s' % (app_name, class_name)
|
|
||||||
return name
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def url(cls):
|
|
||||||
return reverse('autocomplete-lookup', args=[cls.name()])
|
|
||||||
|
|
||||||
def get_query(self, request, term):
|
|
||||||
return []
|
|
||||||
|
|
||||||
def get_item_label(self, item):
|
|
||||||
return smart_text(item)
|
|
||||||
|
|
||||||
def get_item_id(self, item):
|
|
||||||
return smart_text(item)
|
|
||||||
|
|
||||||
def get_item_value(self, item):
|
|
||||||
return smart_text(item)
|
|
||||||
|
|
||||||
def get_item(self, value):
|
|
||||||
return value
|
|
||||||
|
|
||||||
def create_item(self, value):
|
|
||||||
raise NotImplemented()
|
|
||||||
|
|
||||||
def format_item(self, item):
|
|
||||||
return {
|
|
||||||
'id': self.get_item_id(item),
|
|
||||||
'value': self.get_item_value(item),
|
|
||||||
'label': self.get_item_label(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
def results(self, request):
|
|
||||||
term = request.GET.get('term', '')
|
|
||||||
raw_data = self.get_query(request, term)
|
|
||||||
data = []
|
|
||||||
for item in raw_data:
|
|
||||||
data.append(self.format_item(item))
|
|
||||||
content = json.dumps(data, cls=DjangoJSONEncoder, ensure_ascii=False)
|
|
||||||
return HttpResponse(content, content_type='application/json')
|
|
||||||
|
|
||||||
|
|
||||||
class LookupAlreadyRegistered(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class LookupNotRegistered(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class LookupInvalid(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class LookupRegistry(object):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self._registry = {}
|
|
||||||
|
|
||||||
def validate(self, lookup):
|
|
||||||
if not issubclass(lookup, LookupBase):
|
|
||||||
raise LookupInvalid(u'Registered lookups must inherit from the \
|
|
||||||
LookupBase class')
|
|
||||||
|
|
||||||
def register(self, lookup):
|
|
||||||
self.validate(lookup)
|
|
||||||
name = force_text(lookup.name())
|
|
||||||
if name in self._registry:
|
|
||||||
raise LookupAlreadyRegistered(u'The name %s is already registered'
|
|
||||||
% name)
|
|
||||||
self._registry[name] = lookup
|
|
||||||
|
|
||||||
def unregister(self, lookup):
|
|
||||||
self.validate(lookup)
|
|
||||||
name = force_text(lookup.name())
|
|
||||||
if name not in self._registry:
|
|
||||||
raise LookupNotRegistered(u'The name %s is not registered' % name)
|
|
||||||
del self._registry[name]
|
|
||||||
|
|
||||||
def get(self, key):
|
|
||||||
return self._registry.get(key, None)
|
|
||||||
|
|
||||||
|
|
||||||
class ModelLookup(LookupBase):
|
|
||||||
model = None
|
|
||||||
filters = {}
|
|
||||||
search_field = ''
|
|
||||||
|
|
||||||
def get_query(self, request, term):
|
|
||||||
qs = self.get_queryset()
|
|
||||||
if term and self.search_field:
|
|
||||||
qs = qs.filter(**{self.search_field: term})
|
|
||||||
return qs
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
qs = self.model._default_manager.get_query_set()
|
|
||||||
if self.filters:
|
|
||||||
qs = qs.filter(**self.filters)
|
|
||||||
return qs
|
|
||||||
|
|
||||||
def get_item_id(self, item):
|
|
||||||
return item.pk
|
|
||||||
|
|
||||||
def get_item(self, value):
|
|
||||||
item = None
|
|
||||||
if value:
|
|
||||||
try:
|
|
||||||
item = self.get_queryset().filter(pk=value)[0]
|
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
return item
|
|
||||||
|
|
||||||
def create_item(self, value):
|
|
||||||
data = {}
|
|
||||||
if self.search_field:
|
|
||||||
field_name = re.sub(r'__\w+$', '', self.search_field)
|
|
||||||
if field_name:
|
|
||||||
data = {field_name: value}
|
|
||||||
return self.model(**data)
|
|
||||||
@@ -1,250 +0,0 @@
|
|||||||
"""
|
|
||||||
Created on 08.05.2011
|
|
||||||
|
|
||||||
@author: christian
|
|
||||||
"""
|
|
||||||
import re
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.core import validators
|
|
||||||
from django.core.validators import EMPTY_VALUES
|
|
||||||
from django.forms import utils, Form, ModelForm, ValidationError
|
|
||||||
import sys
|
|
||||||
import django.forms.fields
|
|
||||||
from django.utils.translation import gettext as _
|
|
||||||
|
|
||||||
|
|
||||||
from . import widgets
|
|
||||||
|
|
||||||
|
|
||||||
class Html5Mixin(object):
|
|
||||||
|
|
||||||
def widget_attrs(self, widget):
|
|
||||||
"""
|
|
||||||
Overwrites the standard Widget Attributes to add some HTML5 Stuff
|
|
||||||
:param widget: A Widget Object
|
|
||||||
"""
|
|
||||||
attrs = super(Html5Mixin, self).widget_attrs(widget)
|
|
||||||
if self.required and not isinstance(widget, widgets.CheckboxInput):
|
|
||||||
attrs['required'] = 'required'
|
|
||||||
if self.help_text:
|
|
||||||
attrs['title'] = self.help_text
|
|
||||||
attrs['placeholder'] = self.help_text
|
|
||||||
if hasattr(self, 'placeholder'):
|
|
||||||
attrs['placeholder'] = self.placeholder
|
|
||||||
|
|
||||||
if self.accesskey:
|
|
||||||
attrs['accesskey'] = self.accesskey
|
|
||||||
return attrs
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
self.accesskey = kwargs.pop('accesskey', None)
|
|
||||||
super(Html5Mixin, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class AutoCompleteSelectField(Html5Mixin, django.forms.Field):
|
|
||||||
widget = widgets.AutoCompleteSelectWidget
|
|
||||||
default_error_messages = {
|
|
||||||
'invalid_choice': _(u'Select a valid choice. That choice is not one \
|
|
||||||
of the available choices.'),
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, lookup_class, *args, **kwargs):
|
|
||||||
self.lookup_class = lookup_class
|
|
||||||
self.allow_new = kwargs.pop('allow_new', False)
|
|
||||||
if not kwargs['widget']:
|
|
||||||
kwargs['widget'] = self.widget(lookup_class,
|
|
||||||
allow_new=self.allow_new)
|
|
||||||
super(AutoCompleteSelectField, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def to_python(self, value):
|
|
||||||
if value in EMPTY_VALUES:
|
|
||||||
return None
|
|
||||||
if isinstance(value, list):
|
|
||||||
# Input comes from an AutoComplete widget. It's two
|
|
||||||
# components: text and id
|
|
||||||
if len(value) != 2:
|
|
||||||
raise django.forms.ValidationError(
|
|
||||||
self.error_messages['invalid_choice'])
|
|
||||||
lookup = self.lookup_class()
|
|
||||||
if value[1] in EMPTY_VALUES:
|
|
||||||
if not self.allow_new:
|
|
||||||
if value[0]:
|
|
||||||
raise django.forms.ValidationError(
|
|
||||||
self.error_messages['invalid_choice'])
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
value = lookup.create_item(value[0])
|
|
||||||
else:
|
|
||||||
value = lookup.get_item(value[1])
|
|
||||||
if value is None:
|
|
||||||
raise django.forms.ValidationError(
|
|
||||||
self.error_messages['invalid_choice'])
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
class AutoComboboxSelectField(AutoCompleteSelectField):
|
|
||||||
widget = widgets.AutoComboboxSelectWidget
|
|
||||||
|
|
||||||
|
|
||||||
class AutoCompleteSelectMultipleField(Html5Mixin, django.forms.Field):
|
|
||||||
widget = widgets.AutoCompleteSelectMultipleWidget
|
|
||||||
|
|
||||||
default_error_messages = {
|
|
||||||
'invalid_choice': _(u'Select a valid choice. \
|
|
||||||
That choice is not one of the available choices.'),
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, lookup_class, *args, **kwargs):
|
|
||||||
self.lookup_class = lookup_class
|
|
||||||
kwargs['widget'] = self.widget(lookup_class)
|
|
||||||
self.attrs['autofocus'] = 'autofocus'
|
|
||||||
super(AutoCompleteSelectMultipleField, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def to_python(self, value):
|
|
||||||
if value in EMPTY_VALUES:
|
|
||||||
return None
|
|
||||||
lookup = self.lookup_class()
|
|
||||||
items = []
|
|
||||||
for v in value:
|
|
||||||
if v not in EMPTY_VALUES:
|
|
||||||
item = lookup.get_item(v)
|
|
||||||
if item is None:
|
|
||||||
raise django.forms.ValidationError(
|
|
||||||
self.error_messages['invalid_choice'])
|
|
||||||
items.append(item)
|
|
||||||
return items
|
|
||||||
|
|
||||||
|
|
||||||
class AutoComboboxSelectMultipleField(AutoCompleteSelectMultipleField):
|
|
||||||
widget = widgets.AutoComboboxSelectMultipleWidget
|
|
||||||
|
|
||||||
|
|
||||||
class BooleanField(Html5Mixin, django.forms.BooleanField):
|
|
||||||
widget = widgets.CheckboxInput
|
|
||||||
|
|
||||||
|
|
||||||
class CharField(Html5Mixin, django.forms.CharField):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class DateField(Html5Mixin, django.forms.fields.DateField):
|
|
||||||
placeholder = _('yyyy-mm-dd')
|
|
||||||
widget = widgets.DateInput
|
|
||||||
|
|
||||||
|
|
||||||
class DateTimeField(Html5Mixin, django.forms.fields.DateTimeField):
|
|
||||||
widget = widgets.DateTimeInput
|
|
||||||
|
|
||||||
|
|
||||||
class EmailField(Html5Mixin, django.forms.fields.EmailField):
|
|
||||||
widget = widgets.EmailInput
|
|
||||||
|
|
||||||
|
|
||||||
class FileField(Html5Mixin, django.forms.fields.FileField):
|
|
||||||
widget = widgets.NumberInput
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class FloatField(Html5Mixin, django.forms.fields.FloatField):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class HiddenInput(Html5Mixin, django.forms.HiddenInput):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class IntegerField(Html5Mixin, django.forms.fields.IntegerField):
|
|
||||||
widget = widgets.NumberInput
|
|
||||||
|
|
||||||
def widget_attrs(self, widget):
|
|
||||||
attrs = super(IntegerField, self).widget_attrs(widget)
|
|
||||||
if isinstance(widget, widgets.NumberInput):
|
|
||||||
if self.min_value is not None:
|
|
||||||
attrs['min'] = self.min_value
|
|
||||||
if self.max_value is not None:
|
|
||||||
attrs['max'] = self.max_value
|
|
||||||
return attrs
|
|
||||||
|
|
||||||
|
|
||||||
class ModelChoiceField(Html5Mixin, django.forms.ModelChoiceField):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class PasswordInput(Html5Mixin, django.forms.PasswordInput):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class PhoneField(Html5Mixin, django.forms.CharField):
|
|
||||||
widget = widgets.PhoneInput
|
|
||||||
|
|
||||||
def __init__(self, regex=None, max_length=None, min_length=None,
|
|
||||||
error_message=None, *args, **kwargs):
|
|
||||||
super(PhoneField, self).__init__(max_length, min_length,
|
|
||||||
*args, **kwargs)
|
|
||||||
self._set_regex(u'^[0-9+-/ ]+$')
|
|
||||||
|
|
||||||
def _get_regex(self):
|
|
||||||
return self._regex
|
|
||||||
|
|
||||||
def _set_regex(self, regex=u'^[0-9+-/ ]+$'):
|
|
||||||
regex = re.compile(regex, re.UNICODE)
|
|
||||||
self._regex = regex
|
|
||||||
if hasattr(self, '_regex_validator') \
|
|
||||||
and self._regex_validator in self.validators:
|
|
||||||
self.validators.remove(self._regex_validator)
|
|
||||||
self._regex_validator = validators.RegexValidator(regex=regex)
|
|
||||||
self.validators.append(self._regex_validator)
|
|
||||||
|
|
||||||
regex = property(_get_regex, _set_regex)
|
|
||||||
|
|
||||||
|
|
||||||
class ReCaptchaField(django.forms.fields.CharField):
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
self.widget = widgets.ReCaptchaInput
|
|
||||||
self.required = True
|
|
||||||
super(ReCaptchaField, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def get_remote_ip(self):
|
|
||||||
f = sys._getframe()
|
|
||||||
while f:
|
|
||||||
if 'request' in f.f_locals:
|
|
||||||
request = f.f_locals['request']
|
|
||||||
if request:
|
|
||||||
remote_ip = request.META.get('REMOTE_ADDR', None)
|
|
||||||
forwarded_ip = request.META.get('HTTP_X_FORWARDED_FOR', None)
|
|
||||||
return forwarded_ip or remote_ip
|
|
||||||
f = f.f_back
|
|
||||||
|
|
||||||
def clean(self, values):
|
|
||||||
""" test the google recaptcha"""
|
|
||||||
import json, urllib, urllib2
|
|
||||||
|
|
||||||
url = "https://www.google.com/recaptcha/api/siteverify"
|
|
||||||
challenge_value = values[0]
|
|
||||||
data = urllib.urlencode({
|
|
||||||
'secret': settings.RECAPTCHA_PRIVATE_KEY,
|
|
||||||
'response': values[1],
|
|
||||||
'remoteip': self.get_remote_ip()
|
|
||||||
})
|
|
||||||
req = urllib2.Request(url, data)
|
|
||||||
response = urllib2.urlopen(req)
|
|
||||||
result = json.loads(response.read())
|
|
||||||
|
|
||||||
# result["success"] will be True on a success
|
|
||||||
if not result["success"]:
|
|
||||||
raise ValidationError(
|
|
||||||
_(u'Only humans are allowed to submit this form.'))
|
|
||||||
|
|
||||||
|
|
||||||
class RegexField(Html5Mixin, django.forms.RegexField):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class SlugField(Html5Mixin, django.forms.SlugField):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class URLField(Html5Mixin, django.forms.fields.URLField):
|
|
||||||
widget = widgets.URLInput
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
"""
|
|
||||||
Created on 08.05.2011
|
|
||||||
|
|
||||||
@author: christian
|
|
||||||
"""
|
|
||||||
from django.db import models
|
|
||||||
from django.db.models import ForeignKey # @UnusedImport
|
|
||||||
from django.utils import six
|
|
||||||
|
|
||||||
from . import forms, widgets
|
|
||||||
|
|
||||||
|
|
||||||
class BooleanField(models.BooleanField):
|
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
|
||||||
defaults = {'form_class': forms.BooleanField}
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return super(BooleanField, self).formfield(**defaults)
|
|
||||||
|
|
||||||
|
|
||||||
class CharField(models.CharField):
|
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
|
||||||
defaults = {'form_class': forms.CharField}
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return super(CharField, self).formfield(**defaults)
|
|
||||||
|
|
||||||
|
|
||||||
class DateField(models.DateField):
|
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
|
||||||
defaults = {
|
|
||||||
'form_class': forms.DateField}
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return super(DateField, self).formfield(**defaults)
|
|
||||||
|
|
||||||
|
|
||||||
class DateTimeField(models.DateTimeField):
|
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
|
||||||
defaults = {'form_class': forms.DateTimeField}
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return super(DateTimeField, self).formfield(**defaults)
|
|
||||||
|
|
||||||
|
|
||||||
class EmailField(models.EmailField):
|
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
|
||||||
defaults = {'form_class': forms.EmailField}
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return super(EmailField, self).formfield(**defaults)
|
|
||||||
|
|
||||||
|
|
||||||
class FileField(models.FileField):
|
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
|
||||||
defaults = {'form_class': forms.FileField}
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return super(FileField, self).formfield(**defaults)
|
|
||||||
|
|
||||||
|
|
||||||
class ForeignKey(models.ForeignKey):
|
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
|
||||||
db = kwargs.pop('using', None)
|
|
||||||
if isinstance(self.rel.to, six.string_types):
|
|
||||||
raise ValueError("Cannot create form field for %r yet, because "
|
|
||||||
"its related model %r has not been loaded yet" %
|
|
||||||
(self.name, self.rel.to))
|
|
||||||
queryset = self.rel.to._default_manager.using(db)
|
|
||||||
queryset = queryset.complex_filter(self.rel.limit_choices_to)
|
|
||||||
defaults = {
|
|
||||||
'form_class': forms.ModelChoiceField,
|
|
||||||
'queryset': queryset,
|
|
||||||
'to_field_name': self.rel.field_name,
|
|
||||||
}
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return super(ForeignKey, self).formfield(**defaults)
|
|
||||||
|
|
||||||
|
|
||||||
class ImageField(models.ImageField):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class IntegerField(models.IntegerField):
|
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
|
||||||
defaults = {'form_class': forms.IntegerField}
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return super(IntegerField, self).formfield(**defaults)
|
|
||||||
|
|
||||||
|
|
||||||
class NullBooleanField(models.NullBooleanField):
|
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
|
||||||
defaults = {'form_class': forms.BooleanField}
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return super(NullBooleanField, self).formfield(**defaults)
|
|
||||||
|
|
||||||
|
|
||||||
class PositiveSmallIntegerField(models.PositiveSmallIntegerField):
|
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
|
||||||
defaults = {
|
|
||||||
'form_class': forms.IntegerField,
|
|
||||||
'min_value': 0,
|
|
||||||
'max_value': 32767
|
|
||||||
}
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return super(PositiveSmallIntegerField, self).formfield(**defaults)
|
|
||||||
|
|
||||||
|
|
||||||
class PositiveIntegerField(models.IntegerField):
|
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
|
||||||
defaults = {
|
|
||||||
'form_class': forms.IntegerField,
|
|
||||||
'min_value': 0
|
|
||||||
}
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return super(PositiveIntegerField, self).formfield(**defaults)
|
|
||||||
|
|
||||||
|
|
||||||
class SlugField(models.SlugField):
|
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
|
||||||
defaults = {'form_class': forms.SlugField}
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return super(SlugField, self).formfield(**defaults)
|
|
||||||
|
|
||||||
|
|
||||||
class TextField(models.TextField):
|
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
|
||||||
defaults = {
|
|
||||||
'form_class': forms.CharField,
|
|
||||||
'widget': widgets.Textarea
|
|
||||||
}
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return super(TextField, self).formfield(**defaults)
|
|
||||||
|
|
||||||
|
|
||||||
class URLField(models.URLField):
|
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
|
||||||
defaults = {'form_class': forms.URLField}
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return super(URLField, self).formfield(**defaults)
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
"""
|
|
||||||
Created on 05.08.2011
|
|
||||||
|
|
||||||
@author: christian
|
|
||||||
"""
|
|
||||||
from django.http import Http404
|
|
||||||
|
|
||||||
from . import registry
|
|
||||||
|
|
||||||
|
|
||||||
def get_lookup(request, lookup_name):
|
|
||||||
lookup_cls = registry.get(lookup_name)
|
|
||||||
if lookup_cls is None:
|
|
||||||
raise Http404(u'Lookup %s not found' % lookup_name)
|
|
||||||
lookup = lookup_cls()
|
|
||||||
return lookup.results(request)
|
|
||||||
@@ -1,324 +0,0 @@
|
|||||||
"""
|
|
||||||
Created on 08.05.2011
|
|
||||||
|
|
||||||
@author: christian
|
|
||||||
"""
|
|
||||||
from django.conf import settings
|
|
||||||
from django.forms import widgets
|
|
||||||
from django.forms.utils import flatatt
|
|
||||||
from django.utils import formats
|
|
||||||
from django.utils.encoding import force_text
|
|
||||||
from django.utils.html import conditional_escape
|
|
||||||
from django.utils.http import urlencode
|
|
||||||
from django.utils.safestring import mark_safe
|
|
||||||
|
|
||||||
|
|
||||||
class AutoCompleteWidget(widgets.TextInput):
|
|
||||||
|
|
||||||
def __init__(self, lookup_class, attrs=None, *args, **kwargs):
|
|
||||||
self.lookup_class = lookup_class
|
|
||||||
self.allow_new = kwargs.pop('allow_new', False)
|
|
||||||
self.qs = {}
|
|
||||||
super(AutoCompleteWidget, self).__init__(*args, **kwargs)
|
|
||||||
if attrs is not None:
|
|
||||||
self.attrs = attrs.copy()
|
|
||||||
else:
|
|
||||||
self.attrs = {}
|
|
||||||
|
|
||||||
def update_query_parameters(self, qs_dict):
|
|
||||||
self.qs.update(qs_dict)
|
|
||||||
|
|
||||||
def build_attrs(self, extra_attrs=None, **kwargs):
|
|
||||||
attrs = super(AutoCompleteWidget, self).build_attrs(extra_attrs,
|
|
||||||
**kwargs) # @IgnorePep8
|
|
||||||
url = self.lookup_class.url()
|
|
||||||
if self.qs:
|
|
||||||
url = '%s?%s' % (url, urlencode(self.qs))
|
|
||||||
attrs[u'data-selectable-url'] = url
|
|
||||||
attrs[u'data-selectable-type'] = 'text'
|
|
||||||
attrs[u'data-selectable-allow-new'] = str(self.allow_new).lower()
|
|
||||||
return attrs
|
|
||||||
|
|
||||||
|
|
||||||
class AutoComboboxWidget(AutoCompleteWidget):
|
|
||||||
|
|
||||||
def build_attrs(self, extra_attrs=None, **kwargs):
|
|
||||||
attrs = super(AutoComboboxWidget, self).build_attrs(extra_attrs,
|
|
||||||
**kwargs) # @IgnorePep8
|
|
||||||
attrs[u'data-selectable-type'] = 'combobox'
|
|
||||||
return attrs
|
|
||||||
|
|
||||||
|
|
||||||
class DateInput(widgets.DateInput):
|
|
||||||
input_type = 'date'
|
|
||||||
attrs = {'class': 'dateinput'}
|
|
||||||
|
|
||||||
def __init__(self, attrs=None, date_format='%Y-%m-%d'):
|
|
||||||
super(DateInput, self).__init__(attrs)
|
|
||||||
if date_format:
|
|
||||||
self.format = date_format
|
|
||||||
self.manual_format = True
|
|
||||||
else:
|
|
||||||
self.format = formats.get_format('DATE_INPUT_FORMATS')[0]
|
|
||||||
self.manual_format = False
|
|
||||||
|
|
||||||
|
|
||||||
class DateTimeInput(widgets.MultiWidget):
|
|
||||||
"""
|
|
||||||
A Widget that splits datetime input into two <input type="text"> boxes.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, attrs=None, date_format='%Y-%m-%d',
|
|
||||||
time_format='%H:%M'): # @IgnorePep8
|
|
||||||
widgets = (
|
|
||||||
DateInput(attrs=attrs, date_format=date_format),
|
|
||||||
TimeInput(attrs=attrs, time_format=time_format)
|
|
||||||
)
|
|
||||||
super(DateTimeInput, self).__init__(widgets, attrs)
|
|
||||||
|
|
||||||
def decompress(self, value):
|
|
||||||
if value:
|
|
||||||
return [value.date(), value.time()]
|
|
||||||
return [None, None]
|
|
||||||
|
|
||||||
|
|
||||||
class CheckboxInput(widgets.CheckboxInput):
|
|
||||||
input_type = 'checkbox'
|
|
||||||
is_checkbox = True
|
|
||||||
|
|
||||||
def render(self, name, value, attrs=None):
|
|
||||||
final_attrs = self.build_attrs(attrs, type='checkbox', name=name)
|
|
||||||
title = force_text(self.attrs.get('title', ''))
|
|
||||||
try:
|
|
||||||
result = self.check_test(value)
|
|
||||||
except: # Silently catch exceptions
|
|
||||||
result = False
|
|
||||||
if result:
|
|
||||||
final_attrs['checked'] = 'checked'
|
|
||||||
if not (
|
|
||||||
value is True or value is False or value is None or value == ''): # @IgnorePep8
|
|
||||||
# Only add the 'value' attribute if a value is non-empty.
|
|
||||||
final_attrs['value'] = force_text(value)
|
|
||||||
|
|
||||||
return mark_safe(u'<input%s /> %s' % (flatatt(final_attrs), title))
|
|
||||||
|
|
||||||
|
|
||||||
class EmailInput(widgets.TextInput):
|
|
||||||
input_type = 'email'
|
|
||||||
|
|
||||||
|
|
||||||
class NumberInput(widgets.TextInput):
|
|
||||||
input_type = 'number'
|
|
||||||
|
|
||||||
def __init__(self, attrs=None):
|
|
||||||
widgets.Input.__init__(self, attrs=attrs)
|
|
||||||
|
|
||||||
|
|
||||||
class PhoneInput(widgets.TextInput):
|
|
||||||
input_type = 'tel'
|
|
||||||
|
|
||||||
|
|
||||||
class RangeInput(widgets.TextInput):
|
|
||||||
input_type = 'range'
|
|
||||||
|
|
||||||
|
|
||||||
class ReCaptchaInput(widgets.Widget):
|
|
||||||
"""
|
|
||||||
Der HTML Code von Googles ReCaptcha als Form Widget
|
|
||||||
"""
|
|
||||||
recaptcha_challenge_name = 'g-recaptcha-response'
|
|
||||||
recaptcha_response_name = 'g-recaptcha-response'
|
|
||||||
|
|
||||||
def render(self, name, value, attrs=None):
|
|
||||||
html_code = u'''
|
|
||||||
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
|
|
||||||
<div class="g-recaptcha" data-sitekey="{public_key}" data-size="compact"></div>
|
|
||||||
'''.format(public_key=settings.RECAPTCHA_PUBLIC_KEY)
|
|
||||||
return mark_safe(html_code)
|
|
||||||
|
|
||||||
def value_from_datadict(self, data, files, name):
|
|
||||||
return [data.get(self.recaptcha_challenge_name, None),
|
|
||||||
data.get(self.recaptcha_response_name, None)]
|
|
||||||
|
|
||||||
|
|
||||||
class SelectableMultiWidget(widgets.MultiWidget):
|
|
||||||
|
|
||||||
def update_query_parameters(self, qs_dict):
|
|
||||||
self.widgets[0].update_query_parameters(qs_dict)
|
|
||||||
|
|
||||||
|
|
||||||
class Textarea(widgets.Widget):
|
|
||||||
|
|
||||||
def __init__(self, attrs=None):
|
|
||||||
# The 'rows' and 'cols' attributes are required for HTML correctness.
|
|
||||||
default_attrs = {'cols': '40', 'rows': '10'}
|
|
||||||
if attrs:
|
|
||||||
default_attrs.update(attrs)
|
|
||||||
super(Textarea, self).__init__(default_attrs)
|
|
||||||
|
|
||||||
def render(self, name, value, attrs=None):
|
|
||||||
value = '' if value is None else value
|
|
||||||
final_attrs = self.build_attrs(attrs, name=name)
|
|
||||||
return mark_safe(u'<textarea%s>%s</textarea>' % (flatatt(final_attrs),
|
|
||||||
conditional_escape(
|
|
||||||
force_text(
|
|
||||||
value))))
|
|
||||||
|
|
||||||
|
|
||||||
class TextInput(widgets.TextInput):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class TimeInput(widgets.TimeInput):
|
|
||||||
input_type = 'time'
|
|
||||||
|
|
||||||
def __init__(self, attrs=None, time_format='%H:%M'):
|
|
||||||
default_attrs = {'maxlength': 5, 'size': 5}
|
|
||||||
if attrs:
|
|
||||||
default_attrs.update(attrs)
|
|
||||||
super(TimeInput, self).__init__(default_attrs)
|
|
||||||
|
|
||||||
if time_format:
|
|
||||||
self.format = time_format
|
|
||||||
self.manual_format = True
|
|
||||||
else:
|
|
||||||
self.format = formats.get_format('TIME_INPUT_FORMATS')[0]
|
|
||||||
self.manual_format = False
|
|
||||||
|
|
||||||
|
|
||||||
class URLInput(widgets.Input):
|
|
||||||
input_type = 'url'
|
|
||||||
|
|
||||||
|
|
||||||
class LookupMultipleHiddenInput(widgets.MultipleHiddenInput):
|
|
||||||
|
|
||||||
def __init__(self, lookup_class, *args, **kwargs):
|
|
||||||
self.lookup_class = lookup_class
|
|
||||||
super(LookupMultipleHiddenInput, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def render(self, name, value, attrs=None, choices=()):
|
|
||||||
lookup = self.lookup_class()
|
|
||||||
value = [] if value is None else value
|
|
||||||
final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
|
|
||||||
id_ = final_attrs.get('id', None)
|
|
||||||
inputs = []
|
|
||||||
model = getattr(self.lookup_class, 'model', None)
|
|
||||||
for i, v in enumerate(value):
|
|
||||||
item = None
|
|
||||||
if model and isinstance(v, model):
|
|
||||||
item = v
|
|
||||||
v = lookup.get_item_id(item)
|
|
||||||
input_attrs = dict(value=force_text(v), **final_attrs)
|
|
||||||
if id_:
|
|
||||||
# An ID attribute was given. Add a numeric index as a suffix
|
|
||||||
# so that the inputs don't all have the same ID attribute.
|
|
||||||
input_attrs['id'] = '%s_%s' % (id_, i)
|
|
||||||
if v:
|
|
||||||
item = item or lookup.get_item(v)
|
|
||||||
input_attrs['title'] = lookup.get_item_value(item)
|
|
||||||
inputs.append(u'<input%s />' % flatatt(input_attrs))
|
|
||||||
return mark_safe(u'\n'.join(inputs))
|
|
||||||
|
|
||||||
def build_attrs(self, extra_attrs=None, **kwargs):
|
|
||||||
attrs = super(LookupMultipleHiddenInput, self).build_attrs(extra_attrs,
|
|
||||||
**kwargs) # @IgnorePep8
|
|
||||||
attrs[u'data-selectable-type'] = 'hidden-multiple'
|
|
||||||
return attrs
|
|
||||||
|
|
||||||
|
|
||||||
class AutoCompleteSelectMultipleWidget(SelectableMultiWidget):
|
|
||||||
|
|
||||||
def __init__(self, lookup_class, *args, **kwargs):
|
|
||||||
self.lookup_class = lookup_class
|
|
||||||
widgets = [
|
|
||||||
AutoCompleteWidget(lookup_class, allow_new=False,
|
|
||||||
attrs={u'data-selectable-multiple': 'true'}),
|
|
||||||
LookupMultipleHiddenInput(lookup_class)
|
|
||||||
]
|
|
||||||
super(AutoCompleteSelectMultipleWidget, self).__init__(widgets, *args,
|
|
||||||
**kwargs) # @IgnorePep8
|
|
||||||
|
|
||||||
def value_from_datadict(self, data, files, name):
|
|
||||||
return self.widgets[1].value_from_datadict(data, files, name + '_1')
|
|
||||||
|
|
||||||
def render(self, name, value, attrs=None):
|
|
||||||
if value and not hasattr(value, '__iter__'):
|
|
||||||
value = [value]
|
|
||||||
value = [u'', value]
|
|
||||||
return super(AutoCompleteSelectMultipleWidget, self).render(name, value,
|
|
||||||
attrs) # @IgnorePep8
|
|
||||||
|
|
||||||
|
|
||||||
class AutoComboboxSelectMultipleWidget(SelectableMultiWidget):
|
|
||||||
|
|
||||||
def __init__(self, lookup_class, *args, **kwargs):
|
|
||||||
self.lookup_class = lookup_class
|
|
||||||
widgets = [
|
|
||||||
AutoComboboxWidget(lookup_class, allow_new=False,
|
|
||||||
attrs={u'data-selectable-multiple': 'true'}),
|
|
||||||
LookupMultipleHiddenInput(lookup_class)
|
|
||||||
]
|
|
||||||
super(AutoComboboxSelectMultipleWidget, self).__init__(widgets, *args,
|
|
||||||
**kwargs) # @IgnorePep8
|
|
||||||
|
|
||||||
def value_from_datadict(self, data, files, name):
|
|
||||||
return self.widgets[1].value_from_datadict(data, files, name + '_1')
|
|
||||||
|
|
||||||
def render(self, name, value, attrs=None):
|
|
||||||
if value and not hasattr(value, '__iter__'):
|
|
||||||
value = [value]
|
|
||||||
value = [u'', value]
|
|
||||||
return super(AutoComboboxSelectMultipleWidget, self).render(name, value,
|
|
||||||
attrs) # @IgnorePep8
|
|
||||||
|
|
||||||
|
|
||||||
class AutoCompleteSelectWidget(SelectableMultiWidget):
|
|
||||||
|
|
||||||
def __init__(self, lookup_class, *args, **kwargs):
|
|
||||||
self.lookup_class = lookup_class
|
|
||||||
self.allow_new = kwargs.pop('allow_new', False)
|
|
||||||
widget_set = [
|
|
||||||
AutoCompleteWidget(lookup_class, allow_new=self.allow_new),
|
|
||||||
widgets.HiddenInput(attrs={u'data-selectable-type': 'hidden'})
|
|
||||||
]
|
|
||||||
super(AutoCompleteSelectWidget, self).__init__(widget_set, *args,
|
|
||||||
**kwargs) # @IgnorePep8
|
|
||||||
|
|
||||||
def decompress(self, value):
|
|
||||||
if value:
|
|
||||||
lookup = self.lookup_class()
|
|
||||||
model = getattr(self.lookup_class, 'model', None)
|
|
||||||
if model and isinstance(value, model):
|
|
||||||
item = value
|
|
||||||
value = lookup.get_item_id(item)
|
|
||||||
else:
|
|
||||||
item = lookup.get_item(value)
|
|
||||||
item_value = lookup.get_item_value(item)
|
|
||||||
return [item_value, value]
|
|
||||||
return [None, None]
|
|
||||||
|
|
||||||
|
|
||||||
class AutoComboboxSelectWidget(SelectableMultiWidget):
|
|
||||||
|
|
||||||
def __init__(self, lookup_class, *args, **kwargs):
|
|
||||||
self.lookup_class = lookup_class
|
|
||||||
self.allow_new = kwargs.pop('allow_new', False)
|
|
||||||
widget_set = [
|
|
||||||
AutoComboboxWidget(lookup_class, allow_new=self.allow_new),
|
|
||||||
widgets.HiddenInput(attrs={u'data-selectable-type': 'hidden'})
|
|
||||||
]
|
|
||||||
super(AutoComboboxSelectWidget, self).__init__(widget_set, *args,
|
|
||||||
**kwargs) # @IgnorePep8
|
|
||||||
|
|
||||||
def decompress(self, value):
|
|
||||||
if value:
|
|
||||||
lookup = self.lookup_class()
|
|
||||||
model = getattr(self.lookup_class, 'model', None)
|
|
||||||
if model and isinstance(value, model):
|
|
||||||
item = value
|
|
||||||
value = lookup.get_item_id(item)
|
|
||||||
else:
|
|
||||||
item = lookup.get_item(value)
|
|
||||||
item_value = lookup.get_item_value(item)
|
|
||||||
return [item_value, value]
|
|
||||||
return [None, None]
|
|
||||||
@@ -4,10 +4,14 @@ Created on 19.10.2011
|
|||||||
@author: christian
|
@author: christian
|
||||||
"""
|
"""
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
#TODO: Nach BeatutifulSoup 4 convertieren
|
# TODO: Nach BeatutifulSoup 4 convertieren
|
||||||
|
|
||||||
|
|
||||||
class HtmlCleaner(object):
|
class HtmlCleaner(object):
|
||||||
|
"""
|
||||||
|
Tries to clean up HTML code, to reomve all possibilities of an XSS Attack
|
||||||
|
and unwanted inline Javascript and CSS.
|
||||||
|
"""
|
||||||
ACCEPTABLE_ELEMENTS = ['a', 'abbr', 'acronym', 'address', 'area', 'b',
|
ACCEPTABLE_ELEMENTS = ['a', 'abbr', 'acronym', 'address', 'area', 'b',
|
||||||
'big', 'blockquote', 'br', 'button', 'caption',
|
'big', 'blockquote', 'br', 'button', 'caption',
|
||||||
'center', 'cite',
|
'center', 'cite',
|
||||||
@@ -23,7 +27,7 @@ class HtmlCleaner(object):
|
|||||||
'tfoot', 'th',
|
'tfoot', 'th',
|
||||||
'thead', 'tr', 'tt', 'u', 'ul', 'var']
|
'thead', 'tr', 'tt', 'u', 'ul', 'var']
|
||||||
|
|
||||||
ACCEPTABELE_ATTRIBUTES = [
|
ACCEPTABLE_ATTRIBUTES = [
|
||||||
'abbr', 'accept', 'accept-charset', 'accesskey',
|
'abbr', 'accept', 'accept-charset', 'accesskey',
|
||||||
'action', 'align', 'class', 'alt', 'axis',
|
'action', 'align', 'class', 'alt', 'axis',
|
||||||
'char', 'charoff', 'charset', 'checked', 'cite', 'clear', 'cols',
|
'char', 'charoff', 'charset', 'checked', 'cite', 'clear', 'cols',
|
||||||
@@ -35,17 +39,28 @@ class HtmlCleaner(object):
|
|||||||
'span', 'src', 'start', 'summary', 'tabindex', 'target', 'title',
|
'span', 'src', 'start', 'summary', 'tabindex', 'target', 'title',
|
||||||
'type', 'usemap', 'valign', 'value', 'vspace', 'width']
|
'type', 'usemap', 'valign', 'value', 'vspace', 'width']
|
||||||
|
|
||||||
counter = 1
|
|
||||||
tag_removed = False
|
tag_removed = False
|
||||||
|
|
||||||
def clean_attributes(self, tag):
|
def clean_attributes(self, tag):
|
||||||
|
"""
|
||||||
|
reomves all attributes from an element that arenÄt whitelisted.
|
||||||
|
:param tag: an BeautifulSoup Tag element that should be scrubbed
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
for attr in list(tag.attrs.keys()):
|
for attr in list(tag.attrs.keys()):
|
||||||
if attr not in self.ACCEPTABELE_ATTRIBUTES:
|
if attr not in self.ACCEPTABLE_ATTRIBUTES:
|
||||||
del tag[attr]
|
del tag[attr]
|
||||||
elif tag[attr].count('script:'):
|
elif tag[attr].count('script:'):
|
||||||
del tag[attr]
|
del tag[attr]
|
||||||
|
|
||||||
def clean_tag(self, tag):
|
def clean_tag(self, tag):
|
||||||
|
"""
|
||||||
|
Removes the entire tag with all its content, when its not on the
|
||||||
|
whitelist. If the tag is acceptable it will be passed to
|
||||||
|
clean_attributes
|
||||||
|
:param tag: BeautifulSoup Tag element that should be scrubbed
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
if tag.name not in self.ACCEPTABLE_ELEMENTS:
|
if tag.name not in self.ACCEPTABLE_ELEMENTS:
|
||||||
tag.extract() # remove the bad ones
|
tag.extract() # remove the bad ones
|
||||||
self.tag_removed = True
|
self.tag_removed = True
|
||||||
@@ -55,12 +70,12 @@ class HtmlCleaner(object):
|
|||||||
def clean_html(self, fragment=''):
|
def clean_html(self, fragment=''):
|
||||||
"""
|
"""
|
||||||
Reparses and cleans the html from XSS Attacks until it stops changing.
|
Reparses and cleans the html from XSS Attacks until it stops changing.
|
||||||
@param fragment:
|
:param str fragment: HTML Text that should be cleaned up
|
||||||
|
:return str: scrubbed HTML Text
|
||||||
"""
|
"""
|
||||||
while True:
|
while True:
|
||||||
soup = BeautifulSoup(fragment, "html.parser")
|
soup = BeautifulSoup(fragment, "html.parser")
|
||||||
self.tag_removed = False
|
self.tag_removed = False
|
||||||
self.counter += 1
|
|
||||||
for tag in soup.find_all(True):
|
for tag in soup.find_all(True):
|
||||||
self.clean_tag(tag)
|
self.clean_tag(tag)
|
||||||
fragment = str(soup)
|
fragment = str(soup)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
@@ -1,239 +0,0 @@
|
|||||||
"""
|
|
||||||
Created on 06.06.2011
|
|
||||||
|
|
||||||
@author: christian
|
|
||||||
"""
|
|
||||||
import fnmatch
|
|
||||||
from optparse import make_option
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.contrib.sites.models import Site
|
|
||||||
from django.core.management.base import BaseCommand
|
|
||||||
from django.utils.translation import ugettext as _
|
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
|
||||||
"""
|
|
||||||
classdocs
|
|
||||||
"""
|
|
||||||
can_import_settings = True
|
|
||||||
help = _("Reads raw CSS from stdin, and writes compressed CSS to stdout.")
|
|
||||||
option_list = BaseCommand.option_list + (
|
|
||||||
make_option('-w', '--wrap',
|
|
||||||
type='int',
|
|
||||||
default=None,
|
|
||||||
metavar='N',
|
|
||||||
help="Wrap output to approximately N chars per line."),
|
|
||||||
)
|
|
||||||
|
|
||||||
def remove_comments(self, css):
|
|
||||||
"""Remove all CSS comment blocks."""
|
|
||||||
|
|
||||||
iemac = False
|
|
||||||
preserve = False
|
|
||||||
comment_start = css.find("/*")
|
|
||||||
while comment_start >= 0:
|
|
||||||
# Preserve comments that look like `/*!...*/`.
|
|
||||||
# Slicing is used to make sure we don"t get an IndexError.
|
|
||||||
preserve = css[comment_start + 2:comment_start + 3] == "!"
|
|
||||||
|
|
||||||
comment_end = css.find("*/", comment_start + 2)
|
|
||||||
if comment_end < 0:
|
|
||||||
if not preserve:
|
|
||||||
css = css[:comment_start]
|
|
||||||
break
|
|
||||||
elif comment_end >= (comment_start + 2):
|
|
||||||
if css[comment_end - 1] == "\\":
|
|
||||||
# This is an IE Mac-specific comment; leave this one
|
|
||||||
# and the following one alone.
|
|
||||||
comment_start = comment_end + 2
|
|
||||||
iemac = True
|
|
||||||
elif iemac:
|
|
||||||
comment_start = comment_end + 2
|
|
||||||
iemac = False
|
|
||||||
elif not preserve:
|
|
||||||
css = css[:comment_start] + css[comment_end + 2:]
|
|
||||||
else:
|
|
||||||
comment_start = comment_end + 2
|
|
||||||
comment_start = css.find("/*", comment_start)
|
|
||||||
|
|
||||||
return css
|
|
||||||
|
|
||||||
def remove_unnecessary_whitespace(self, css):
|
|
||||||
"""Remove unnecessary whitespace characters."""
|
|
||||||
|
|
||||||
def pseudoclasscolon(css):
|
|
||||||
"""
|
|
||||||
Prevents 'p :link' from becoming 'p:link'.
|
|
||||||
|
|
||||||
Translates 'p :link' into 'p ___PSEUDOCLASSCOLON___link'; this is
|
|
||||||
translated back again later.
|
|
||||||
"""
|
|
||||||
|
|
||||||
regex = re.compile(r"(^|\})(([^\{\:])+\:)+([^\{]*\{)")
|
|
||||||
match = regex.search(css)
|
|
||||||
while match:
|
|
||||||
css = ''.join([
|
|
||||||
css[:match.start()],
|
|
||||||
match.group().replace(":", "___PSEUDOCLASSCOLON___"),
|
|
||||||
css[match.end():]])
|
|
||||||
match = regex.search(css)
|
|
||||||
return css
|
|
||||||
|
|
||||||
css = pseudoclasscolon(css)
|
|
||||||
# Remove spaces from before things.
|
|
||||||
css = re.sub(r"\s+([!{};:>+\(\)\],])", r"\1", css)
|
|
||||||
|
|
||||||
# If there is a `@charset`,
|
|
||||||
# then only allow one, and move to the beginning.
|
|
||||||
css = re.sub(r"^(.*)(@charset \"[^\"]*\";)", r"\2\1", css)
|
|
||||||
css = re.sub(r"^(\s*@charset [^;]+;\s*)+", r"\1", css)
|
|
||||||
|
|
||||||
# Put the space back in for a few cases, such as `@media screen` and
|
|
||||||
# `(-webkit-min-device-pixel-ratio:0)`.
|
|
||||||
css = re.sub(r"\band\(", "and (", css)
|
|
||||||
|
|
||||||
# Put the colons back.
|
|
||||||
css = css.replace('___PSEUDOCLASSCOLON___', ':')
|
|
||||||
|
|
||||||
# Remove spaces from after things.
|
|
||||||
css = re.sub(r"([!{}:;>+\(\[,])\s+", r"\1", css)
|
|
||||||
|
|
||||||
return css
|
|
||||||
|
|
||||||
def remove_unnecessary_semicolons(self, css):
|
|
||||||
"""Remove unnecessary semicolons."""
|
|
||||||
|
|
||||||
return re.sub(r";+\}", "}", css)
|
|
||||||
|
|
||||||
def remove_empty_rules(self, css):
|
|
||||||
"""Remove empty rules."""
|
|
||||||
|
|
||||||
return re.sub(r"[^\}\{]+\{\}", "", css)
|
|
||||||
|
|
||||||
def normalize_rgb_colors_to_hex(self, css):
|
|
||||||
"""Convert `rgb(51,102,153)` to `#336699`."""
|
|
||||||
|
|
||||||
regex = re.compile(r"rgb\s*\(\s*([0-9,\s]+)\s*\)")
|
|
||||||
match = regex.search(css)
|
|
||||||
while match:
|
|
||||||
colors = match.group(1).split(",")
|
|
||||||
hexcolor = '#%.2x%.2x%.2x' % map(int, colors)
|
|
||||||
css = css.replace(match.group(), hexcolor)
|
|
||||||
match = regex.search(css)
|
|
||||||
return css
|
|
||||||
|
|
||||||
def condense_zero_units(self, css):
|
|
||||||
"""Replace `0(px, em, %, etc)` with `0`."""
|
|
||||||
|
|
||||||
return re.sub(r"([\s:])(0)(px|em|%|in|cm|mm|pc|pt|ex)", r"\1\2", css)
|
|
||||||
|
|
||||||
def condense_multidimensional_zeros(self, css):
|
|
||||||
"""Replace `:0 0 0 0;`, `:0 0 0;` etc. with `:0;`."""
|
|
||||||
|
|
||||||
css = css.replace(":0 0 0 0;", ":0;")
|
|
||||||
css = css.replace(":0 0 0;", ":0;")
|
|
||||||
css = css.replace(":0 0;", ":0;")
|
|
||||||
|
|
||||||
# Revert `background-position:0;` to the valid `background-position:0
|
|
||||||
# 0;`.
|
|
||||||
css = css.replace("background-position:0;", "background-position:0 0;")
|
|
||||||
|
|
||||||
return css
|
|
||||||
|
|
||||||
def condense_floating_points(self, css):
|
|
||||||
"""Replace `0.6` with `.6` where possible."""
|
|
||||||
|
|
||||||
return re.sub(r"(:|\s)0+\.(\d+)", r"\1.\2", css)
|
|
||||||
|
|
||||||
def condense_hex_colors(self, css):
|
|
||||||
"""Shorten colors from #AABBCC to #ABC where possible."""
|
|
||||||
|
|
||||||
regex = re.compile(
|
|
||||||
r"([^\"'=\s])(\s*)#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])")
|
|
||||||
match = regex.search(css)
|
|
||||||
while match:
|
|
||||||
first = match.group(3) + match.group(5) + match.group(7)
|
|
||||||
second = match.group(4) + match.group(6) + match.group(8)
|
|
||||||
if first.lower() == second.lower():
|
|
||||||
css = css.replace(match.group(),
|
|
||||||
match.group(1) + match.group(2) + '#' + first)
|
|
||||||
match = regex.search(css, match.end() - 3)
|
|
||||||
else:
|
|
||||||
match = regex.search(css, match.end())
|
|
||||||
return css
|
|
||||||
|
|
||||||
def condense_whitespace(self, css):
|
|
||||||
"""Condense multiple adjacent whitespace characters into one."""
|
|
||||||
|
|
||||||
return re.sub(r"\s+", " ", css)
|
|
||||||
|
|
||||||
def condense_semicolons(self, css):
|
|
||||||
"""Condense multiple adjacent semicolon characters into one."""
|
|
||||||
|
|
||||||
return re.sub(r";;+", ";", css)
|
|
||||||
|
|
||||||
def wrap_css_lines(self, css, line_length):
|
|
||||||
"""Wrap the lines of the given CSS to an approximate length."""
|
|
||||||
|
|
||||||
lines = []
|
|
||||||
line_start = 0
|
|
||||||
for i, char in enumerate(css):
|
|
||||||
# It's safe to break after `}` characters.
|
|
||||||
if char == '}' and (i - line_start >= line_length):
|
|
||||||
lines.append(css[line_start:i + 1])
|
|
||||||
line_start = i + 1
|
|
||||||
|
|
||||||
if line_start < len(css):
|
|
||||||
lines.append(css[line_start:])
|
|
||||||
return '\n'.join(lines)
|
|
||||||
|
|
||||||
def compress(self, css, wrap=None):
|
|
||||||
css = self.remove_comments(css)
|
|
||||||
css = self.condense_whitespace(css)
|
|
||||||
# A pseudo class for the Box Model Hack
|
|
||||||
# (see http://tantek.com/CSS/Examples/boxmodelhack.html)
|
|
||||||
css = css.replace('"\\"}\\""', "___PSEUDOCLASSBMH___")
|
|
||||||
css = self.remove_unnecessary_whitespace(css)
|
|
||||||
css = self.remove_unnecessary_semicolons(css)
|
|
||||||
css = self.condense_zero_units(css)
|
|
||||||
css = self.condense_multidimensional_zeros(css)
|
|
||||||
css = self.condense_floating_points(css)
|
|
||||||
css = self.normalize_rgb_colors_to_hex(css)
|
|
||||||
css = self.condense_hex_colors(css)
|
|
||||||
if wrap is not None:
|
|
||||||
css = self.wrap_css_lines(css, wrap)
|
|
||||||
css = css.replace("___PSEUDOCLASSBMH___", '"\\"}\\""')
|
|
||||||
css = self.condense_semicolons(css)
|
|
||||||
# A Hack for IE compatiblity
|
|
||||||
# These crappy browser has issues with AND Statments in @MEDIA Blocks
|
|
||||||
css = css.replace('and(', 'and (')
|
|
||||||
return css.strip()
|
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
|
||||||
CSS_ROOT = os.path.join(settings.STATICFILES_DIRS[0], 'css')
|
|
||||||
for site in Site.objects.all():
|
|
||||||
css_input = os.path.join(CSS_ROOT, site.domain)
|
|
||||||
css_output = '%s/%s.css' % (CSS_ROOT,
|
|
||||||
site.domain.replace('.', '_'))
|
|
||||||
|
|
||||||
print("Compressing CSS for {}".format(site.name))
|
|
||||||
print("Input Dir: {}".format(css_input))
|
|
||||||
print("Output File: {}".format(css_output))
|
|
||||||
|
|
||||||
try:
|
|
||||||
os.makedirs(css_input)
|
|
||||||
except OSError:
|
|
||||||
pass
|
|
||||||
css = ''
|
|
||||||
"""Read each .css file in the css_input directory,
|
|
||||||
and append their content"""
|
|
||||||
for file_name in fnmatch.filter(sorted(os.listdir(css_input)),
|
|
||||||
'*.css'):
|
|
||||||
print('Adding: {}'.format(file_name))
|
|
||||||
with open(os.path.join(css_input, file_name), 'r') as css_file:
|
|
||||||
css += css_file.read()
|
|
||||||
with open(css_output, 'w') as css_file:
|
|
||||||
css_file.write(self.compress(css))
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
"""
|
|
||||||
Created on 06.06.2011
|
|
||||||
|
|
||||||
@author: christian
|
|
||||||
"""
|
|
||||||
import fnmatch
|
|
||||||
import os
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.contrib.sites.models import Site
|
|
||||||
from django.core.management.base import BaseCommand
|
|
||||||
from django.utils.translation import ugettext as _
|
|
||||||
import jsmin
|
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
|
||||||
"""
|
|
||||||
classdocs
|
|
||||||
"""
|
|
||||||
can_import_settings = True
|
|
||||||
help = _("Reads raw CSS from stdin, and writes compressed CSS to stdout.")
|
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
|
||||||
JS_ROOT = os.path.join(settings.STATICFILES_DIRS[0], 'js')
|
|
||||||
for site in Site.objects.all():
|
|
||||||
js_input = os.path.join(JS_ROOT, site.domain)
|
|
||||||
js_output = '%s/%s.js' % (JS_ROOT, site.domain.replace('.', '_'))
|
|
||||||
|
|
||||||
print("Compressing JavaScript for {}".format(site.name))
|
|
||||||
print("Input Dir: {}".format(js_input))
|
|
||||||
print("Output File: %s".format(js_output))
|
|
||||||
|
|
||||||
try:
|
|
||||||
os.makedirs(js_input)
|
|
||||||
except OSError:
|
|
||||||
pass
|
|
||||||
output = ''
|
|
||||||
# Read each .js file in the js_input directory, and append their
|
|
||||||
# content
|
|
||||||
js_files = fnmatch.filter(sorted(os.listdir(js_input)), '*.js')
|
|
||||||
for file_name in js_files:
|
|
||||||
print(" Adding: {}...".format(file_name))
|
|
||||||
input_file_name = os.path.join(js_input, file_name)
|
|
||||||
with open(input_file_name, 'r') as input_file:
|
|
||||||
output += input_file.read()
|
|
||||||
with open(js_output, 'w') as output_file:
|
|
||||||
output_file.write(jsmin.jsmin(output))
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
"""
|
|
||||||
Created on 06.06.2011
|
|
||||||
|
|
||||||
@author: christian
|
|
||||||
"""
|
|
||||||
import os
|
|
||||||
import fnmatch
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.contrib.sites.models import Site
|
|
||||||
from django.core.management.base import BaseCommand
|
|
||||||
from django.utils.translation import ugettext as _
|
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
|
||||||
"""
|
|
||||||
classdocs
|
|
||||||
"""
|
|
||||||
can_import_settings = True
|
|
||||||
help = _("Compile SCSS rules.")
|
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
|
||||||
CSS_ROOT = os.path.join(settings.STATICFILES_DIRS[0], 'css')
|
|
||||||
for site in Site.objects.all():
|
|
||||||
css_input = os.path.join(CSS_ROOT, site.domain)
|
|
||||||
css_output = '%s/%s.css' % (CSS_ROOT,
|
|
||||||
site.domain.replace('.', '_'))
|
|
||||||
|
|
||||||
print _("Compressing CSS for %s") % site.name
|
|
||||||
print "Input Dir: %s" % css_input
|
|
||||||
print "Output File: %s" % css_output
|
|
||||||
|
|
||||||
try:
|
|
||||||
os.makedirs(css_input)
|
|
||||||
except OSError:
|
|
||||||
pass
|
|
||||||
css = ''
|
|
||||||
"""Read each .css file in the css_input directory,
|
|
||||||
and append their content"""
|
|
||||||
for file_name in fnmatch.filter(sorted(os.listdir(css_input)),
|
|
||||||
'*.css'):
|
|
||||||
print ' Adding: %s' % file_name
|
|
||||||
with open(os.path.join(css_input, file_name), 'r') as css_file:
|
|
||||||
css += css_file.read()
|
|
||||||
with open(css_output, 'w') as css_file:
|
|
||||||
css_file.write(self.compress(css))
|
|
||||||
# file.write(css)
|
|
||||||
@@ -2,8 +2,7 @@ import logging
|
|||||||
|
|
||||||
from django.core import mail
|
from django.core import mail
|
||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
from django.conf import settings
|
from django.template import loader
|
||||||
from django.template import loader, Context
|
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
|
|
||||||
@@ -48,7 +47,7 @@ class MassMailer(object):
|
|||||||
if isinstance(recipient, self.USER_MODEL):
|
if isinstance(recipient, self.USER_MODEL):
|
||||||
self.recipients.add(recipient)
|
self.recipients.add(recipient)
|
||||||
else:
|
else:
|
||||||
self.log.warn('%s is not a User Object!', recipient)
|
self.log.warning('%s is not a User Object!', recipient)
|
||||||
|
|
||||||
def add_recipients(self, user_list):
|
def add_recipients(self, user_list):
|
||||||
for user in user_list:
|
for user in user_list:
|
||||||
@@ -56,10 +55,10 @@ class MassMailer(object):
|
|||||||
self.log.debug('Adding %s as Recipient' % user)
|
self.log.debug('Adding %s as Recipient' % user)
|
||||||
self.recipients.add(user)
|
self.recipients.add(user)
|
||||||
else:
|
else:
|
||||||
self.log.warn('%s is not a User Object!', user)
|
self.log.warning('%s is not a User Object!', user)
|
||||||
|
|
||||||
def process_mails(self):
|
def process_mails(self):
|
||||||
mail_context = Context(self.context)
|
mail_context = self.context
|
||||||
mail_context['site'] = Site.objects.get_current()
|
mail_context['site'] = Site.objects.get_current()
|
||||||
|
|
||||||
self.txt_template = loader.get_template(self.txt_template)
|
self.txt_template = loader.get_template(self.txt_template)
|
||||||
@@ -103,7 +102,7 @@ class MassMailer(object):
|
|||||||
try:
|
try:
|
||||||
mail.send()
|
mail.send()
|
||||||
except:
|
except:
|
||||||
self.log.warn("Mail failed for: %s", mail.to)
|
self.log.warning("Mail failed for: %s", mail.to)
|
||||||
else:
|
else:
|
||||||
self.log.info("Mail sent successful to: %s" % mail.to)
|
self.log.info("Mail sent successful to: %s" % mail.to)
|
||||||
self.close_smtp_connection()
|
self.close_smtp_connection()
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import html_cleaner
|
|||||||
class HtmlTestCase(unittest.TestCase):
|
class HtmlTestCase(unittest.TestCase):
|
||||||
known_html = (
|
known_html = (
|
||||||
('<STRONG>Fett!</STRONG>', '<strong>Fett!</strong>'),
|
('<STRONG>Fett!</STRONG>', '<strong>Fett!</strong>'),
|
||||||
('<a href="link.html" onclick="do_evil()">Bad Link</a>', '<a href="link.html">Bad Link</a>'),
|
('<a href="link.html" onclick="do_evil()">Bad Link</a>',
|
||||||
|
'<a href="link.html">Bad Link</a>'),
|
||||||
('''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
('''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||||
<HTML><HEAD>
|
<HTML><HEAD>
|
||||||
<META http-equiv=Content-Type content="text/html; charset=iso-8859-1">
|
<META http-equiv=Content-Type content="text/html; charset=iso-8859-1">
|
||||||
@@ -32,8 +33,8 @@ class HtmlTestCase(unittest.TestCase):
|
|||||||
href="http://www.xxxxxxxxxxxx.com">http://www.xxxxxxxxxxxx.com</A><BR>(xxx)
|
href="http://www.xxxxxxxxxxxx.com">http://www.xxxxxxxxxxxx.com</A><BR>(xxx)
|
||||||
xxx-xxxx</FONT></DIV></BODY></HTML>
|
xxx-xxxx</FONT></DIV></BODY></HTML>
|
||||||
''',
|
''',
|
||||||
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">'
|
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_html_cleaner(self):
|
def test_html_cleaner(self):
|
||||||
@@ -42,5 +43,6 @@ class HtmlTestCase(unittest.TestCase):
|
|||||||
for original, tidy in self.known_html:
|
for original, tidy in self.known_html:
|
||||||
self.assertEqual(cleaner.clean_html(original), tidy)
|
self.assertEqual(cleaner.clean_html(original), tidy)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user