Django Sitemap Framework integriert

This commit is contained in:
2016-10-11 23:54:18 +02:00
parent 8595959872
commit ba44e97e9a
20 changed files with 249 additions and 176 deletions

View File

@@ -4,6 +4,7 @@ django-appconf
django-compressor django-compressor
django-contrib-comments django-contrib-comments
django-ckeditor django-ckeditor
django-csp
django-extra-views django-extra-views
django-grappelli django-grappelli
django-markdown django-markdown
@@ -17,4 +18,4 @@ PyJWT
python-social-auth python-social-auth
pytz==2013d pytz==2013d
requests requests
requests-oauthlib requests-oauthlib

View File

@@ -8,8 +8,8 @@ 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-16 18:07+0200\n" "POT-Creation-Date: 2016-09-28 00:25+0200\n"
"PO-Revision-Date: 2016-09-15 23:07+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"
"Language: de\n" "Language: de\n"
@@ -18,7 +18,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Translated-Using: django-rosetta 0.7.2\n" "X-Translated-Using: django-rosetta 0.7.2\n"
"X-Generator: Gtranslator 2.91.7\n" "X-Generator: Poedit 1.8.9\n"
#: src/content/feeds.py:14 #: src/content/feeds.py:14
msgid "Current news from Kasu" msgid "Current news from Kasu"

25
src/content/sitemaps.py Normal file
View File

@@ -0,0 +1,25 @@
from django.contrib.sitemaps import Sitemap
from .models import Article, Page
class ArticleSitemap(Sitemap):
changefreq = "never"
priority = 0.6
protocol = 'https'
def items(self):
return Article.objects.published()
def lastmod(self, article):
return article.date_modified
class PageSitemap(Sitemap):
changefreq = "monthly"
priority = 0.4
protocol = 'https'
def items(self):
return Page.objects.all() #filter(status__gt=0)
def location(self, page):
return page.get_absolute_url()

View File

@@ -7,8 +7,8 @@ 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-16 18:07+0200\n" "POT-Creation-Date: 2016-09-28 00:25+0200\n"
"PO-Revision-Date: 2016-09-15 23:13+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"
"Language: de\n" "Language: de\n"

22
src/events/sitemaps.py Normal file
View File

@@ -0,0 +1,22 @@
from django.contrib.sitemaps import Sitemap
from django.utils import timezone
from .models import Event, Photo
class EventSitemap(Sitemap):
changefreq = "never"
priority = 0.6
protocol = 'https'
def items(self):
return Event.objects.all()
def priority(self, event):
delta = timezone.now() - event.start
delta = abs(delta.days / 300.0 )
return max(1 - delta, 0.1)
def lastmod(self, event):
return event.end
return min(event.end, timezone.now())

View File

@@ -7,8 +7,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: kasu.utils\n" "Project-Id-Version: kasu.utils\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-09-16 18:07+0200\n" "POT-Creation-Date: 2016-09-28 00:25+0200\n"
"PO-Revision-Date: 2015-08-16 11:38+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"
"Language: de\n" "Language: de\n"
@@ -16,14 +16,14 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 1.8.3\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/kasu/settings.py:147 #: src/kasu/settings.py:160
msgid "German" msgid "German"
msgstr "Deutsch" msgstr "Deutsch"
#: src/kasu/settings.py:147 #: src/kasu/settings.py:160
msgid "English" msgid "English"
msgstr "Englisch" msgstr "Englisch"

View File

@@ -11,9 +11,6 @@ INTERNAL_IPS = ('127.0.0.1',)
MANAGERS = ADMINS MANAGERS = ADMINS
ROOT_URLCONF = 'kasu.urls' ROOT_URLCONF = 'kasu.urls'
SECRET_KEY = 'set in local_settings' SECRET_KEY = 'set in local_settings'
SESSION_COOKIE_DOMAIN = 'kasu.at' # Die ganze Domain Kasu
SESSION_COOKIE_AGE = 15768000 # Session dauer: 4 Wochen
SESSION_COOKIE_SECURE = True
SITE_ID = 1 SITE_ID = 1
# Path Info # Path Info
@@ -40,6 +37,7 @@ PREREQ_APPS = [
'django.contrib.messages', 'django.contrib.messages',
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.sites', 'django.contrib.sites',
'django.contrib.sitemaps',
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'django_comments', 'django_comments',
'ckeditor', 'ckeditor',
@@ -66,6 +64,7 @@ CACHES = {
# Request Middleware # Request Middleware
MIDDLEWARE_CLASSES = [ MIDDLEWARE_CLASSES = [
'csp.middleware.CSPMiddleware',
'django.middleware.security.SecurityMiddleware', 'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
@@ -110,6 +109,20 @@ TEMPLATES = [
}, },
] ]
#Settings for Security Middleware
CSP_DEFAULT_SRC = ("'self'",)
CSP_IMG_SRC = CSP_DEFAULT_SRC
CSP_SCRIPT_SRC = CSP_DEFAULT_SRC
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_AGE = 15768000 # Session dauer: 4 Wochen
SESSION_COOKIE_SECURE = True
# E-Mail Settings (set in local_settings) # E-Mail Settings (set in local_settings)
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = "" EMAIL_HOST = ""

View File

@@ -0,0 +1,8 @@
var idSite = 1;
var piwikTrackingApiUrl = 'https://kasu.at/piwik/piwik.php';
var _paq = _paq || [];
_paq.push(['setTrackerUrl', piwikTrackingApiUrl]);
_paq.push(['setSiteId', idSite]);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);

View File

@@ -6,6 +6,7 @@
<meta name="description" content="{% block description %}{% endblock %}"/> <meta name="description" content="{% block description %}{% endblock %}"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta charset="UTF-8"> <meta charset="UTF-8">
<script src="https://kasu.at/piwik/piwik.js" async defer></script>
<!--[if lt IE 9]> <!--[if lt IE 9]>
<script type="text/javascript"> <script type="text/javascript">
document.createElement('header'); document.createElement('header');
@@ -17,7 +18,8 @@
document.createElement('hgroup'); document.createElement('hgroup');
</script> </script>
<![endif]--> <![endif]-->
<link rel="stylesheet" href="{{STATIC_URL}}css/kasu.css" />
<link rel="stylesheet" href="{{STATIC_URL}}css/kasu.css" />
<link rel="manifest" href="/manifest.json" /> <link rel="manifest" href="/manifest.json" />
<link rel="alternate" type="application/rss+xml" title="{% trans 'Current News' %}" <link rel="alternate" type="application/rss+xml" title="{% trans 'Current News' %}"
href="{% url 'feed-latest-news' %}"/> href="{% url 'feed-latest-news' %}"/>
@@ -27,7 +29,8 @@
<link rel="apple-touch-icon" sizes="180x180" href="{{STATIC_URL}}img/apple-touch-icon-180x180.png" /> <link rel="apple-touch-icon" sizes="180x180" href="{{STATIC_URL}}img/apple-touch-icon-180x180.png" />
<link rel="icon" type="image/png" href="{{STATIC_URL}}img/favicon-96x96.png" sizes="96x96" /> <link rel="icon" type="image/png" href="{{STATIC_URL}}img/favicon-96x96.png" sizes="96x96" />
<link rel="mask-icon" href="{{STATIC_URL}}img/safari-pinned-tab.svg" color="#5bbad5" /> <link rel="mask-icon" href="{{STATIC_URL}}img/safari-pinned-tab.svg" color="#5bbad5" />
{% block opengraph %} {% block opengraph %}
<meta property="og:type" content="website"/> <meta property="og:type" content="website"/>
<meta property="og:title" content="Kasu - Verein Japanische Spielekultur"/> <meta property="og:title" content="Kasu - Verein Japanische Spielekultur"/>
@@ -167,7 +170,7 @@
<button type="submit">{% trans "Go" %}</button> <button type="submit">{% trans "Go" %}</button>
</form> </form>
</footer> </footer>
<nav id="usernav"> <nav id="usernav">
{% if user.is_authenticated %} {% if user.is_authenticated %}
{% trans "Logged in as" %}: {% trans "Logged in as" %}:
<a rel="nofollow" href="{% url 'membership-details' user.username %}">{{user.username}}</a> - <a rel="nofollow" href="{% url 'membership-details' user.username %}">{{user.username}}</a> -
@@ -185,6 +188,7 @@
title="{% trans 'Login with Google' %}" aria-label="{% trans 'Login with Google' %}"></a> title="{% trans 'Login with Google' %}" aria-label="{% trans 'Login with Google' %}"></a>
{% endif %} {% endif %}
</nav> </nav>
<script type="text/javascript">{% block javascript %}{% endblock %}</script> <script src="{{STATIC_URL}}/js/piwik.js" async defer></script>
<noscript><img src="//kasu.at/piwik/piwik.php?idsite=1" style="border:0;" alt="" /></noscript>
</body> </body>
</html> </html>

View File

@@ -1,5 +1,6 @@
User-agent: * User-agent: *
Sitemap: https://kasu.at/sitemap.xml
Disallow: /admin/ Disallow: /admin/
Disallow: /cgi-bin/ Disallow: /cgi-bin/
Disallow: /users/ Disallow: /users/
host: example.com Host: kasu.at

View File

@@ -2,20 +2,27 @@
from django.conf import settings from django.conf import settings
from django.conf.urls import patterns, include, url from django.conf.urls import patterns, include, url
from django.contrib import admin from django.contrib import admin
from django.contrib.sitemaps.views import sitemap
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from content.feeds import LatestNews, LatestComments from content.feeds import LatestNews, LatestComments
from content.views import * # @UnusedWildImport from content.views import PageAddForm, PageEditForm, PageHtml, PagePdf, StartPage
from content.sitemaps import ArticleSitemap, PageSitemap
from events.views import EventListIcal from events.views import EventListIcal
from events.sitemaps import EventSitemap
from membership.views import MembershipDetail from membership.views import MembershipDetail
admin.autodiscover() admin.autodiscover()
sitemaps = {
'articles': ArticleSitemap,
'events': EventSitemap,
'pages': PageSitemap,
}
urlpatterns = patterns( urlpatterns = patterns(
'', '',
url(r'^$', StartPage.as_view()), url(r'^$', StartPage.as_view()),
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'^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')),
@@ -38,9 +45,12 @@ urlpatterns = patterns(
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'^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]+)/$', 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()),
) )
if settings.DEBUG: if settings.DEBUG:

View File

@@ -7,8 +7,8 @@ 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-16 18:07+0200\n" "POT-Creation-Date: 2016-09-28 00:25+0200\n"
"PO-Revision-Date: 2015-09-06 00:13+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"
"Language: de\n" "Language: de\n"
@@ -16,7 +16,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 1.8.3\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 #: src/mahjong_ranking/admin.py:29

View File

@@ -7,8 +7,8 @@ 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-16 18:07+0200\n" "POT-Creation-Date: 2016-09-28 00:25+0200\n"
"PO-Revision-Date: 2014-12-11 22:47+0100\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"
"Language: de\n" "Language: de\n"
@@ -16,7 +16,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 1.6.11\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 #: src/maistar_ranking/admin.py:24

View File

@@ -16,7 +16,11 @@ from utils.massmailer import MassMailer
class MembershipForm(forms.ModelForm): class MembershipForm(forms.ModelForm):
error_css_class = 'error' error_css_class = 'error'
required_css_class = 'required' required_css_class = 'required'
birthday = forms.DateField(label=_('birthday'), required=False) birthday = forms.DateField(
label=_('birthday'),
required=False,
help_text=_('Input format: yyyy-mm-dd')
)
email = forms.EmailField(label=_('Email'), required=True) email = forms.EmailField(label=_('Email'), required=True)
class Meta: class Meta:
@@ -33,13 +37,6 @@ class MembershipForm(forms.ModelForm):
Please fill out this field yet.')) Please fill out this field yet.'))
return self.cleaned_data['birthday'] return self.cleaned_data['birthday']
def clean_telephone(self):
if self.cleaned_data['membership'] and not self.cleaned_data[
'telephone']:
raise forms.ValidationError(_('For your membership, we need this. \
Please fill out this field yet.'))
return self.cleaned_data['telephone']
def clean_street_name(self): def clean_street_name(self):
if self.cleaned_data['membership'] and not self.cleaned_data[ if self.cleaned_data['membership'] and not self.cleaned_data[
'street_name']: 'street_name']:
@@ -68,10 +65,8 @@ 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(), password1 = forms.CharField(widget=forms.PasswordInput(), label=_('password'))
label=_('password')) password2 = forms.CharField(widget=forms.PasswordInput(), label=_('password (again)'))
password2 = forms.CharField(widget=forms.PasswordInput(),
label=_('password (again)'))
recaptcha = forms.ReCaptchaField() recaptcha = forms.ReCaptchaField()
class Meta: class Meta:

View File

@@ -7,8 +7,8 @@ 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-16 18:07+0200\n" "POT-Creation-Date: 2016-09-28 00:25+0200\n"
"PO-Revision-Date: 2016-09-16 19:06+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"
"Language: de\n" "Language: de\n"
@@ -35,60 +35,64 @@ msgstr "Gruppe"
msgid "Groups" msgid "Groups"
msgstr "Gruppen" msgstr "Gruppen"
#: src/membership/admin.py:61 src/membership/models.py:162 #: src/membership/admin.py:62 src/membership/models.py:164
#: src/membership/models.py:210 #: src/membership/models.py:215
#: src/membership/templates/membership/register_form.html:28 #: src/membership/templates/membership/register_form.html:32
msgid "Membership" msgid "Membership"
msgstr "Mitgliedschaft" msgstr "Mitgliedschaft"
#: src/membership/admin.py:64 #: src/membership/admin.py:65
msgid "Permissions" msgid "Permissions"
msgstr "Berechtigung" msgstr "Berechtigung"
#: src/membership/admin.py:66 #: src/membership/admin.py:67
msgid "Important dates" msgid "Important dates"
msgstr "Wichtige Daten" msgstr "Wichtige Daten"
#: src/membership/forms.py:19 #: src/membership/forms.py:20
msgid "birthday" msgid "birthday"
msgstr "Geburtstag" msgstr "Geburtstag"
#: src/membership/forms.py:20 #: src/membership/forms.py:22
msgid "Input format: yyyy-mm-dd"
msgstr "Eingabeformat: tt.mm.jjjj"
#: src/membership/forms.py:24
msgid "Email" msgid "Email"
msgstr "E-Mail" msgstr "E-Mail"
#: src/membership/forms.py:32 src/membership/forms.py:39 #: src/membership/forms.py:36 src/membership/forms.py:43
#: src/membership/forms.py:46 src/membership/forms.py:53 #: 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:59 #: src/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:72 #: src/membership/forms.py:68
msgid "password" msgid "password"
msgstr "Passwort" msgstr "Passwort"
#: src/membership/forms.py:74 #: src/membership/forms.py:69
msgid "password (again)" msgid "password (again)"
msgstr "Passwort (wiederholen)" msgstr "Passwort (wiederholen)"
#: src/membership/forms.py:97 #: src/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:106 #: src/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:115 #: src/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."
@@ -100,70 +104,70 @@ msgstr "Männlich"
msgid "Female" msgid "Female"
msgstr "Weiblich" msgstr "Weiblich"
#: src/membership/models.py:88 #: src/membership/models.py:90
msgid "user" msgid "user"
msgstr "Benutzer" msgstr "Benutzer"
#: src/membership/models.py:90 #: src/membership/models.py:92
msgid "activation key" msgid "activation key"
msgstr "Aktivierungsschlüssel" msgstr "Aktivierungsschlüssel"
#: src/membership/models.py:94 #: src/membership/models.py:96
msgid "pending activation" msgid "pending activation"
msgstr "Ausstehende Aktivierung" msgstr "Ausstehende Aktivierung"
#: src/membership/models.py:95 #: src/membership/models.py:97
msgid "pending activations" msgid "pending activations"
msgstr "Wartende Aktivierungen" msgstr "Wartende Aktivierungen"
#: src/membership/models.py:98 #: src/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:145 #: src/membership/models.py:147
msgid "Gender" msgid "Gender"
msgstr "Geschlecht" msgstr "Geschlecht"
#: src/membership/models.py:164 #: src/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:167 #: src/membership/models.py:170
msgid "Birthday Date" msgid "Birthday Date"
msgstr "Geburtstag" msgstr "Geburtstag"
#: src/membership/models.py:169 #: src/membership/models.py:174
msgid "Telephone" msgid "Telephone"
msgstr "Telefon" msgstr "Telefon"
#: src/membership/models.py:175 #: src/membership/models.py:180
msgid "Address" msgid "Address"
msgstr "Adresse" msgstr "Adresse"
#: src/membership/models.py:181 #: src/membership/models.py:186
msgid "Postcode" msgid "Postcode"
msgstr "Postleitzahl" msgstr "Postleitzahl"
#: src/membership/models.py:186 #: src/membership/models.py:191
msgid "Town/City" msgid "Town/City"
msgstr "Ort" msgstr "Ort"
#: src/membership/models.py:194 #: src/membership/models.py:199
msgid "Paid until" msgid "Paid until"
msgstr "Bezahlt bis" msgstr "Bezahlt bis"
#: src/membership/models.py:200 #: src/membership/models.py:205
msgid "Confirmed" msgid "Confirmed"
msgstr "Bestätigt" msgstr "Bestätigt"
#: src/membership/models.py:202 #: src/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:211 #: src/membership/models.py:216
msgid "Memberships" msgid "Memberships"
msgstr "Mitgliedschaften" msgstr "Mitgliedschaften"
@@ -362,18 +366,7 @@ msgstr "Speichern"
msgid "Registration" msgid "Registration"
msgstr "Registrieren" msgstr "Registrieren"
#: src/membership/templates/membership/register_form.html:16 #: src/membership/templates/membership/register_form.html:9
msgid "name"
msgstr "Name"
#: src/membership/templates/membership/register_form.html:22
#: src/membership/templates/registration/login.html:6
#: src/membership/templates/registration/login.html:8
#: src/membership/templates/registration/login.html:37
msgid "login"
msgstr "Anmelden"
#: src/membership/templates/membership/register_form.html:34
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 "
@@ -387,6 +380,17 @@ 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
msgid "name"
msgstr "Name"
#: src/membership/templates/membership/register_form.html:26
#: src/membership/templates/registration/login.html:6
#: src/membership/templates/registration/login.html:8
#: src/membership/templates/registration/login.html:37
msgid "login"
msgstr "Anmelden"
#: src/membership/templates/membership/register_form.html:39 #: src/membership/templates/membership/register_form.html:39
msgid "reset" msgid "reset"
msgstr "Zurücksetzen" msgstr "Zurücksetzen"
@@ -549,7 +553,7 @@ msgstr "Passwort zurücksetzen"
msgid "Transmit" msgid "Transmit"
msgstr "Übermitteln" msgstr "Übermitteln"
#: src/membership/views.py:54 #: src/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."
@@ -557,11 +561,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:74 #: src/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:88 #: src/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"

View File

@@ -166,7 +166,10 @@ class Membership(AbstractUser):
help_text=_('Yes, I confirm that I am in agreement with the statutes \ help_text=_('Yes, I confirm that I am in agreement with the statutes \
and would like to become a member.') and would like to become a member.')
) )
birthday = models.DateField(_("Birthday Date"), blank=True, null=True) birthday = models.DateField(
_("Birthday Date"),
blank=True, null=True,
)
telephone = models.CharField( telephone = models.CharField(
_("Telephone"), _("Telephone"),
max_length=30, max_length=30,

View File

@@ -6,12 +6,16 @@ from django.core.urlresolvers import reverse
from django.http import Http404 from django.http import Http404
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 django.utils.decorators import method_decorator
from csp.decorators import csp_update
from mahjong_ranking.models import KyuDanRanking, SeasonRanking 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 = {
'SCRIPT_SRC': ['https://www.google.com/recaptcha/', 'https://www.gstatic.com/recaptcha/'],
'FRAME_SRC': 'https://www.google.com/recaptcha/',
'STYLE_SRC': "'unsafe-inline'"
}
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
@@ -109,6 +113,10 @@ class RegisterForm(generic.FormView):
success_url = '/membership/activation_sent/' success_url = '/membership/activation_sent/'
template_name = 'membership/register_form.html' template_name = 'membership/register_form.html'
@method_decorator(csp_update(**RECAPTCHA_CSP))
def dispatch(self, *args, **kwargs):
return super(RegisterForm, self).dispatch(*args, **kwargs)
def form_valid(self, form): def form_valid(self, form):
form.save() form.save()
return generic.FormView.form_valid(self, form) return generic.FormView.form_valid(self, form)

View File

@@ -9,9 +9,11 @@ from django.conf import settings
from django.core import validators from django.core import validators
from django.core.validators import EMPTY_VALUES from django.core.validators import EMPTY_VALUES
from django.forms import utils, Form, ModelForm, ValidationError from django.forms import utils, Form, ModelForm, ValidationError
import sys
import django.forms.fields import django.forms.fields
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from . import widgets from . import widgets
@@ -28,6 +30,9 @@ class Html5Mixin(object):
if self.help_text: if self.help_text:
attrs['title'] = self.help_text attrs['title'] = self.help_text
attrs['placeholder'] = self.help_text attrs['placeholder'] = self.help_text
if hasattr(self, 'placeholder'):
attrs['placeholder'] = self.placeholder
if self.accesskey: if self.accesskey:
attrs['accesskey'] = self.accesskey attrs['accesskey'] = self.accesskey
return attrs return attrs
@@ -124,6 +129,7 @@ class CharField(Html5Mixin, django.forms.CharField):
class DateField(Html5Mixin, django.forms.fields.DateField): class DateField(Html5Mixin, django.forms.fields.DateField):
placeholder = _('yyyy-mm-dd')
widget = widgets.DateInput widget = widgets.DateInput
@@ -200,63 +206,36 @@ class ReCaptchaField(django.forms.fields.CharField):
self.required = True self.required = True
super(ReCaptchaField, self).__init__(*args, **kwargs) super(ReCaptchaField, self).__init__(*args, **kwargs)
def _check_recaptcha(self, challenge_value, response_value, remote_ip=None): def get_remote_ip(self):
""" f = sys._getframe()
Submits a reCAPTCHA request for verification. while f:
Returns RecaptchaResponse for the request if 'request' in f.f_locals:
request = f.f_locals['request']
@param challenge_value: value of recaptcha_challenge_field if request:
@param response_value: value of recaptcha_response_field remote_ip = request.META.get('REMOTE_ADDR', None)
@param remoteip -- the user's ip address forwarded_ip = request.META.get('HTTP_X_FORWARDED_FOR', None)
return forwarded_ip or remote_ip
""" f = f.f_back
import urllib
import urllib2
private_key = settings.RECAPTCHA_PRIVATE_KEY
challenge_value = challenge_value.encode('utf-8')
response_value = response_value.encode('utf-8')
params = urllib.urlencode({
'privatekey': private_key,
'remoteip': remote_ip,
'challenge': challenge_value,
'response': response_value,
})
request = urllib2.Request(
url="http://www.google.com/recaptcha/api/verify",
data=params,
headers={
"Content-type": "application/x-www-form-urlencoded",
"User-agent": "reCAPTCHA Python"
}
)
httpresp = urllib2.urlopen(request)
return_values = httpresp.read().splitlines()
httpresp.close()
return_code = return_values[0]
if (return_code == "true"):
return True
else:
return False
def clean(self, values): def clean(self, values):
""" test the google recaptcha"""
import json, urllib, urllib2
url = "https://www.google.com/recaptcha/api/siteverify"
challenge_value = values[0] challenge_value = values[0]
response_value = values[1] data = urllib.urlencode({
super(ReCaptchaField, self).clean(response_value) 'secret': settings.RECAPTCHA_PRIVATE_KEY,
if not challenge_value: '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( raise ValidationError(
_(u'The CAPTCHA challenge is missing.')) _(u'Only humans are allowed to submit this form.'))
elif not response_value:
raise ValidationError(
_(u'The CAPTCHA solution is missing.'))
elif self._check_recaptcha(challenge_value, response_value):
return challenge_value
else:
raise ValidationError(
_(u'The CAPTCHA solution was incorrect.'))
class RegexField(Html5Mixin, django.forms.RegexField): class RegexField(Html5Mixin, django.forms.RegexField):

View File

@@ -126,23 +126,15 @@ class ReCaptchaInput(widgets.Widget):
""" """
Der HTML Code von Googles ReCaptcha als Form Widget Der HTML Code von Googles ReCaptcha als Form Widget
""" """
recaptcha_challenge_name = 'recaptcha_challenge_field' recaptcha_challenge_name = 'g-recaptcha-response'
recaptcha_response_name = 'recaptcha_response_field' recaptcha_response_name = 'g-recaptcha-response'
def render(self, name, value, attrs=None): def render(self, name, value, attrs=None):
javascript = u""" html_code = u'''
<script type="text/javascript">var RecaptchaOptions = {theme : <script src="https://www.google.com/recaptcha/api.js" async defer></script>
'%(theme)s'};</script><script type="text/javascript" <div class="g-recaptcha" data-sitekey="{public_key}" data-size="compact"></div>
src="https://www.google.com/recaptcha/api/challenge?k=%(public_key)s"> '''.format(public_key=settings.RECAPTCHA_PUBLIC_KEY)
</script><noscript><iframe return mark_safe(html_code)
src="https://www.google.com/recaptcha/api/noscript?k=%(public_key)s"
height="130" width="500"></iframe><br /><textarea
name="recaptcha_challenge_field" rows="3" cols="40"></textarea><input
type="hidden" name="recaptcha_response_field" value="manual_challenge">
</noscript>"""
return mark_safe(javascript % {'public_key':
settings.RECAPTCHA_PUBLIC_KEY,
'theme': 'red'})
def value_from_datadict(self, data, files, name): def value_from_datadict(self, data, files, name):
return [data.get(self.recaptcha_challenge_name, None), return [data.get(self.recaptcha_challenge_name, None),

View File

@@ -7,16 +7,16 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: kasu.utils\n" "Project-Id-Version: kasu.utils\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-09-16 18:07+0200\n" "POT-Creation-Date: 2016-09-28 00:25+0200\n"
"PO-Revision-Date: 2015-08-16 11:42+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@posteo.at>\n"
"Language-Team: Kasu <verein@kasu.at>\n" "Language-Team: Kasu <verein@kasu.at>\n"
"Language: de\n" "Language: de\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 1.8.3\n" "X-Generator: Poedit 1.8.9\n"
#: src/utils/__init__.py:16 #: src/utils/__init__.py:16
msgid "Rejected" msgid "Rejected"
@@ -1014,31 +1014,27 @@ msgstr "Sambia"
msgid "Zimbabwe" msgid "Zimbabwe"
msgstr "Zimbabwe" msgstr "Zimbabwe"
#: src/utils/html5/forms.py:43 #: src/utils/html5/forms.py:48
msgid "" msgid ""
"Select a valid choice. That choice is not one of the available " "Select a valid choice. That choice is not one of the available "
"choices." "choices."
msgstr "" msgstr ""
"Bitte eine gültige Auswahl treffen. Diese Option steht nicht zur Verfügung." "Bitte eine gültige Auswahl treffen. Diese Option steht nicht zur Verfügung."
#: src/utils/html5/forms.py:89 #: src/utils/html5/forms.py:94
msgid "" msgid ""
"Select a valid choice. That choice is not one of the available " "Select a valid choice. That choice is not one of the available "
"choices." "choices."
msgstr "" msgstr ""
"Bitte eine gültige Auswahl treffen. Diese Option steht nicht zur Verfügung." "Bitte eine gültige Auswahl treffen. Diese Option steht nicht zur Verfügung."
#: src/utils/html5/forms.py:251 #: src/utils/html5/forms.py:132
msgid "The CAPTCHA challenge is missing." msgid "yyyy-mm-dd"
msgstr "Das CAPTCHA Rätsel wurde nicht gelöst" msgstr "tt.mm.jjjj"
#: src/utils/html5/forms.py:254 #: src/utils/html5/forms.py:238
msgid "The CAPTCHA solution is missing." msgid "Only humans are allowed to submit this form."
msgstr "Das CAPTCHA wurde nicht richtig gelöst." msgstr "Nur Menschen dürfen dieses Formular übermitteln."
#: src/utils/html5/forms.py:259
msgid "The CAPTCHA solution was incorrect."
msgstr "Das CAPTCHA wurde nicht richtig gelöst."
#: src/utils/management/commands/compresscss.py:22 #: src/utils/management/commands/compresscss.py:22
#: src/utils/management/commands/compressjs.py:21 #: src/utils/management/commands/compressjs.py:21
@@ -1071,3 +1067,15 @@ msgstr "Du hast nicht genügend Rechte dafür."
#: src/utils/mixins.py:100 #: src/utils/mixins.py:100
msgid "You don't have the permissions for this" msgid "You don't have the permissions for this"
msgstr "Du hast nicht genügend Rechte dafür." msgstr "Du hast nicht genügend Rechte dafür."
#~ msgid "dd.mm.yyyy"
#~ msgstr "tt.mm.jjjj"
#~ msgid "The CAPTCHA challenge is missing."
#~ msgstr "Das CAPTCHA Rätsel wurde nicht gelöst"
#~ msgid "The CAPTCHA solution is missing."
#~ msgstr "Das CAPTCHA wurde nicht richtig gelöst."
#~ msgid "The CAPTCHA solution was incorrect."
#~ msgstr "Das CAPTCHA wurde nicht richtig gelöst."