@register.filter
def pretty_field(field, template=None):
if template is None:
- template = '''
+ template = u'''
<li>
<span class="error">%(errors)s</span>
<label class="nohide"><span class="label">%(label)s: </span>%(input)s</label>
return mark_safe(template % {
'errors': field.errors,
'input': field,
- 'label': force_unicode(field.label),
+ 'label': ('*' if field.field.required else '') + force_unicode(field.label),
'helptext': force_unicode(field.help_text),
})
def placeholdized(form):
for field in form.fields.values():
- field.widget.attrs['placeholder'] = field.label
+ field.widget.attrs['placeholder'] = field.label + ('*' if field.required else '')
return form
"""
allowed_methods = ['GET']
fields = ['title', 'parent', 'children'] + Book.formats + [
- 'media', 'url', 'cover', 'cover_thumb', 'simple_thumb', 'simple_cover', 'fragment_data', 'preview'] + [
+ 'media', 'url', 'cover', 'cover_thumb', 'simple_thumb', 'simple_cover', 'fragment_data', 'audio_length',
+ 'preview'] + [
category_plural[c] for c in book_tag_categories]
@piwik_track
"""
allowed_methods = ('GET',)
model = Book
- fields = book_tag_categories + ['href', 'title', 'url', 'cover', 'cover_thumb', 'slug', 'simple_thumb']
+ fields = book_tag_categories + ['href', 'title', 'url', 'cover', 'cover_thumb', 'slug', 'simple_thumb', 'has_audio']
@classmethod
def genres(cls, book):
class FilterBooksHandler(AnonymousBooksHandler):
fields = book_tag_categories + [
- 'href', 'title', 'url', 'cover', 'cover_thumb', 'simple_thumb', 'slug', 'key']
+ 'href', 'title', 'url', 'cover', 'cover_thumb', 'simple_thumb', 'has_audio', 'slug', 'key']
def parse_bool(self, s):
if s in ('true', 'false'):
for book_format in Book.formats:
setattr(BookDetails, book_format, _file_getter(book_format))
+
add_file_getters()
"""
try:
- tags, ancestors = read_tags(tags, allowed=self.categories)
+ tags, ancestors = read_tags(tags, request, allowed=self.categories)
except ValueError:
return rc.NOT_FOUND
fragments = Fragment.tagged.with_all(tags).select_related('book')
return rc.NOT_FOUND
after = request.GET.get('after')
count = int(request.GET.get('count', 50))
- ids = BookUserData.objects.filter(user=request.user, complete=state == 'complete').values_list('book_id', flat=True)
+ 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')
if after:
books = books.filter(slug__gt=after)
--- /dev/null
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('catalogue', '0023_book_abstract'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='book',
+ name='audio_length',
+ field=models.CharField(max_length=8, verbose_name='audio length', blank=True),
+ ),
+ ]
--- /dev/null
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('catalogue', '0024_book_audio_length'),
+ ('catalogue', '0024_auto_20180510_1407'),
+ ]
+
+ operations = [
+ ]
wiki_link = models.CharField(blank=True, max_length=240)
print_on_demand = models.BooleanField(_('print on demand'), default=False)
recommended = models.BooleanField(_('recommended'), default=False)
+ audio_length = models.CharField(_('audio length'), blank=True, max_length=8)
preview = models.BooleanField(_('preview'), default=False)
preview_until = models.DateField(_('preview until'), blank=True, null=True)
def is_foreign(self):
return self.language_code() != settings.LANGUAGE_CODE
+ def set_audio_length(self):
+ length = self.get_audio_length()
+ if length > 0:
+ self.audio_length = self.format_audio_length(length)
+ self.save()
+
+ @staticmethod
+ def format_audio_length(seconds):
+ if seconds < 60*60:
+ minutes = seconds // 60
+ seconds = seconds % 60
+ return '%d:%02d' % (minutes, seconds)
+ else:
+ hours = seconds // 3600
+ minutes = seconds % 3600 // 60
+ seconds = seconds % 60
+ return '%d:%02d:%02d' % (hours, minutes, seconds)
+
+ def get_audio_length(self):
+ from mutagen.mp3 import MP3
+ total = 0
+ for media in self.get_mp3():
+ audio = MP3(media.file.path)
+ total += audio.info.length
+ return int(total)
+
def has_media(self, type_):
if type_ in Book.formats:
return bool(getattr(self, "%s_file" % type_))
has_description.short_description = _('description')
has_description.boolean = True
- # ugly ugly ugly
def has_mp3_file(self):
- return bool(self.has_media("mp3"))
+ return self.has_media("mp3")
has_mp3_file.short_description = 'MP3'
has_mp3_file.boolean = True
def has_ogg_file(self):
- return bool(self.has_media("ogg"))
+ return self.has_media("ogg")
has_ogg_file.short_description = 'OGG'
has_ogg_file.boolean = True
def has_daisy_file(self):
- return bool(self.has_media("daisy"))
+ return self.has_media("daisy")
has_daisy_file.short_description = 'DAISY'
has_daisy_file.boolean = True
default=''
).contribute_to_class(Book, field_name)
+
add_file_fields()
@receiver([post_save, post_delete], sender=BookMedia)
def bookmedia_save(sender, instance, **kwargs):
+ instance.book.set_audio_length()
instance.book.save()
{% else %}
<p class="book-box-tools">{% trans "For now this work is only available for our subscribers." %}</p>
{% endif %}
- <div class="clearboth"></div>
- {% if book.abstract %}
- <div class="abstract more">
- {{ book.abstract|safe }}
- </div>
- {% endif %}
{% block book-box-extra-info %}{% endblock %}
- {% block box-append %}
- {% endblock %}
+ {% block box-append %}{% endblock %}
</div>
+ {% if book.abstract %}
+ <div class="abstract more">
+ {{ book.abstract|safe }}
+ </div>
+ {% endif %}
{% endwith %}
{% block right-column %}
def data_processing(self):
return mark_safe('%s %s %s' % (self.data_processing_part1, self.data_processing_part2, self.data_processing_part3))
- def save(self):
+ def save(self, *args, **kwargs):
try:
# multiple inheritance mode
- super(NewsletterForm, self).save()
+ super(NewsletterForm, self).save(*args, **kwargs)
except AttributeError:
pass
if not self.cleaned_data.get('agree_newsletter'):
# -*- coding: utf-8 -*-
+from allauth.socialaccount.forms import SignupForm
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
def save(self, commit=True):
super(RegistrationForm, self).save(commit=commit)
NewsletterForm.save(self)
+
+
+class SocialSignupForm(NewsletterForm, SignupForm):
+ data_processing_part2 = u'''\
+Dane są przetwarzane w zakresie niezbędnym do prowadzenia serwisu, a także w celach prowadzenia statystyk, \
+ewaluacji i sprawozdawczości. W przypadku wyrażenia dodatkowej zgody adres e-mail zostanie wykorzystany \
+także w celu przesyłania newslettera Wolnych Lektur.'''
+
+ def save(self, *args, **kwargs):
+ super(SocialSignupForm, self).save(*args, **kwargs)
--- /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 allauth.socialaccount.models import SocialAccount
+from django.core.management.base import BaseCommand
+
+
+KEPT_FIELDS = {
+ 'facebook': ['link', 'name', 'id', 'locale', 'timezone', 'updated_time', 'verified'],
+ 'google': ['name', 'picture', 'locale', 'id', 'verified_email', 'link'],
+}
+
+
+class Command(BaseCommand):
+ def handle(self, *args, **options):
+ for provider, kept_fields in KEPT_FIELDS.iteritems():
+ for sa in SocialAccount.objects.filter(provider=provider):
+ trimmed_data = {k: v for k, v in sa.extra_data.iteritems() if k in kept_fields}
+ sa.extra_data = trimmed_data
+ sa.save()
@media screen and (min-width: 1024px) {
display: inline-block;
@include size(width, 590px);
+ @include size(min-height, 196px);
}
}
@media screen and (min-width: 62.5em) {
float: left;
@include size(width, 536px);
+ @include size(min-height, 196px);
}
}
overflow: hidden;
position: relative;
+ @media screen and (min-width: 62.5em) {
+ @include size(width, 536px);
+ }
+
p.paragraph {
margin-bottom: 0;
margin-top: 1.2em;
--- /dev/null
+{% extends "socialaccount/base.html" %}
+
+{% load i18n %}
+{% load ajaxable_tags %}
+
+{% block head_title %}{% trans "Signup" %}{% endblock %}
+
+{% block content %}
+ <h1>{% trans "Sign Up" %}</h1>
+
+<p>{% blocktrans with provider_name=account.get_provider.name site_name=site.name %}You are about to use your {{provider_name}} account to login to
+{{site_name}}. As a final step, please complete the following form:{% endblocktrans %}</p>
+
+<form class="signup cuteform" id="signup_form" method="post" action="{% url 'socialaccount_signup' %}">
+ {% csrf_token %}
+ <ul>
+ {{ form.username|pretty_field }}
+ {{ form.email|pretty_field }}
+ {{ form.agree_newsletter|pretty_checkbox }}
+ </ul>
+ {% if redirect_field_value %}
+ <input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
+ {% endif %}
+ <p><span class="helptext">{{ form.data_processing }}</span></p>
+ <button type="submit">{% trans "Sign Up" %} »</button>
+</form>
+
+{% endblock %}
url(r'^uzytkownik/signup/$', views.RegisterFormView(), name='register'),
url(r'^uzytkownik/logout/$', views.logout_then_redirect, name='logout'),
url(r'^uzytkownik/zaloguj-utworz/$', views.LoginRegisterFormView(), name='login_register'),
+ url(r'^uzytkownik/social/signup/$', views.SocialSignupView.as_view(), name='socialaccount_signup'),
# Includes.
url(r'^latests_blog_posts.html$', views.latest_blog_posts, name='latest_blog_posts'),
#
from datetime import date, datetime
import feedparser
+from allauth.socialaccount.views import SignupView
from django.conf import settings
from django.contrib import auth
from django.contrib.auth.decorators import login_required
-from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
+from django.contrib.auth.forms import AuthenticationForm
from django.core.cache import cache
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from ssify import ssi_included
from social.utils import get_or_choose_cite
-from wolnelektury.forms import RegistrationForm
+from wolnelektury.forms import RegistrationForm, SocialSignupForm
def main_page(request):
return render(request, 'widget.html')
+class SocialSignupView(SignupView):
+ form_class = SocialSignupForm
+
+
def exception_test(request):
msg = request.GET.get('msg')
if msg: