From 1076830cbd3a839d1f332100bf3ac6b1fb24c86a Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Thu, 7 Apr 2022 11:59:32 +0200 Subject: [PATCH] Preview access for book funders. --- src/catalogue/models/book.py | 7 ++++++- src/catalogue/templatetags/catalogue_tags.py | 2 +- src/catalogue/views.py | 6 +++--- src/funding/admin.py | 1 + src/funding/forms.py | 4 +++- src/funding/migrations/0006_funding_user.py | 21 +++++++++++++++++++ src/funding/models.py | 1 + src/funding/templates/funding/email/base.txt | 4 ++-- .../templates/funding/email/published.txt | 13 ++++++++++-- src/funding/urls.py | 1 + src/funding/views.py | 20 +++++++++++++++--- 11 files changed, 67 insertions(+), 13 deletions(-) create mode 100644 src/funding/migrations/0006_funding_user.py diff --git a/src/catalogue/models/book.py b/src/catalogue/models/book.py index d3eddfd71..9de495029 100644 --- a/src/catalogue/models/book.py +++ b/src/catalogue/models/book.py @@ -230,7 +230,12 @@ class Book(models.Model): if not self.preview: return True Membership = apps.get_model('club', 'Membership') - return Membership.is_active_for(user) + if Membership.is_active_for(user): + return True + Funding = apps.get_model('funding', 'Funding') + if Funding.objects.filter(user=user, offer__book=self): + return True + return False def save(self, force_insert=False, force_update=False, **kwargs): from sortify import sortify diff --git a/src/catalogue/templatetags/catalogue_tags.py b/src/catalogue/templatetags/catalogue_tags.py index 8124b349c..93950d73c 100644 --- a/src/catalogue/templatetags/catalogue_tags.py +++ b/src/catalogue/templatetags/catalogue_tags.py @@ -509,7 +509,7 @@ def strip_tag(html, tag_name): def status(book, user): if not book.preview: return 'open' - elif Membership.is_active_for(user): + elif book.is_accessible_to(user): return 'preview' else: return 'closed' diff --git a/src/catalogue/views.py b/src/catalogue/views.py index fe4b2bfae..037345bf1 100644 --- a/src/catalogue/views.py +++ b/src/catalogue/views.py @@ -19,7 +19,7 @@ from django.views.decorators.cache import never_cache from ajaxable.utils import AjaxableFormView from club.forms import ScheduleForm -from club.models import Club, Membership +from club.models import Club from annoy.models import DynamicTextInsert from pdcounter import views as pdcounter_views from picture.models import Picture, PictureArea @@ -328,7 +328,7 @@ def player(request, slug): def book_text(request, slug): book = get_object_or_404(Book, slug=slug) - if book.preview and not Membership.is_active_for(request.user): + if not book.is_accessible_to(request.user): return HttpResponseRedirect(book.get_absolute_url()) if not book.has_html_file(): @@ -427,7 +427,7 @@ class CustomPDFFormView(AjaxableFormView): def validate_object(self, obj, request): book = obj - if book.preview and not Membership.is_active_for(request.user): + if not book.is_accessible_to(request.user): return HttpResponseRedirect(book.get_absolute_url()) return super(CustomPDFFormView, self).validate_object(obj, request) diff --git a/src/funding/admin.py b/src/funding/admin.py index 27109e696..f2b1020a4 100644 --- a/src/funding/admin.py +++ b/src/funding/admin.py @@ -62,6 +62,7 @@ class FundingAdmin(admin.ModelAdmin): list_display = ['payed_at', 'offer', 'amount', 'name', 'email', 'perk_names'] search_fields = ['name', 'email', 'offer__title', 'offer__author'] list_filter = [PayedFilter, 'offer', PerksFilter] + search_fields = ['user'] actions = [export_as_csv_action( fields=[ 'id', 'offer', 'name', 'email', 'amount', 'payed_at', diff --git a/src/funding/forms.py b/src/funding/forms.py index ef797740f..f56c08776 100644 --- a/src/funding/forms.py +++ b/src/funding/forms.py @@ -29,8 +29,9 @@ class FundingForm(NewsletterForm): W przypadku podania danych zostaną one wykorzystane w sposób podany powyżej, a w przypadku wyrażenia dodatkowej zgody adres e-mail zostanie wykorzystany także w celu przesyłania newslettera Wolnych Lektur.''' - def __init__(self, offer, *args, **kwargs): + def __init__(self, request, offer, *args, **kwargs): self.offer = offer + self.user = request.user if request.user.is_authenticated else None super(FundingForm, self).__init__(*args, **kwargs) self.fields['amount'].widget.form_instance = self @@ -57,6 +58,7 @@ adres e-mail zostanie wykorzystany także w celu przesyłania newslettera Wolnyc email=self.cleaned_data['email'], amount=self.cleaned_data['amount'], language_code=get_language(), + user=self.user, ) funding.perks.set(funding.offer.get_perks(funding.amount)) return funding diff --git a/src/funding/migrations/0006_funding_user.py b/src/funding/migrations/0006_funding_user.py new file mode 100644 index 000000000..c295b2e45 --- /dev/null +++ b/src/funding/migrations/0006_funding_user.py @@ -0,0 +1,21 @@ +# Generated by Django 2.2.27 on 2022-04-07 08:38 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('funding', '0005_auto_20210120_1358'), + ] + + operations = [ + migrations.AddField( + model_name='funding', + name='user', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/src/funding/models.py b/src/funding/models.py index 289ec3379..0e3fa425d 100644 --- a/src/funding/models.py +++ b/src/funding/models.py @@ -270,6 +270,7 @@ class Funding(models.Model): offer = models.ForeignKey(Offer, models.PROTECT, verbose_name=_('offer')) name = models.CharField(_('name'), max_length=127, blank=True) email = models.EmailField(_('email'), blank=True, db_index=True) + user = models.ForeignKey(settings.AUTH_USER_MODEL, models.SET_NULL, blank=True, null=True) amount = models.DecimalField(_('amount'), decimal_places=2, max_digits=10) payed_at = models.DateTimeField(_('payed at'), null=True, blank=True, db_index=True) perks = models.ManyToManyField(Perk, verbose_name=_('perks'), blank=True) diff --git a/src/funding/templates/funding/email/base.txt b/src/funding/templates/funding/email/base.txt index 101cec601..f147469af 100644 --- a/src/funding/templates/funding/email/base.txt +++ b/src/funding/templates/funding/email/base.txt @@ -2,11 +2,11 @@ {% block body %} {% endblock %}{% get_current_language as LANGUAGE_CODE %} {% if LANGUAGE_CODE == 'pl' %}Chcesz wiedzieć więcej o działaniach realizowanych w ramach projektu Wolne Lektury? -Zapisz się na nasz newsletter http://{{ site.domain }}{% url 'subscribe' %}, a już nigdy nie przegapisz żadnej publikacji nowej książki czy kolejnej zbiórki.{% endif %} +Zapisz się na nasz newsletter https://{{ site.domain }}{% url 'subscribe' %}, a już nigdy nie przegapisz żadnej publikacji nowej książki czy kolejnej zbiórki.{% endif %} {% blocktrans %}Cheers, Wolne Lektury team{% endblocktrans %} -- {% blocktrans %}If you don't want to receive any more updates, please visit this page:{% endblocktrans %} -http://{{site.domain}}{{ funding.get_disable_notifications_url }} +https://{{site.domain}}{{ funding.get_disable_notifications_url }} {% endautoescape %} diff --git a/src/funding/templates/funding/email/published.txt b/src/funding/templates/funding/email/published.txt index 672efa2ae..fbc71add2 100644 --- a/src/funding/templates/funding/email/published.txt +++ b/src/funding/templates/funding/email/published.txt @@ -4,14 +4,23 @@ {% blocktrans %}we have just published the book you contributed to:{% endblocktrans %} {{ author }} – {{ offer.book.title }} - http://{{ site.domain }}{{ offer.book.get_absolute_url }} + https://{{ site.domain }}{{ offer.book.get_absolute_url }} +{% if book.preview %} +Dzięki Tobie, niedługo będzie bezpłatnie dla wszystkich w wielu formatach. Tymczasem możesz przeczytać ją już teraz jako prapremierę. +{% if funding.user %}Wystarczy, że zalogujesz się na Wolnych Lekturach (jako {{ funding.user.username }}). +{% else %}Wystarczy, że zalogujesz się na Wolnych Lekturach i wejdziesz pod ten adres, aby uzyskać wcześniejszy dostęp: +https://{{ site.domain }}{% url 'funding_claim' funding.notify_key %} +{% endif %} +{% else %} {% blocktrans %}Thanks to you, it is now available for free, in various formats, to everyone.{% endblocktrans %} +{% endif %} + {% if current %} {% blocktrans %}If you'd like to help liberate another book, or invite your friends to do so, we're currently raising money for:{% endblocktrans %} {{ current.author }} – {{ current.title }} - http://{{ site.domain }}{% url 'funding_current' %} + https://{{ site.domain }}{% url 'funding_current' %} {% endif %}{% endblock %} diff --git a/src/funding/urls.py b/src/funding/urls.py index d7289378e..fd9708fdd 100644 --- a/src/funding/urls.py +++ b/src/funding/urls.py @@ -18,6 +18,7 @@ urlpatterns = [ path('niepowodzenie/', banner_exempt(views.NoThanksView.as_view()), name='funding_nothanks'), path('wylacz_email/', banner_exempt(views.DisableNotifications.as_view()), name='funding_disable_notifications'), + path('przylacz//', banner_exempt(views.claim), name='funding_claim'), path('getpaid/', include('getpaid.urls')), ] diff --git a/src/funding/views.py b/src/funding/views.py index 5d4669e66..750f021d7 100644 --- a/src/funding/views.py +++ b/src/funding/views.py @@ -1,9 +1,10 @@ # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later. # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. # -from django.http import Http404 +from django.http import Http404, HttpResponseRedirect from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse +from django.contrib.auth.decorators import login_required from django.views.decorators.csrf import csrf_exempt from django.views.generic import TemplateView, FormView, ListView from getpaid.models import Payment @@ -92,9 +93,9 @@ class OfferDetailView(FormView): if form_class is None: form_class = self.get_form_class() if self.request.method == 'POST': - return form_class(self.object, self.request.POST) + return form_class(self.request, self.object, self.request.POST) else: - return form_class(self.object, initial={'amount': app_settings.DEFAULT_AMOUNT}) + return form_class(self.request, self.object, initial={'amount': app_settings.DEFAULT_AMOUNT}) def get_context_data(self, **kwargs): ctx = super(OfferDetailView, self).get_context_data(**kwargs) @@ -157,3 +158,16 @@ class DisableNotifications(TemplateView): def post(self, *args, **kwargs): self.object.disable_notifications() return redirect(self.request.get_full_path()) + + +@login_required +def claim(request, key): + funding = get_object_or_404(Funding, notify_key=key) + if funding.user is None: + funding.user = request.user + funding.save() + return HttpResponseRedirect( + funding.offer.book.get_absolute_url() if funding.offer.book is not None + else funding.offer.get_absolute_url() + ) + -- 2.20.1