-Subproject commit 7dc1b2c84ca9b53454d9eb0c296b4f005dcb780c
+Subproject commit df1ef1a80800b58ae6d818f5bdb0ff919c558d37
-i https://py.mdrn.pl:8443/simple/
-django-debug-toolbar
+django-debug-toolbar<1.10
+django-debug-toolbar-template-timings
Fabric
sphinx
pyinotify
-fnpdeploy>=0.2.2
+fnpdeploy>=0.2.3
paypalrestsdk
django-haystack<2.8.0
-django-migdal>=0.8.1
+django-migdal>=0.8.3
-python-slugify
\ No newline at end of file
+python-slugify
+
+firebase-admin
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
+from django.db.models import Q
from django.http.response import HttpResponse
from django.utils.functional import lazy
from django.db import models
from . import emitters # Register our emitters
API_BASE = WL_BASE = MEDIA_BASE = lazy(
- lambda: u'http://' + Site.objects.get_current().domain, unicode)()
+ lambda: u'https://' + Site.objects.get_current().domain, unicode)()
+SORT_KEY_SEP = '$'
category_singular = {
'authors': 'author',
book_tag_categories = ['author', 'epoch', 'kind', 'genre']
+book_list_fields = book_tag_categories + [
+ 'href', 'title', 'url', 'cover', 'cover_thumb', 'slug', 'simple_thumb', 'has_audio', 'cover_color', 'full_sort_key']
+
def read_tags(tags, request, allowed):
""" Reads a path of filtering tags.
@classmethod
def cover_color(cls, book):
- return WLCover.epoch_colors.get(book.extra_info['epoch'], '#000000')
+ return WLCover.epoch_colors.get(book.extra_info.get('epoch'), '#000000')
+
+ @classmethod
+ def full_sort_key(cls, book):
+ return '%s%s%s%s%s' % (book.sort_key_author, SORT_KEY_SEP, book.sort_key, SORT_KEY_SEP, book.id)
+
+ @staticmethod
+ def books_after(books, after, new_api):
+ if not new_api:
+ return books.filter(slug__gt=after)
+ try:
+ author, title, book_id = after.split(SORT_KEY_SEP)
+ except ValueError:
+ return Book.objects.none()
+ return books.filter(Q(sort_key_author__gt=author)
+ | (Q(sort_key_author=author) & Q(sort_key__gt=title))
+ | (Q(sort_key_author=author) & Q(sort_key=title) & Q(id__gt=int(book_id))))
+
+ @staticmethod
+ def order_books(books, new_api):
+ if new_api:
+ return books.order_by('sort_key_author', 'sort_key', 'id')
+ else:
+ return books.order_by('slug')
class BookDetailHandler(BaseHandler, BookDetails):
"""
allowed_methods = ('GET',)
model = Book
- fields = book_tag_categories + [
- 'href', 'title', 'url', 'cover', 'cover_thumb', 'slug', 'simple_thumb', 'has_audio', 'cover_color']
+ fields = book_list_fields
@classmethod
def genres(cls, book):
@piwik_track
def read(self, request, tags=None, top_level=False, audiobooks=False, daisy=False, pk=None,
recommended=False, newest=False, books=None,
- after=None, before=None, count=None):
+ after=None, count=None):
""" Lists all books with given tags.
:param tags: filtering tags; should be a path of categories
except ValueError:
return rc.NOT_FOUND
+ new_api = request.GET.get('new_api')
if 'after' in request.GET:
after = request.GET['after']
- if 'before' in request.GET:
- before = request.GET['before']
if 'count' in request.GET:
count = request.GET['count']
books = Book.tagged.with_all(tags)
else:
books = books if books is not None else Book.objects.all()
- books = books.order_by('slug')
+ books = self.order_books(books, new_api)
if top_level:
books = books.filter(parent=None)
books = books.order_by('-created_at')
if after:
- books = books.filter(slug__gt=after)
- if before:
- books = books.filter(slug__lt=before)
+ books = self.books_after(books, after, new_api)
- books = books.only('slug', 'title', 'cover', 'cover_thumb')
+ if new_api:
+ books = books.only('slug', 'title', 'cover', 'cover_thumb', 'sort_key', 'sort_key_author')
+ else:
+ books = books.only('slug', 'title', 'cover', 'cover_thumb')
for category in book_tag_categories:
books = prefetch_relations(books, category)
if count:
- if before:
- books = list(reversed(books.order_by('-slug')[:count]))
- else:
- books = books[:count]
+ books = books[:count]
return books
class BooksHandler(BookDetailHandler):
allowed_methods = ('GET', 'POST')
model = Book
- fields = book_tag_categories + ['href', 'title', 'url', 'cover', 'cover_thumb', 'cover_color', 'slug']
+ fields = book_list_fields + ['liked']
anonymous = AnonymousBooksHandler
+ # hack, because piston is stupid
+ @classmethod
+ def liked(cls, book):
+ return getattr(book, 'liked', None)
+
+ def read(self, request, **kwargs):
+ books = AnonymousBooksHandler().read(request, **kwargs)
+ likes = set(Book.tagged.with_any(request.user.tag_set.all()).values_list('id', flat=True))
+
+ new_books = [
+ BookProxy(book).set('liked', book.id in likes)
+ for book in books]
+ return QuerySetProxy(new_books)
+
def create(self, request, *args, **kwargs):
if not request.user.has_perm('catalogue.add_book'):
return rc.FORBIDDEN
class Meta:
managed = False
- def __init__(self, book, key):
+ def __init__(self, book, key=None):
self.book = book
self.key = key
+ def set(self, attr, value):
+ self.__setattr__(attr, value)
+ return self
+
def __getattr__(self, item):
- if item not in ('book', 'key'):
- return self.book.__getattribute__(item)
- else:
- return self.__getattribute__(item)
+ return self.book.__getattribute__(item)
class QuerySetProxy(models.QuerySet):
return iter(self.list)
-class FilterBooksHandler(AnonymousBooksHandler):
- fields = book_tag_categories + [
- 'href', 'title', 'url', 'cover', 'cover_thumb', 'cover_color', 'simple_thumb', 'has_audio', 'slug', 'key']
+class AnonFilterBooksHandler(AnonymousBooksHandler):
+ fields = book_list_fields + ['key']
def parse_bool(self, s):
if s in ('true', 'false'):
is_audiobook = self.parse_bool(request.GET.get('audiobook'))
preview = self.parse_bool(request.GET.get('preview'))
+ new_api = request.GET.get('new_api')
after = request.GET.get('after')
count = int(request.GET.get('count', 50))
- books = Book.objects.distinct().order_by('slug')
+ books = self.order_books(Book.objects.distinct(), new_api)
if is_lektura is not None:
books = books.filter(has_audience=is_lektura)
if is_audiobook is not None:
books_title = books.filter(title__iregex='\m' + search_string)
books_title = books_title.exclude(id__in=list(books_author.values_list('id', flat=True)))
if after and (key_sep in after):
- which, slug = after.split(key_sep, 1)
+ which, key = after.split(key_sep, 1)
if which == 'title':
- book_lists = [(books_title.filter(slug__gt=slug), 'title')]
+ book_lists = [(self.books_after(books_title, key, new_api), 'title')]
else: # which == 'author'
- book_lists = [(books_author.filter(slug__gt=slug), 'author'), (books_title, 'title')]
+ book_lists = [(self.books_after(books_author, key, new_api), 'author'), (books_title, 'title')]
else:
book_lists = [(books_author, 'author'), (books_title, 'title')]
else:
if after and key_sep in after:
- which, slug = after.split(key_sep, 1)
- books = books.filter(slug__gt=slug)
+ which, key = after.split(key_sep, 1)
+ books = self.books_after(books, key, new_api)
book_lists = [(books, 'book')]
filtered_books = []
for book_list, label in book_lists:
- book_list = book_list.only('slug', 'title', 'cover', 'cover_thumb')
+ book_list = book_list.only('slug', 'title', 'cover', 'cover_thumb', 'sort_key_author', 'sort_key')
for category in book_tag_categories:
book_list = prefetch_relations(book_list, category)
remaining_count = count - len(filtered_books)
- new_books = [BookProxy(book, '%s%s%s' % (label, key_sep, book.slug))
- for book in book_list[:remaining_count]]
+ new_books = [
+ BookProxy(book, '%s%s%s' % (
+ label, key_sep, book.slug if not new_api else self.full_sort_key(book)))
+ for book in book_list[:remaining_count]]
filtered_books += new_books
if len(filtered_books) == count:
break
return QuerySetProxy(filtered_books)
+class FilterBooksHandler(BooksHandler):
+ anonymous = AnonFilterBooksHandler
+ fields = book_list_fields + ['key', 'liked']
+
+ # hack, because piston is stupid
+ @classmethod
+ def liked(cls, book):
+ return getattr(book, 'liked', None)
+
+ def read(self, request):
+ qsp = AnonFilterBooksHandler().read(request)
+ likes = set(Book.tagged.with_any(request.user.tag_set.all()).values_list('id', flat=True))
+ for book in qsp.list:
+ book.set('liked', book.id in likes)
+ return qsp
+
+
+class BookPreviewHandler(BookDetailHandler):
+ fields = BookDetailHandler.fields + ['slug']
+
+ def read(self, request):
+ return Book.objects.filter(preview=True)
+
+
# add categorized tags fields for Book
def _tags_getter(category):
@classmethod
return rc.NOT_FOUND
after = request.GET.get('after')
- before = request.GET.get('before')
count = request.GET.get('count')
tags = Tag.objects.filter(category=category_sng).exclude(items=None).order_by('slug')
if after:
tags = tags.filter(slug__gt=after)
- if before:
- tags = tags.filter(slug__lt=before)
if count:
- if before:
- tags = list(reversed(tags.order_by('-slug')[:count]))
- else:
- tags = tags[:count]
+ tags = tags[:count]
return tags
class UserDataHandler(BaseHandler):
model = BookUserData
- fields = ('state', 'username')
+ fields = ('state', 'username', 'premium')
allowed_methods = ('GET', 'POST')
def read(self, request, slug=None):
if not request.user.is_authenticated():
return rc.FORBIDDEN
if slug is None:
- return {'username': request.user.username}
+ return {'username': request.user.username, 'premium': is_subscribed(request.user)}
try:
book = Book.objects.get(slug=slug)
except Book.DoesNotExist:
class UserShelfHandler(BookDetailHandler):
- fields = book_tag_categories + [
- 'href', 'title', 'url', 'cover', 'cover_thumb', 'simple_thumb', 'slug', 'key']
+ fields = book_list_fields + ['liked']
def parse_bool(self, s):
if s in ('true', 'false'):
else:
return None
+ # hack, because piston is stupid
+ @classmethod
+ def liked(cls, book):
+ return getattr(book, 'liked', None)
+
def read(self, request, state):
if not request.user.is_authenticated():
return rc.FORBIDDEN
+ likes = set(Book.tagged.with_any(request.user.tag_set.all()).values_list('id', flat=True))
if state not in ('reading', 'complete', 'likes'):
return rc.NOT_FOUND
+ new_api = request.GET.get('new_api')
after = request.GET.get('after')
count = int(request.GET.get('count', 50))
if state == 'likes':
else:
ids = BookUserData.objects.filter(user=request.user, complete=state == 'complete')\
.values_list('book_id', flat=True)
- books = Book.objects.filter(id__in=list(ids)).distinct().order_by('slug')
+ books = Book.objects.filter(id__in=list(ids)).distinct()
+ books = self.order_books(books, new_api)
if after:
- books = books.filter(slug__gt=after)
+ books = self.books_after(books, after, new_api)
if count:
books = books[:count]
- return books
+ new_books = []
+ for book in books:
+ new_books.append(BookProxy(book).set('liked', book.id in likes))
+ return QuerySetProxy(new_books)
class UserLikeHandler(BaseHandler):
return rc.NOT_FOUND
return {'likes': likes(request.user, book)}
- def create(self, request, slug, action='like'):
+ def create(self, request, slug):
if not request.user.is_authenticated():
return rc.FORBIDDEN
try:
book = Book.objects.get(slug=slug)
except Book.DoesNotExist:
return rc.NOT_FOUND
+ action = request.GET.get('action', 'like')
if action == 'like':
book.like(request.user)
elif action == 'unlike':
class BlogEntryHandler(BaseHandler):
model = Entry
- fields = ('title', 'lead', 'body', 'place', 'time', 'image_url', 'gallery_urls', 'type', 'key')
+ fields = (
+ 'title', 'lead', 'body', 'place', 'time', 'image_url', 'image_thumb', 'gallery_urls', 'type', 'key', 'url')
def read(self, request):
after = request.GET.get('after')
@classmethod
def image_url(cls, entry):
- return entry.image.url if entry.image else None
+ return (WL_BASE + entry.image.url) if entry.image else None
+
+ @classmethod
+ def image_thumb(cls, entry):
+ return MEDIA_BASE + default.backend.get_thumbnail(
+ entry.image, "193x193").url if entry.image else ''
@classmethod
def gallery_urls(cls, entry):
- return [photo.url() for photo in entry.photo_set.all()]
+ return [WL_BASE + photo.url() for photo in entry.photo_set.all()]
@classmethod
def key(cls, entry):
return entry.first_published_at
+
+ @classmethod
+ def url(cls, entry):
+ return WL_BASE + entry.get_absolute_url()
--- /dev/null
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import datetime
+from django.utils.timezone import utc
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('api', '0003_bookuserdata'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='bookuserdata',
+ name='last_changed',
+ field=models.DateTimeField(default=datetime.datetime(2018, 11, 28, 14, 41, 2, 673054, tzinfo=utc), auto_now=True),
+ preserve_default=False,
+ ),
+ ]
book = models.ForeignKey(Book)
user = models.ForeignKey(User)
complete = models.BooleanField(default=False)
+ last_changed = models.DateTimeField(auto_now=True)
def get_state(self):
return 'complete' if self.complete else 'reading'
auth = OAuthAuthentication(realm="Wolne Lektury")
+class DjangoAuthentication(object):
+ """
+ Authentication handler that always returns
+ True, so no authentication is needed, nor
+ initiated (`challenge` is missing.)
+ """
+ def is_authenticated(self, request):
+ return request.user.is_authenticated()
+
+ def challenge(self):
+ from django.http import HttpResponse
+ resp = HttpResponse("Authorization Required")
+ resp.status_code = 401
+ return resp
+
+
def auth_resource(handler):
+ from django.conf import settings
+ if settings.DEBUG:
+ django_auth = DjangoAuthentication()
+ return CsrfExemptResource(handler=handler, authentication=django_auth)
return CsrfExemptResource(handler=handler, authentication=auth)
ebook_list_resource = Resource(handler=handlers.EBooksHandler)
# book_list_resource = Resource(handler=handlers.BooksHandler)
book_resource = Resource(handler=handlers.BookDetailHandler)
-filter_book_resource = Resource(handler=handlers.FilterBooksHandler)
+filter_book_resource = auth_resource(handler=handlers.FilterBooksHandler)
epub_resource = auth_resource(handler=handlers.EpubHandler)
+preview_resource = Resource(handler=handlers.BookPreviewHandler)
+
reading_resource = auth_resource(handler=handlers.UserDataHandler)
shelf_resource = auth_resource(handler=handlers.UserShelfHandler)
tags_re = r'^(?P<tags>(?:(?:[a-z0-9-]+/){2}){0,6})'
-paginate_re = r'(?:before/(?P<before>[a-z0-9-]+)/)?(?:after/(?P<after>[a-z0-9-]+)/)?(?:count/(?P<count>[0-9]+)/)?$'
+paginate_re = r'(?:after/(?P<after>[a-z0-9-]+)/)?(?:count/(?P<count>[0-9]+)/)?$'
@ssi_included
book_list_resource, {"daisy": True}, name='api_daisy_list'),
url(r'^recommended/' + paginate_re, book_list_resource, {"recommended": True}, name='api_recommended_list'),
- url(r'^newest/', book_list_resource, {"newest": True, "top_level": True, "count": 20}, name='api_newest_list'),
- url(r'^filter-books/', filter_book_resource, name='api_filter_books'),
+ url(r'^newest/$', book_list_resource, {"newest": True, "top_level": True, "count": 20}, name='api_newest_list'),
+ url(r'^filter-books/$', filter_book_resource, name='api_filter_books'),
+
+ url(r'^preview/$', preview_resource, name='api_preview'),
url(r'^pictures/$', picture_resource),
parser.add_argument('--width', type=int)
parser.add_argument('--height', type=int)
parser.add_argument('--bleed', action='store_true')
+ parser.add_argument('--cover-class', type=str)
def handle(self, *args, **options):
slug = options['slug']
width = options['width']
height = options.get('height')
+ cover_class = options.get('cover_class')
bleed = 20 if options['bleed'] else 0
wldoc = Book.objects.get(slug=slug).wldocument()
- cover = make_cover(wldoc.book_info, width=width, height=height, bleed=bleed)
+ kwargs = {}
+ if cover_class:
+ kwargs['cover_class'] = cover_class
+ cover = make_cover(wldoc.book_info, width=width, height=height, bleed=bleed, **kwargs)
cover.save('%s.jpg' % slug)
def fragment_data(self):
fragment = self.choose_fragment()
if fragment:
- return {'title': fragment.book.pretty_title(), 'html': fragment.get_short_text()}
+ return {
+ 'title': fragment.book.pretty_title(),
+ 'html': re.sub('</?blockquote[^>]*>', '', fragment.get_short_text()),
+ }
else:
return None
from django.http import HttpResponse
from django.utils.encoding import force_unicode
+from paypal.rest import user_is_subscribed
from reporting.utils import read_chunks
# Use the system (hardware-based) random number generator if it exists.
def is_subscribed(user):
- return user.is_authenticated() # TEMPORARY
+ return user_is_subscribed(user)
from hashlib import md5
-import requests
from django.conf import settings
from mailchimp3 import MailChimp
from mailchimp3.mailchimpclient import MailChimpError
-INTERESTS = {settings.MAILCHIMP_GROUP_ID: True}
-
-
-def get_client():
- headers = requests.utils.default_headers()
- headers['User-Agent'] = '%s (%s)' % settings.MANAGERS[0]
-
def subscriber_hash(email):
return md5(email).hexdigest()
data={'interests': interests})
-def subscribe(email):
+def subscribe(email, mailing_lists=None):
client = MailChimp(mc_api=settings.MAILCHIMP_API_KEY, timeout=10.0)
try:
member = client.lists.members.get(settings.MAILCHIMP_LIST_ID, subscriber_hash(email))
else:
if member['status'] != 'subscribed':
remove_from_groups(email, client)
+ mailing_lists = mailing_lists or [settings.MAILCHIMP_DEFAULT_GROUP]
+ interests = {
+ settings.MAILCHIMP_GROUP_IDS[mailing_list]: True
+ for mailing_list in mailing_lists
+ if mailing_list in settings.MAILCHIMP_GROUP_IDS
+ }
client.lists.members.create_or_update(
settings.MAILCHIMP_LIST_ID, subscriber_hash(email),
data={
'email_address': email,
'status_if_new': 'subscribed',
'status': 'subscribed',
- 'interests': INTERESTS,
+ 'interests': interests,
+ }
+ )
+
+
+def unsubscribe(email, mailing_lists=None):
+ client = MailChimp(mc_api=settings.MAILCHIMP_API_KEY, timeout=10.0)
+ try:
+ member = client.lists.members.get(settings.MAILCHIMP_LIST_ID, subscriber_hash(email))
+ except MailChimpError:
+ return
+ else:
+ if member['status'] != 'subscribed':
+ return
+ mailing_lists = mailing_lists or settings.MAILCHIMP_GROUP_IDS
+ interests = {
+ settings.MAILCHIMP_GROUP_IDS[mailing_list]: False
+ for mailing_list in mailing_lists
+ if mailing_list in settings.MAILCHIMP_GROUP_IDS
+ }
+ client.lists.members.update(
+ settings.MAILCHIMP_LIST_ID, subscriber_hash(email),
+ data={
+ 'interests': interests,
}
)
data = '%s%s%s%s%s' % (self.id, self.contact, serialized_body, self.ip, self.form_tag)
return sha1(data).hexdigest()
+ def keys(self):
+ try:
+ from .views import contact_forms
+ orig_fields = contact_forms[self.form_tag]().fields
+ except KeyError:
+ orig_fields = {}
+ return list(orig_fields.keys())
+
+ def items(self):
+ return [(key, self.body[key]) for key in self.keys() if key in self.body]
+
class Attachment(models.Model):
contact = models.ForeignKey(Contact)
https://{{site_domain}}{% url 'admin:contact_contact_change' contact.pk %}
-{% for k, v in contact.body.items %}
+{% for k, v in contact.items %}
{{ k }}:
{{ v|pretty_print }}
{% endfor %}
# -*- coding: utf-8 -*-
from django.core.exceptions import ValidationError
from django.core.validators import validate_email
-from django.forms import Form, BooleanField
+from django.forms import Form, BooleanField, MultipleChoiceField
from django.forms.fields import EmailField
+from django.forms.widgets import CheckboxSelectMultiple
from django.template.loader import render_to_string
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _, ugettext
email_field = 'email'
agree_newsletter = BooleanField(
required=False, initial=False, label=_(u'I want to receive Wolne Lektury\'s newsletter.'))
+ mailing = False
+ mailing_field = 'agree_newsletter'
data_processing_part1 = u'''\
Administratorem danych osobowych jest Fundacja Nowoczesna Polska (ul. Marszałkowska 84/92 lok. 125, 00-514 Warszawa).
super(NewsletterForm, self).save(*args, **kwargs)
except AttributeError:
pass
- if not self.cleaned_data.get('agree_newsletter'):
+ if not (self.mailing or self.cleaned_data.get(self.mailing_field)):
return
email = self.cleaned_data[self.email_field]
try:
# send_noreply_mail(
# ugettext(u'Confirm your subscription to Wolne Lektury newsletter'),
# render_to_string('newsletter/subscribe_email.html', {'subscription': subscription}), [email])
- mailing.subscribe(email)
+ mailing.subscribe(email, mailing_lists=self.cleaned_data.get('mailing_lists'))
class SubscribeForm(NewsletterForm):
+ mailing = True
+ agree_newsletter = None
+
email = EmailField(label=_('email address'))
+ mailing_lists = MultipleChoiceField(
+ widget=CheckboxSelectMultiple,
+ choices=(('general', _(u'general newsletter')), ('contest', _(u'about the contest'))),
+ label=_(u'mailing list'))
def __init__(self, *args, **kwargs):
super(SubscribeForm, self).__init__(*args, **kwargs)
- self.fields['agree_newsletter'].required = True
class UnsubscribeForm(Form):
subscription = self.cleaned_data['subscription']
subscription.active = False
subscription.save()
+ mailing.unsubscribe(subscription.email)
context = {'subscription': subscription}
# refactor to send_noreply_mail
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-04-04 17:12+0200\n"
+"POT-Creation-Date: 2018-09-28 11:23+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: forms.py:17
+#: forms.py:19
msgid "I want to receive Wolne Lektury's newsletter."
msgstr ""
-#: forms.py:46 forms.py:54 models.py:10
+#: forms.py:60 forms.py:71 models.py:10
msgid "email address"
msgstr ""
-#: forms.py:61
+#: forms.py:63
+msgid "general newsletter"
+msgstr ""
+
+#: forms.py:63
+msgid "about the contest"
+msgstr ""
+
+#: forms.py:64
+msgid "mailing list"
+msgstr ""
+
+#: forms.py:78
msgid "Email address not found."
msgstr ""
-#: forms.py:72
+#: forms.py:89
msgid "Unsubscribe from Wolne Lektury's newsletter."
msgstr ""
msgid "Your subscription to Wolne Lektury newsletter is confirmed. Thank you!"
msgstr ""
-#: templates/newsletter/subscribe_form.html:15
+#: templates/newsletter/subscribe_form.html:16
msgid "Subscribe"
msgstr ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-04-04 17:12+0200\n"
+"POT-Creation-Date: 2018-09-28 11:23+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: forms.py:17
+#: forms.py:19
msgid "I want to receive Wolne Lektury's newsletter."
msgstr ""
-#: forms.py:46 forms.py:54 models.py:10
+#: forms.py:60 forms.py:71 models.py:10
msgid "email address"
msgstr ""
-#: forms.py:61
+#: forms.py:63
+msgid "general newsletter"
+msgstr ""
+
+#: forms.py:63
+msgid "about the contest"
+msgstr ""
+
+#: forms.py:64
+msgid "mailing list"
+msgstr ""
+
+#: forms.py:78
msgid "Email address not found."
msgstr ""
-#: forms.py:72
+#: forms.py:89
msgid "Unsubscribe from Wolne Lektury's newsletter."
msgstr ""
msgid "Your subscription to Wolne Lektury newsletter is confirmed. Thank you!"
msgstr ""
-#: templates/newsletter/subscribe_form.html:15
+#: templates/newsletter/subscribe_form.html:16
msgid "Subscribe"
msgstr ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-04-04 17:12+0200\n"
+"POT-Creation-Date: 2018-09-28 11:23+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: forms.py:17
+#: forms.py:19
msgid "I want to receive Wolne Lektury's newsletter."
msgstr ""
-#: forms.py:46 forms.py:54 models.py:10
+#: forms.py:60 forms.py:71 models.py:10
msgid "email address"
msgstr ""
-#: forms.py:61
+#: forms.py:63
+msgid "general newsletter"
+msgstr ""
+
+#: forms.py:63
+msgid "about the contest"
+msgstr ""
+
+#: forms.py:64
+msgid "mailing list"
+msgstr ""
+
+#: forms.py:78
msgid "Email address not found."
msgstr ""
-#: forms.py:72
+#: forms.py:89
msgid "Unsubscribe from Wolne Lektury's newsletter."
msgstr ""
msgid "Your subscription to Wolne Lektury newsletter is confirmed. Thank you!"
msgstr ""
-#: templates/newsletter/subscribe_form.html:15
+#: templates/newsletter/subscribe_form.html:16
msgid "Subscribe"
msgstr ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-04-04 17:12+0200\n"
+"POT-Creation-Date: 2018-09-28 11:23+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
-#: forms.py:17
+#: forms.py:19
msgid "I want to receive Wolne Lektury's newsletter."
msgstr ""
-#: forms.py:46 forms.py:54 models.py:10
+#: forms.py:60 forms.py:71 models.py:10
msgid "email address"
msgstr ""
-#: forms.py:61
+#: forms.py:63
+msgid "general newsletter"
+msgstr ""
+
+#: forms.py:63
+msgid "about the contest"
+msgstr ""
+
+#: forms.py:64
+msgid "mailing list"
+msgstr ""
+
+#: forms.py:78
msgid "Email address not found."
msgstr ""
-#: forms.py:72
+#: forms.py:89
msgid "Unsubscribe from Wolne Lektury's newsletter."
msgstr ""
msgid "Your subscription to Wolne Lektury newsletter is confirmed. Thank you!"
msgstr ""
-#: templates/newsletter/subscribe_form.html:15
+#: templates/newsletter/subscribe_form.html:16
msgid "Subscribe"
msgstr ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-04-04 17:12+0200\n"
+"POT-Creation-Date: 2018-09-28 11:23+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: forms.py:17
+#: forms.py:19
msgid "I want to receive Wolne Lektury's newsletter."
msgstr ""
-#: forms.py:46 forms.py:54 models.py:10
+#: forms.py:60 forms.py:71 models.py:10
msgid "email address"
msgstr ""
-#: forms.py:61
+#: forms.py:63
+msgid "general newsletter"
+msgstr ""
+
+#: forms.py:63
+msgid "about the contest"
+msgstr ""
+
+#: forms.py:64
+msgid "mailing list"
+msgstr ""
+
+#: forms.py:78
msgid "Email address not found."
msgstr ""
-#: forms.py:72
+#: forms.py:89
msgid "Unsubscribe from Wolne Lektury's newsletter."
msgstr ""
msgid "Your subscription to Wolne Lektury newsletter is confirmed. Thank you!"
msgstr ""
-#: templates/newsletter/subscribe_form.html:15
+#: templates/newsletter/subscribe_form.html:16
msgid "Subscribe"
msgstr ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-04-04 17:12+0200\n"
+"POT-Creation-Date: 2018-09-28 11:23+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n"
"%100<10 || n%100>=20) ? 1 : 2);\n"
-#: forms.py:17
+#: forms.py:19
msgid "I want to receive Wolne Lektury's newsletter."
msgstr ""
-#: forms.py:46 forms.py:54 models.py:10
+#: forms.py:60 forms.py:71 models.py:10
msgid "email address"
msgstr ""
-#: forms.py:61
+#: forms.py:63
+msgid "general newsletter"
+msgstr ""
+
+#: forms.py:63
+msgid "about the contest"
+msgstr ""
+
+#: forms.py:64
+msgid "mailing list"
+msgstr ""
+
+#: forms.py:78
msgid "Email address not found."
msgstr ""
-#: forms.py:72
+#: forms.py:89
msgid "Unsubscribe from Wolne Lektury's newsletter."
msgstr ""
msgid "Your subscription to Wolne Lektury newsletter is confirmed. Thank you!"
msgstr ""
-#: templates/newsletter/subscribe_form.html:15
+#: templates/newsletter/subscribe_form.html:16
msgid "Subscribe"
msgstr ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-04-04 17:12+0200\n"
+"POT-Creation-Date: 2018-09-28 11:23+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Jan Szejko <jan.szejko@nowoczesnapolska.org.pl>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2);\n"
-#: forms.py:17
+#: forms.py:19
msgid "I want to receive Wolne Lektury's newsletter."
msgstr "Chcę otrzymywać newsletter Wolnych Lektur"
-#: forms.py:46 forms.py:54 models.py:10
+#: forms.py:60 forms.py:71 models.py:10
msgid "email address"
msgstr "adres email"
-#: forms.py:61
+#: forms.py:63
+msgid "general newsletter"
+msgstr "ogólny newsletter"
+
+#: forms.py:63
+msgid "about the contest"
+msgstr "informacje o konkursie"
+
+#: forms.py:64
+msgid "mailing list"
+msgstr "lista mailowa"
+
+#: forms.py:78
msgid "Email address not found."
msgstr "Nie znaleziono adresu email."
-#: forms.py:72
+#: forms.py:89
msgid "Unsubscribe from Wolne Lektury's newsletter."
msgstr "Wypisuję się z newslettera Wolnych Lektur"
msgid "Your subscription to Wolne Lektury newsletter is confirmed. Thank you!"
msgstr "Potwierdzono subskrypcję newslettera Wolnych Lektur. Dziękujemy!"
-#: templates/newsletter/subscribe_form.html:15
+#: templates/newsletter/subscribe_form.html:16
msgid "Subscribe"
msgstr "Zapisz się"
msgstr "Zapisz się na newsletter"
#: views.py:28
-#| msgid "Subscribe"
msgid "Subscribed"
msgstr "Zapisano do newslettera"
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-04-04 17:12+0200\n"
+"POT-Creation-Date: 2018-09-28 11:23+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
-#: forms.py:17
+#: forms.py:19
msgid "I want to receive Wolne Lektury's newsletter."
msgstr ""
-#: forms.py:46 forms.py:54 models.py:10
+#: forms.py:60 forms.py:71 models.py:10
msgid "email address"
msgstr ""
-#: forms.py:61
+#: forms.py:63
+msgid "general newsletter"
+msgstr ""
+
+#: forms.py:63
+msgid "about the contest"
+msgstr ""
+
+#: forms.py:64
+msgid "mailing list"
+msgstr ""
+
+#: forms.py:78
msgid "Email address not found."
msgstr ""
-#: forms.py:72
+#: forms.py:89
msgid "Unsubscribe from Wolne Lektury's newsletter."
msgstr ""
msgid "Your subscription to Wolne Lektury newsletter is confirmed. Thank you!"
msgstr ""
-#: templates/newsletter/subscribe_form.html:15
+#: templates/newsletter/subscribe_form.html:16
msgid "Subscribe"
msgstr ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-04-04 17:12+0200\n"
+"POT-Creation-Date: 2018-09-28 11:23+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
-#: forms.py:17
+#: forms.py:19
msgid "I want to receive Wolne Lektury's newsletter."
msgstr ""
-#: forms.py:46 forms.py:54 models.py:10
+#: forms.py:60 forms.py:71 models.py:10
msgid "email address"
msgstr ""
-#: forms.py:61
+#: forms.py:63
+msgid "general newsletter"
+msgstr ""
+
+#: forms.py:63
+msgid "about the contest"
+msgstr ""
+
+#: forms.py:64
+msgid "mailing list"
+msgstr ""
+
+#: forms.py:78
msgid "Email address not found."
msgstr ""
-#: forms.py:72
+#: forms.py:89
msgid "Unsubscribe from Wolne Lektury's newsletter."
msgstr ""
msgid "Your subscription to Wolne Lektury newsletter is confirmed. Thank you!"
msgstr ""
-#: templates/newsletter/subscribe_form.html:15
+#: templates/newsletter/subscribe_form.html:16
msgid "Subscribe"
msgstr ""
{% render_honeypot_field %}
<ol>
<li>{{ form.email|pretty_field }}</li>
- <li>{{ form.agree_newsletter|pretty_checkbox }}</li>
+ <li>{{ form.mailing_lists|pretty_field }}</li>
<li><span class="helptext">{{ form.data_processing }}</span></li>
<li><input type="submit" value="{% trans "Subscribe" %}"/></li>
</ol>
# Add new tags
tags_to_add = [tag for tag in updated_tags if tag not in current_tags]
for tag in tags_to_add:
- self.intermediary_table_model.objects.create(tag=tag, content_object=obj)
+ existing = self.intermediary_table_model.objects.filter(
+ content_type__pk=content_type.pk, object_id=obj.pk, tag=tag)
+ if not existing:
+ self.intermediary_table_model.objects.create(tag=tag, content_object=obj)
tags_updated.send(sender=type(obj), instance=obj, affected_tags=tags_to_add + tags_for_removal)
class PaypalSubscriptionForm(forms.Form):
- amount = forms.IntegerField(min_value=10, max_value=30000, initial=20, label=_('amount'))
+ amount = forms.IntegerField(min_value=5, max_value=30000, initial=20, label=_('amount in PLN'))
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-08-30 15:57+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: forms.py:10
+msgid "amount in PLN"
+msgstr ""
+
+#: templates/paypal/cancel.html:5
+msgid "Zrezygnowano z płatności :("
+msgstr ""
+
+#: templates/paypal/error.html:1
+msgid "PayPal Error"
+msgstr ""
+
+#: templates/paypal/error.html:5
+msgid "Learn more"
+msgstr ""
+
+#: templates/paypal/form.html:6 templates/paypal/form.html.py:9
+msgid "Wolne Lektury Friend Club"
+msgstr ""
+
+#: templates/paypal/form.html:17
+msgid "Subscribe with PayPal"
+msgstr ""
+
+#: templates/paypal/form.html:20
+msgid "You must be logged in to subscribe."
+msgstr ""
+
+#: templates/paypal/return.html:8
+msgid "Dziękujemy, że jesteś z nami i pomagasz nam rozwijać Wolne Lektury!"
+msgstr ""
+
+#: templates/paypal/return.html:9
+msgid "Pamiętaj, że zawsze możesz się z nami skontaktować:"
+msgstr ""
+
+#: templates/paypal/return.html:11
+msgid "Do przeczytania!"
+msgstr ""
+
+#: templates/paypal/return.html:11
+msgid "Zespół Wolnych Lektur"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-08-30 15:57+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: forms.py:10
+msgid "amount in PLN"
+msgstr ""
+
+#: templates/paypal/cancel.html:5
+msgid "Zrezygnowano z płatności :("
+msgstr ""
+
+#: templates/paypal/error.html:1
+msgid "PayPal Error"
+msgstr ""
+
+#: templates/paypal/error.html:5
+msgid "Learn more"
+msgstr ""
+
+#: templates/paypal/form.html:6 templates/paypal/form.html.py:9
+msgid "Wolne Lektury Friend Club"
+msgstr ""
+
+#: templates/paypal/form.html:17
+msgid "Subscribe with PayPal"
+msgstr ""
+
+#: templates/paypal/form.html:20
+msgid "You must be logged in to subscribe."
+msgstr ""
+
+#: templates/paypal/return.html:8
+msgid "Dziękujemy, że jesteś z nami i pomagasz nam rozwijać Wolne Lektury!"
+msgstr ""
+
+#: templates/paypal/return.html:9
+msgid "Pamiętaj, że zawsze możesz się z nami skontaktować:"
+msgstr ""
+
+#: templates/paypal/return.html:11
+msgid "Do przeczytania!"
+msgstr ""
+
+#: templates/paypal/return.html:11
+msgid "Zespół Wolnych Lektur"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-08-30 15:57+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: forms.py:10
+msgid "amount in PLN"
+msgstr ""
+
+#: templates/paypal/cancel.html:5
+msgid "Zrezygnowano z płatności :("
+msgstr ""
+
+#: templates/paypal/error.html:1
+msgid "PayPal Error"
+msgstr ""
+
+#: templates/paypal/error.html:5
+msgid "Learn more"
+msgstr ""
+
+#: templates/paypal/form.html:6 templates/paypal/form.html.py:9
+msgid "Wolne Lektury Friend Club"
+msgstr ""
+
+#: templates/paypal/form.html:17
+msgid "Subscribe with PayPal"
+msgstr ""
+
+#: templates/paypal/form.html:20
+msgid "You must be logged in to subscribe."
+msgstr ""
+
+#: templates/paypal/return.html:8
+msgid "Dziękujemy, że jesteś z nami i pomagasz nam rozwijać Wolne Lektury!"
+msgstr ""
+
+#: templates/paypal/return.html:9
+msgid "Pamiętaj, że zawsze możesz się z nami skontaktować:"
+msgstr ""
+
+#: templates/paypal/return.html:11
+msgid "Do przeczytania!"
+msgstr ""
+
+#: templates/paypal/return.html:11
+msgid "Zespół Wolnych Lektur"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-08-30 15:57+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+#: forms.py:10
+msgid "amount in PLN"
+msgstr ""
+
+#: templates/paypal/cancel.html:5
+msgid "Zrezygnowano z płatności :("
+msgstr ""
+
+#: templates/paypal/error.html:1
+msgid "PayPal Error"
+msgstr ""
+
+#: templates/paypal/error.html:5
+msgid "Learn more"
+msgstr ""
+
+#: templates/paypal/form.html:6 templates/paypal/form.html.py:9
+msgid "Wolne Lektury Friend Club"
+msgstr ""
+
+#: templates/paypal/form.html:17
+msgid "Subscribe with PayPal"
+msgstr ""
+
+#: templates/paypal/form.html:20
+msgid "You must be logged in to subscribe."
+msgstr ""
+
+#: templates/paypal/return.html:8
+msgid "Dziękujemy, że jesteś z nami i pomagasz nam rozwijać Wolne Lektury!"
+msgstr ""
+
+#: templates/paypal/return.html:9
+msgid "Pamiętaj, że zawsze możesz się z nami skontaktować:"
+msgstr ""
+
+#: templates/paypal/return.html:11
+msgid "Do przeczytania!"
+msgstr ""
+
+#: templates/paypal/return.html:11
+msgid "Zespół Wolnych Lektur"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-08-30 15:57+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: forms.py:10
+msgid "amount in PLN"
+msgstr ""
+
+#: templates/paypal/cancel.html:5
+msgid "Zrezygnowano z płatności :("
+msgstr ""
+
+#: templates/paypal/error.html:1
+msgid "PayPal Error"
+msgstr ""
+
+#: templates/paypal/error.html:5
+msgid "Learn more"
+msgstr ""
+
+#: templates/paypal/form.html:6 templates/paypal/form.html.py:9
+msgid "Wolne Lektury Friend Club"
+msgstr ""
+
+#: templates/paypal/form.html:17
+msgid "Subscribe with PayPal"
+msgstr ""
+
+#: templates/paypal/form.html:20
+msgid "You must be logged in to subscribe."
+msgstr ""
+
+#: templates/paypal/return.html:8
+msgid "Dziękujemy, że jesteś z nami i pomagasz nam rozwijać Wolne Lektury!"
+msgstr ""
+
+#: templates/paypal/return.html:9
+msgid "Pamiętaj, że zawsze możesz się z nami skontaktować:"
+msgstr ""
+
+#: templates/paypal/return.html:11
+msgid "Do przeczytania!"
+msgstr ""
+
+#: templates/paypal/return.html:11
+msgid "Zespół Wolnych Lektur"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-08-30 15:57+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n"
+"%100<10 || n%100>=20) ? 1 : 2);\n"
+
+#: forms.py:10
+msgid "amount in PLN"
+msgstr ""
+
+#: templates/paypal/cancel.html:5
+msgid "Zrezygnowano z płatności :("
+msgstr ""
+
+#: templates/paypal/error.html:1
+msgid "PayPal Error"
+msgstr ""
+
+#: templates/paypal/error.html:5
+msgid "Learn more"
+msgstr ""
+
+#: templates/paypal/form.html:6 templates/paypal/form.html.py:9
+msgid "Wolne Lektury Friend Club"
+msgstr ""
+
+#: templates/paypal/form.html:17
+msgid "Subscribe with PayPal"
+msgstr ""
+
+#: templates/paypal/form.html:20
+msgid "You must be logged in to subscribe."
+msgstr ""
+
+#: templates/paypal/return.html:8
+msgid "Dziękujemy, że jesteś z nami i pomagasz nam rozwijać Wolne Lektury!"
+msgstr ""
+
+#: templates/paypal/return.html:9
+msgid "Pamiętaj, że zawsze możesz się z nami skontaktować:"
+msgstr ""
+
+#: templates/paypal/return.html:11
+msgid "Do przeczytania!"
+msgstr ""
+
+#: templates/paypal/return.html:11
+msgid "Zespół Wolnych Lektur"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-08-30 15:57+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
+"|| n%100>=20) ? 1 : 2);\n"
+
+#: forms.py:10
+msgid "amount in PLN"
+msgstr "kwota w złotych"
+
+#: templates/paypal/cancel.html:5
+msgid "Zrezygnowano z płatności :("
+msgstr ""
+
+#: templates/paypal/error.html:1
+msgid "PayPal Error"
+msgstr "Błąd PayPala"
+
+#: templates/paypal/error.html:5
+msgid "Learn more"
+msgstr "Dowiedz się więcej"
+
+#: templates/paypal/form.html:6 templates/paypal/form.html.py:9
+msgid "Wolne Lektury Friend Club"
+msgstr "Klub Przyjaciół Wolnych Lektur"
+
+#: templates/paypal/form.html:17
+msgid "Subscribe with PayPal"
+msgstr "Subskrypcja przez PayPal"
+
+#: templates/paypal/form.html:20
+msgid "You must be logged in to subscribe."
+msgstr "Musisz się zalogować, aby ustawić subskrypcję."
+
+#: templates/paypal/return.html:8
+msgid "Dziękujemy, że jesteś z nami i pomagasz nam rozwijać Wolne Lektury!"
+msgstr ""
+
+#: templates/paypal/return.html:9
+msgid "Pamiętaj, że zawsze możesz się z nami skontaktować:"
+msgstr ""
+
+#: templates/paypal/return.html:11
+msgid "Do przeczytania!"
+msgstr ""
+
+#: templates/paypal/return.html:11
+msgid "Zespół Wolnych Lektur"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-08-30 15:57+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+
+#: forms.py:10
+msgid "amount in PLN"
+msgstr ""
+
+#: templates/paypal/cancel.html:5
+msgid "Zrezygnowano z płatności :("
+msgstr ""
+
+#: templates/paypal/error.html:1
+msgid "PayPal Error"
+msgstr ""
+
+#: templates/paypal/error.html:5
+msgid "Learn more"
+msgstr ""
+
+#: templates/paypal/form.html:6 templates/paypal/form.html.py:9
+msgid "Wolne Lektury Friend Club"
+msgstr ""
+
+#: templates/paypal/form.html:17
+msgid "Subscribe with PayPal"
+msgstr ""
+
+#: templates/paypal/form.html:20
+msgid "You must be logged in to subscribe."
+msgstr ""
+
+#: templates/paypal/return.html:8
+msgid "Dziękujemy, że jesteś z nami i pomagasz nam rozwijać Wolne Lektury!"
+msgstr ""
+
+#: templates/paypal/return.html:9
+msgid "Pamiętaj, że zawsze możesz się z nami skontaktować:"
+msgstr ""
+
+#: templates/paypal/return.html:11
+msgid "Do przeczytania!"
+msgstr ""
+
+#: templates/paypal/return.html:11
+msgid "Zespół Wolnych Lektur"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-08-30 15:57+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+
+#: forms.py:10
+msgid "amount in PLN"
+msgstr ""
+
+#: templates/paypal/cancel.html:5
+msgid "Zrezygnowano z płatności :("
+msgstr ""
+
+#: templates/paypal/error.html:1
+msgid "PayPal Error"
+msgstr ""
+
+#: templates/paypal/error.html:5
+msgid "Learn more"
+msgstr ""
+
+#: templates/paypal/form.html:6 templates/paypal/form.html.py:9
+msgid "Wolne Lektury Friend Club"
+msgstr ""
+
+#: templates/paypal/form.html:17
+msgid "Subscribe with PayPal"
+msgstr ""
+
+#: templates/paypal/form.html:20
+msgid "You must be logged in to subscribe."
+msgstr ""
+
+#: templates/paypal/return.html:8
+msgid "Dziękujemy, że jesteś z nami i pomagasz nam rozwijać Wolne Lektury!"
+msgstr ""
+
+#: templates/paypal/return.html:9
+msgid "Pamiętaj, że zawsze możesz się z nami skontaktować:"
+msgstr ""
+
+#: templates/paypal/return.html:11
+msgid "Do przeczytania!"
+msgstr ""
+
+#: templates/paypal/return.html:11
+msgid "Zespół Wolnych Lektur"
+msgstr ""
plan = models.ForeignKey(BillingPlan)
active = models.BooleanField(max_length=32)
token = models.CharField(max_length=32)
+
+ def get_agreement(self):
+ from .rest import get_agreement
+ return get_agreement(self.agreement_id)
+
+ def check_agreement(self):
+ from .rest import check_agreement
+ return check_agreement(self.agreement_id)
from django.utils import timezone
from paypalrestsdk import BillingPlan, BillingAgreement, ResourceNotFound
from django.conf import settings
-from .models import BillingPlan as BillingPlanModel
+from .models import BillingPlan as BillingPlanModel, BillingAgreement as BillingAgreementModel
paypalrestsdk.configure(settings.PAYPAL_CONFIG)
return a.state == 'Active'
+def user_is_subscribed(user):
+ agreements = BillingAgreementModel.objects.filter(user=user)
+ return any(agreement.check_agreement() for agreement in agreements)
+
+
def execute_agreement(token):
return BillingAgreement.execute(token)
+{% load i18n %}
<h1>{% trans "PayPal Error" %}: {{ error.message }}</h1>
{% for detail in error.details %}
<p>{{ detail.field }}: {{ detail.issue }}</p>
{% extends "base/base.html" %}
{% load i18n %}
+{% load chunks %}
+{% load static from staticfiles %}
-{% block title %}{% trans "Subscription" %}{% endblock %}
+{% block title %}{% trans "Wolne Lektury Friend Club" %}{% endblock %}
{% block body %}
+ <div class="mobile-margins">
+ <h1>{% trans "Wolne Lektury Friend Club" %}</h1>
+ <p>Poniżej możesz ustawić comiesięczną płatność <strong>(co najmniej 5 zł)</strong>, aby dołączyć do Przyjaciół Wolnych Lektur.</p>
{# https://www.facebook.com/sharer/sharer.php?u=https%3A//wolnelektury.pl{% url 'paypal_form' %} #}
{% if user.is_authenticated %}
<form method="post">
{% csrf_token %}
- {{ form.as_p }}
+ {{ form.amount.label_tag }}{{ form.amount }}
{# paypal submit button #}
- <button type="submit">{% trans "Subscribe with PayPal" %}</button>
+ <input type="image" src="{% static 'img/btn_subscribe_LG_pl.gif' %}" alt="{% trans "Subscribe with PayPal" %}" style="margin-left: 2em; vertical-align: bottom;">
</form>
{% else %}
{% trans "You must be logged in to subscribe." %}
{% endif %}
+ {% chunk "klub_info" %}
+ </div>
{% endblock %}
\ No newline at end of file
urlpatterns = (
url(r'^form/$', views.paypal_form, name='paypal_form'),
- url(r'^app-form/$', views.paypal_form, kwargs={'app': True}, name='paypal_api_form'),
+ url(r'^app-form/$', views.paypal_form, kwargs={'app': True}, name='paypal_app_form'),
url(r'^return/$', views.paypal_return, name='paypal_return'),
- url(r'^app-return/$', views.paypal_return, kwargs={'app': True}, name='paypal_api_return'),
+ url(r'^app-return/$', views.paypal_return, kwargs={'app': True}, name='paypal_app_return'),
url(r'^cancel/$', views.paypal_cancel, name='paypal_cancel'),
)
--- /dev/null
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from django.contrib import admin
+
+from .models import Notification
+
+
+admin.site.register(Notification)
--- /dev/null
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from django import forms
+from django.contrib.sites.models import Site
+
+from push.models import Notification
+from push.utils import send_fcm_push
+
+
+class NotificationForm(forms.ModelForm):
+
+ class Meta:
+ model = Notification
+ exclude = ('timestamp', 'message_id')
+
+ def save(self, commit=True):
+ notification = super(NotificationForm, self).save(commit=commit)
+ wl_base = u'https://' + Site.objects.get_current().domain
+ if notification.image:
+ image_url = wl_base + notification.image.url
+ else:
+ image_url = None
+ notification.message_id = send_fcm_push(notification.title, notification.body, image_url)
+ if commit:
+ notification.save()
--- /dev/null
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Notification',
+ fields=[
+ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+ ('timestamp', models.DateTimeField(auto_now_add=True)),
+ ('title', models.CharField(max_length=256)),
+ ('body', models.CharField(max_length=2048)),
+ ('image_url', models.URLField()),
+ ('message_id', models.CharField(max_length=2048)),
+ ],
+ ),
+ ]
--- /dev/null
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('push', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='notification',
+ options={'ordering': ['-timestamp']},
+ ),
+ migrations.RemoveField(
+ model_name='notification',
+ name='image_url',
+ ),
+ migrations.AddField(
+ model_name='notification',
+ name='image',
+ field=models.FileField(upload_to=b'push/img', verbose_name='image', blank=True),
+ ),
+ migrations.AlterField(
+ model_name='notification',
+ name='body',
+ field=models.CharField(max_length=2048, verbose_name='content'),
+ ),
+ migrations.AlterField(
+ model_name='notification',
+ name='title',
+ field=models.CharField(max_length=256, verbose_name='title'),
+ ),
+ ]
--- /dev/null
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('push', '0002_auto_20180830_1627'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='notification',
+ name='image',
+ field=models.ImageField(upload_to=b'push/img', verbose_name='image', blank=True),
+ ),
+ ]
--- /dev/null
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+
+
+class Notification(models.Model):
+ timestamp = models.DateTimeField(auto_now_add=True)
+ title = models.CharField(max_length=256, verbose_name=_(u'title'))
+ body = models.CharField(max_length=2048, verbose_name=_(u'content'))
+ image = models.ImageField(verbose_name=_(u'image'), blank=True, upload_to='push/img')
+ message_id = models.CharField(max_length=2048)
+
+ class Meta:
+ ordering = ['-timestamp']
+
+ def __unicode__(self):
+ return '%s: %s' % (self.timestamp, self.title)
--- /dev/null
+{% extends "base/base.html" %}
+{% load i18n %}
+
+{% block titleextra %}{% trans "Notifications" %}{% endblock %}
+
+
+{% block body %}
+ <h1>Wyślij powiadomienie</h1>
+
+ <form method="post" class="submit-form" action="" enctype="multipart/form-data">
+ {% csrf_token %}
+ <table>
+ {{ form.as_table }}
+ <tr><td></td><td><button type="submit">Wyślij</button></td></tr>
+ </table>
+ </form>
+{% endblock %}
\ No newline at end of file
--- /dev/null
+{% extends "base/base.html" %}
+{% load i18n %}
+
+{% block titleextra %}{% trans "Notifications" %}{% endblock %}
+
+
+{% block body %}
+ <h1>Wysłano powiadomienie</h1>
+ <p>Gratulacje!</p>
+{% endblock %}
\ No newline at end of file
--- /dev/null
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from django.conf.urls import patterns, url
+
+from push import views
+
+urlpatterns = (
+ url(r'^wyslij/$', views.notification_form, name='notification_form'),
+ url(r'^wyslane/$', views.notification_sent, name='notification_sent'),
+)
--- /dev/null
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+import firebase_admin
+from firebase_admin import credentials, messaging
+from django.conf import settings
+
+cred = credentials.Certificate(settings.FCM_PRIVATE_KEY_PATH)
+firebase_admin.initialize_app(cred)
+
+TOPIC = 'wolnelektury'
+
+
+def send_fcm_push(title, body, image_url=None):
+ # See documentation on defining a message payload.
+ data = {}
+ # data = {
+ # 'title': title,
+ # 'body': body,
+ # }
+ if image_url:
+ data['imageUrl'] = image_url
+ message = messaging.Message(
+ notification=messaging.Notification(
+ title=title,
+ body=body,
+ ),
+ data=data,
+ topic=TOPIC,
+ )
+ message_id = messaging.send(message)
+ return message_id
--- /dev/null
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from django.contrib.auth.decorators import permission_required
+from django.core.urlresolvers import reverse
+from django.http.response import HttpResponseRedirect
+from django.shortcuts import render
+
+from push.forms import NotificationForm
+
+
+@permission_required('push.change_notification')
+def notification_form(request):
+ if request.method == 'POST':
+ form = NotificationForm(data=request.POST, files=request.FILES or None)
+ if form.is_valid():
+ form.save()
+ return HttpResponseRedirect(reverse('notification_sent'))
+ else:
+ form = NotificationForm()
+ return render(request, 'push/notification_form.html', {'form': form})
+
+
+def notification_sent(request):
+ return render(request, 'push/notification_sent.html')
\ No newline at end of file
urlpatterns = patterns(
'search.views',
- url(r'^$', 'main', name='search'),
+ url(r'^$', 'main', name='wlsearch'),
url(r'^hint/$', 'hint', name='search_hint'),
)
u'rozpowszechnianie ich wizerunków.')
+class CoJaCzytamForm(ContactForm):
+ form_tag = 'cojaczytam'
+ form_title = u"#cojaczytam?"
+ admin_list = ['opiekun_nazwisko', 'contact', 'nazwa_kampanii']
+ # ends_on = (2018, 11, 16)
+ disabled_template = 'contact/disabled_contact_form.html'
+ submit_label = u'Wyślij'
+
+ opiekun_nazwisko = forms.CharField(label=u'Imię i nazwisko Opiekuna/ki', max_length=128)
+ contact = forms.EmailField(label=u'Adres e-mail Opiekuna/ki', max_length=128)
+ opiekun_tel = forms.CharField(label=u'Numer telefonu Opiekuna/ki', max_length=32)
+ nazwa_dkk = forms.CharField(label=u'Nazwa szkoły/biblioteki publicznej', max_length=128)
+ adres_dkk = forms.CharField(label=u'Adres szkoły/biblioteki publicznej', max_length=128)
+
+ nazwa_kampanii = forms.CharField(label=u'Nazwa kampanii', max_length=255)
+
+ wiek = forms.ChoiceField(label=u'Grupa wiekowa', choices=(
+ ('9-14', u'uczniowie kl. IV-VIII szkół podstawowych w wieku 9-14 lat,'),
+ ('15-19', u'uczniowie gimnazjum oraz wszystkich typów szkół ponadpodstawowych w wieku 15-19.'),
+ ), widget=forms.RadioSelect)
+
+ uczestnik1_header = HeaderField(label=u'Dane\xa0Uczestników (3 do 5)')
+ uczestnik1_imie = forms.CharField(label=u'Imię', max_length=128)
+ uczestnik1_nazwisko = forms.CharField(label=u'Nazwisko', max_length=128)
+ uczestnik1_email = forms.EmailField(label=u'Adres e-mail', max_length=128)
+ uczestnik2_header = HeaderField(label=u'')
+ uczestnik2_imie = forms.CharField(label=u'Imię', max_length=128)
+ uczestnik2_nazwisko = forms.CharField(label=u'Nazwisko', max_length=128)
+ uczestnik2_email = forms.EmailField(label=u'Adres e-mail', max_length=128)
+ uczestnik3_header = HeaderField(label=u'')
+ uczestnik3_imie = forms.CharField(label=u'Imię', max_length=128)
+ uczestnik3_nazwisko = forms.CharField(label=u'Nazwisko', max_length=128)
+ uczestnik3_email = forms.EmailField(label=u'Adres e-mail', max_length=128)
+ uczestnik4_header = HeaderField(label=u'')
+ uczestnik4_imie = forms.CharField(label=u'Imię', max_length=128, required=False)
+ uczestnik4_nazwisko = forms.CharField(label=u'Nazwisko', max_length=128, required=False)
+ uczestnik4_email = forms.EmailField(label=u'Adres e-mail', max_length=128, required=False)
+ uczestnik5_header = HeaderField(label=u'')
+ uczestnik5_imie = forms.CharField(label=u'Imię', max_length=128, required=False)
+ uczestnik5_nazwisko = forms.CharField(label=u'Nazwisko', max_length=128, required=False)
+ uczestnik5_email = forms.EmailField(label=u'Adres e-mail', max_length=128, required=False)
+
+ ankieta_header = HeaderField(label=u'')
+ opis_kampanii = forms.CharField(
+ label=u'Krótki opis realizacji oraz przebiegu kampanii', max_length=255, widget=forms.Textarea)
+ co_sie_udalo = forms.CharField(label=u'Co udało Wam się zrealizować?', max_length=1024, widget=forms.Textarea)
+ co_sie_nie_udalo = forms.CharField(
+ label=u'Czy jest coś, co chcieliście zrealizować, a się nie udało? Jeśli tak, to dlaczego?', max_length=1024,
+ widget=forms.Textarea)
+ wnioski = forms.CharField(
+ label=u'Jakie wnioski na przyszłość wyciągnęliście z tego, czego się nie udało zrealizować?', max_length=1024,
+ widget=forms.Textarea)
+ zasieg = forms.CharField(
+ label=u'Do ilu odbiorców udało Wam się dotrzeć z Waszą kompanią? Podaj liczbę, może być szacunkowa.',
+ max_length=1024, widget=forms.Textarea)
+ grupy_odbiorcow = forms.CharField(
+ label=u'Do jakich grup odbiorców dotarliście (np. uczniowie, nauczyciele, rodzice, seniorzy, inni)?',
+ max_length=1024, widget=forms.Textarea)
+ plik = forms.FileField(
+ label=u'Plik .zip ze stworzonymi materiałami (np. zdjęcia, dokumenty tekstowe)')
+ materialy = forms.CharField(
+ label=u'Adresy stworzonych materiałów online (jeśli dotyczy)', max_length=1024, widget=forms.Textarea,
+ required=False)
+
+ agree_header = HeaderField(label=u'Oświadczenia')
+ agree_terms = forms.BooleanField(
+ label='Regulamin',
+ help_text=mark_safe_lazy(
+ u'Znam i akceptuję <a href="/media/chunks/attachment/Regulamin_konkursu_cojaczytam_edycja_2018.pdf">'
+ u'Regulamin Konkursu</a>.'),
+ )
+ agree_data = forms.BooleanField(
+ label='Przetwarzanie danych osobowych',
+ help_text=u'Oświadczam, że wyrażam zgodę na przetwarzanie danych osobowych zawartych w niniejszym formularzu '
+ u'zgłoszeniowym przez Fundację Nowoczesna Polska (administratora danych) z siedzibą w Warszawie (00-514) '
+ u'przy ul. Marszałkowskiej 84/92 lok. 125 na potrzeby organizacji Konkursu. Jednocześnie oświadczam, '
+ u'że zostałam/em poinformowana/y o tym, że mam prawo wglądu w treść swoich danych i możliwość ich '
+ u'poprawiania oraz że ich podanie jest dobrowolne, ale niezbędne do dokonania zgłoszenia.')
+ agree_license = forms.BooleanField(
+ label='Licencja',
+ help_text=mark_safe_lazy(
+ u'Wyrażam zgodę oraz potwierdzam, że uczestnicy (lub ich przedstawiciele ustawowi – gdy dotyczy) '
+ u'wyrazili zgodę na korzystanie ze stworzonych materiałów zgodnie z postanowieniami '
+ u'<a href="http://freedomdefined.org/Definition/Pl">wolnej licencji</a>, takiej jak '
+ u'<a href="https://creativecommons.org/licenses/by-sa/3.0/pl/">Creative Commons Uznanie autorstwa – '
+ u'Na tych samych warunkach 3.0 PL</a>. Licencja pozwala każdemu na swobodne, nieodpłatne korzystanie '
+ u'z utworu '
+ u'w oryginale oraz w postaci opracowań do wszelkich celów wymagając poszanowania autorstwa i innych praw '
+ u'osobistych oraz tego, aby ewentualne opracowania utworu były także udostępniane na tej samej licencji.'))
+ agree_wizerunek = forms.BooleanField(
+ label='Rozpowszechnianie wizerunku',
+ help_text=u'Wyrażam zgodę oraz potwierdzam, że uczestnicy (lub ich przedstawiciele ustawowi – gdy dotyczy) '
+ u'wyrazili zgodę na fotografowanie oraz nagrywanie, a następnie rozpowszechnianie ich '
+ u'wizerunków w celach promocyjnych.')
+
+
class WorkshopsForm(ContactForm):
form_tag = 'warsztaty'
form_title = u"Wolne Lektury Fest"
u'24.11.2017 roku i następnie rozpowszechnianie mojego wizerunku w celach promocyjnych.')
agree_gala = forms.BooleanField(
label=u'Wezmę udział w uroczystej gali o godz. 19.00.', required=False)
+
+
+class WLFest2018Form(ContactForm):
+ form_tag = 'wlfest2018'
+ form_title = u"Wolne Lektury Fest"
+ nazwisko = forms.CharField(label=u'Imię i nazwisko uczestnika', max_length=128)
+ instytucja = forms.CharField(label=u'Instytucja/organizacja', max_length=128, required=False)
+ contact = forms.EmailField(label=u'Adres e-mail', max_length=128)
+ tel = forms.CharField(label=u'Numer telefonu', max_length=32)
+ warsztaty = forms.MultipleChoiceField(choices=(
+ ('kim-sa-odbiorcy', u'Kim są odbiorcy zdigitalizowanych zasobów kultury w Polsce? (9:30-11:30)'),
+ ('business-model-canvas', u'Business Model Canvas dla kultury (9:30-11:30)'),
+ ('jak-byc-glam', u'Jak być GLAM? Współpraca pomiędzy instytucjami kultury a Wikipedią (12:00-14:00)'),
+ ('wirtualne-muzea', u'Jak twórczo i zgodnie z prawem wykorzystywać zasoby dziedzictwa kulturowego '
+ u'na przykładzie portalu „Wirtualne Muzea Małopolski” (12:00-14:00)'),
+ ('jak-legalnie-tworzyc', u'Jak legalnie tworzyć i korzystać z cudzej twórczości (15:00-17:00)'),
+ ('aplikacje-w-dzialaniach', u'Aplikacje w działaniach kulturalnych (15:00-17:00)')),
+ widget=forms.CheckboxSelectMultiple,
+ )
+ agree_header = HeaderField(label=mark_safe_lazy(u'<strong>Oświadczenia</strong>'))
+ agree_data = forms.BooleanField(
+ label='Przetwarzanie danych osobowych',
+ help_text=u'Administratorem danych osobowych przetwarzanych w związku z organizacją wydarzenia '
+ u'„WOLNE LEKTURY FEST” jest Fundacja Nowoczesna Polska '
+ u'(ul. Marszałkowska 84/92 lok. 125, 00-514 Warszawa). Podanie danych osobowych jest konieczne '
+ u'do dokonania rejestracji na wydarzenie. Dane są przetwarzane w zakresie niezbędnym '
+ u'do przeprowadzenia wydarzenia, a także w celach prowadzenia statystyk, '
+ u'ewaluacji i sprawozdawczości. Osobom, których dane są zbierane, przysługuje prawo dostępu '
+ u'do treści swoich danych oraz ich poprawiania. Więcej informacji w polityce prywatności '
+ u'(https://nowoczesnapolska.org.pl/prywatnosc/).')
+ agree_wizerunek = forms.BooleanField(
+ label='Rozpowszechnianie wizerunku',
+ help_text=u'Wyrażam zgodę na fotografowanie i nagrywanie podczas warsztatów „WOLNE LEKTURY FEST” '
+ u'28.11.2018 roku i następnie rozpowszechnianie mojego wizerunku w celach promocyjnych.')
+ agree_gala = forms.BooleanField(
+ label=u'Wezmę udział w spotkaniu z Julią Fiedorczuk o godz. 17:30.', required=False)
# -*- coding: utf-8 -*-
# Django settings for wolnelektury project.
+from .apps import *
from .basic import *
from .auth import *
from .cache import *
from .static import *
from .paths import *
-
-MIDDLEWARE_CLASSES = [
- 'django.middleware.csrf.CsrfViewMiddleware',
- 'ssify.middleware.SsiMiddleware',
- 'django.middleware.cache.UpdateCacheMiddleware',
- 'ssify.middleware.PrepareForCacheMiddleware',
- 'django.middleware.common.CommonMiddleware',
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'django.contrib.admindocs.middleware.XViewMiddleware',
- 'fnp_django_pagination.middleware.PaginationMiddleware',
- 'ssify.middleware.LocaleMiddleware',
- 'maintenancemode.middleware.MaintenanceModeMiddleware',
- 'django.middleware.common.CommonMiddleware',
- 'django.contrib.messages.middleware.MessageMiddleware',
- 'fnpdjango.middleware.SetRemoteAddrFromXRealIP',
- 'django.middleware.cache.FetchFromCacheMiddleware',
-]
-
-ROOT_URLCONF = 'wolnelektury.urls'
-
-# These are the ones we should test.
-INSTALLED_APPS_OUR = [
- 'wolnelektury',
- # our
- 'ajaxable',
- 'api',
- 'catalogue',
- 'chunks',
- 'dictionary',
- 'infopages',
- 'lesmianator',
- 'newtagging',
- 'opds',
- 'pdcounter',
- 'reporting',
- 'sponsors',
- 'stats',
- 'suggest',
- 'picture',
- 'social',
- 'waiter',
- 'search',
- 'oai',
- 'funding',
- 'polls',
- 'libraries',
- 'newsletter',
- 'contact',
- 'isbn',
- 'paypal',
-]
-
-GETPAID_BACKENDS = (
- 'getpaid.backends.payu',
-)
-
-INSTALLED_APPS_CONTRIB = [
- # Should be before django.contrib.admin
- 'modeltranslation',
-
- # external
- 'django.contrib.auth',
- 'django.contrib.contenttypes',
- 'django.contrib.sessions',
- 'django.contrib.sites',
- 'django.contrib.admin',
- 'django.contrib.admindocs',
- 'django.contrib.staticfiles',
- 'fnp_django_pagination',
- 'pipeline',
- 'piston',
- 'piwik',
- 'sorl.thumbnail',
- 'kombu.transport.django',
- 'honeypot',
- 'fnpdjango',
- 'getpaid',
- 'getpaid.backends.payu',
- 'ssify',
- 'django_extensions',
- 'raven.contrib.django.raven_compat',
-
- 'migdal',
- 'django_comments',
- 'django_comments_xtd',
-
- # allauth stuff
- 'uni_form',
- 'allauth',
- 'allauth.account',
- 'allauth.socialaccount',
- 'allauth.socialaccount.providers.openid',
- 'allauth.socialaccount.providers.facebook',
- 'allauth.socialaccount.providers.google',
- # 'allauth.socialaccount.providers.twitter',
- ]
-
-INSTALLED_APPS = INSTALLED_APPS_OUR + INSTALLED_APPS_CONTRIB
-
# Load localsettings, if they exist
try:
from wolnelektury.localsettings import *
--- /dev/null
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+# These are the ones we should test.
+INSTALLED_APPS_OUR = [
+ 'wolnelektury',
+ # our
+ 'ajaxable',
+ 'api',
+ 'catalogue',
+ 'chunks',
+ 'dictionary',
+ 'infopages',
+ 'lesmianator',
+ 'newtagging',
+ 'opds',
+ 'pdcounter',
+ 'reporting',
+ 'sponsors',
+ 'stats',
+ 'suggest',
+ 'picture',
+ 'social',
+ 'waiter',
+ 'search',
+ 'oai',
+ 'funding',
+ 'polls',
+ 'libraries',
+ 'newsletter',
+ 'contact',
+ 'isbn',
+ 'paypal',
+ 'push',
+]
+
+INSTALLED_APPS_CONTRIB = [
+ # Should be before django.contrib.admin
+ 'modeltranslation',
+
+ # external
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.sites',
+ 'django.contrib.admin',
+ 'django.contrib.admindocs',
+ 'django.contrib.staticfiles',
+ 'fnp_django_pagination',
+ 'pipeline',
+ 'piston',
+ 'piwik',
+ 'sorl.thumbnail',
+ 'kombu.transport.django',
+ 'honeypot',
+ 'fnpdjango',
+ 'getpaid',
+ 'getpaid.backends.payu',
+ 'ssify',
+ 'django_extensions',
+ 'raven.contrib.django.raven_compat',
+
+ 'migdal',
+ 'django_comments',
+ 'django_comments_xtd',
+ 'django_gravatar',
+
+ # allauth stuff
+ 'uni_form',
+ 'allauth',
+ 'allauth.account',
+ 'allauth.socialaccount',
+ 'allauth.socialaccount.providers.openid',
+ 'allauth.socialaccount.providers.facebook',
+ 'allauth.socialaccount.providers.google',
+ # 'allauth.socialaccount.providers.twitter',
+]
+
+INSTALLED_APPS = INSTALLED_APPS_OUR + INSTALLED_APPS_CONTRIB
),
},
}]
+
+MIDDLEWARE_CLASSES = [
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'ssify.middleware.SsiMiddleware',
+ 'django.middleware.cache.UpdateCacheMiddleware',
+ 'ssify.middleware.PrepareForCacheMiddleware',
+ 'django.middleware.common.CommonMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.admindocs.middleware.XViewMiddleware',
+ 'fnp_django_pagination.middleware.PaginationMiddleware',
+ 'ssify.middleware.LocaleMiddleware',
+ 'maintenancemode.middleware.MaintenanceModeMiddleware',
+ 'django.middleware.common.CommonMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ 'fnpdjango.middleware.SetRemoteAddrFromXRealIP',
+ 'django.middleware.cache.FetchFromCacheMiddleware',
+]
+
+ROOT_URLCONF = 'wolnelektury.urls'
# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
#
from fnpdjango.utils.text.textilepl import textile_pl
+from migdal import EntryType
+from django.utils.translation import ugettext_lazy as _
HONEYPOT_FIELD_NAME = 'miut'
PAGINATION_INVALID_PAGE_RAISES_404 = True
GETPAID_ORDER_DESCRIPTION = "{% load funding_tags %}{{ order|sanitize_payment_title }}"
+GETPAID_BACKENDS = (
+ 'getpaid.backends.payu',
+)
+
PIWIK_URL = ''
PIWIK_SITE_ID = 0
PIWIK_TOKEN = ''
MARKUP_FIELD_TYPES = (
('textile_pl', textile_pl),
)
+
+MIGDAL_TYPES = (
+ EntryType('news', _('news'), commentable=False, on_main=True, promotable=True),
+ EntryType('publications', _('publications'), commentable=False),
+ EntryType('info', _('info'), commentable=False),
+ EntryType('event', _('events'), commentable=False),
+)
background: #f7f7f7;
color: black;
- @include size(font-size, 13px);
+ @include size(font-size, 15px);
}
a {
}
h2 {
- @include size(font-size, 20px);
+ @include size(font-size, 23px);
font-weight: normal;
}
h3 {
- @include size(font-size, 15px);
+ @include size(font-size, 17px);
font-weight: normal;
}
.left-column, .right-column {
@include size(max-width, 600px);
+ @include size(padding-left, 1em);
+ @include size(padding-right, 1em);
}
@media screen and (min-width: 62.5em) {
- .left-column {
+ .left-column, .right-column {
@include size(width, 470px);
+ padding-left: 0;
+ padding-right: 0;
+ }
+
+ .left-column {
float: left;
}
.right-column {
- @include size(width, 470px);
float: right;
}
}
@include size(margin-bottom, 10px);
}
}
+
+@media screen and (max-width: 62.5em) {
+ .mobile-margins {margin-left: 1em; margin-right: 1em;}
+}
</li>
</ul>
</nav>
- <form id="search-area" action="{% url 'search' %}">
+ <form id="search-area" action="{% url 'wlsearch' %}">
<div id="search-field">
<label for="search">{{ search_form.q.label }}</label>
{{ search_form.q }}
--- /dev/null
+{% extends "contact/form.html" %}
+
+{% block body %}
+ {{ block.super }}
+ <p><a href="{{ MEDIA_URL }}chunks/attachment/Zgoda_dla_rodzic%C3%B3w.doc">Formularz zgody dla rodziców i opiekunów</a></p>
+{% endblock %}
\ No newline at end of file
from django.contrib import admin
from django.views.generic import RedirectView
import django.views.static
+from migdal.urls import urlpatterns as migdal_urlpatterns
import catalogue.views
import picture.views
from . import views
url(r'^formularz/', include('contact.urls')),
url(r'^isbn/', include('isbn.urls')),
url(r'^paypal/', include('paypal.urls')),
+ url(r'^powiadomienie/', include('push.urls')),
# Admin panel
url(r'^admin/catalogue/book/import$', catalogue.views.import_book, name='import_book'),
url(r'^error-test/$', views.exception_test),
# url(r'^post-test/$', views.post_test),
]
+
+urlpatterns += migdal_urlpatterns