Login form.
[wolnelektury.git] / src / wolnelektury / views.py
1 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
2 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
3 #
4 from datetime import date, datetime
5 from urllib.parse import quote_plus
6 import feedparser
7 from allauth.socialaccount.views import SignupView
8
9 from django.conf import settings
10 from django.contrib import auth
11 from django.contrib.auth.decorators import login_required
12 from django.contrib.auth.forms import AuthenticationForm
13 from django.contrib.auth.views import LoginView
14 from django.core.cache import cache
15 from django.http import HttpResponse, HttpResponseRedirect
16 from django.shortcuts import render
17 from django.utils.translation import gettext_lazy as _
18 from django.views.decorators.cache import never_cache
19
20 from ajaxable.utils import AjaxableFormView
21 from ajaxable.utils import placeholdized
22 from catalogue.models import Book, Collection, Tag, Fragment
23
24 from social.utils import get_or_choose_cite
25 from wolnelektury.forms import RegistrationForm, SocialSignupForm, WLAuthenticationForm
26
27
28 @never_cache
29 def main_page(request):
30     ctx = {
31         'last_published': Book.objects.exclude(cover_thumb='').filter(findable=True, parent=None).order_by('-created_at')[:6],
32         'theme_books': [],
33     }
34
35     # FIXME: find this theme and books properly.
36     if Fragment.objects.exists():
37         while True:
38             ctx['theme'] = Tag.objects.filter(category='theme').order_by('?')[:1][0]
39             tf = Fragment.tagged.with_any([ctx['theme']]).select_related('book').filter(book__findable=True).order_by('?')[:100]
40             if not tf:
41                 continue
42             ctx['theme_fragment'] = tf[0]
43             for f in tf:
44                 if f.book not in ctx['theme_books']:
45                     ctx['theme_books'].append(f.book)
46                 if len(ctx['theme_books']) == 3:
47                     break
48             break
49
50     # Choose collections for main.
51     ctx['collections'] = Collection.objects.filter(listed=True).order_by('?')[:4]
52
53     best = []
54     best_places = 5
55     recommended_collection = None
56     for recommended in Collection.objects.filter(listed=True, role='recommend').order_by('?'):
57         if recommended_collection is None:
58             recommended_collection = recommended
59         books = list(recommended.get_books().exclude(id__in=[b.id for b in best]).order_by('?')[:best_places])
60         best.extend(books)
61         best_places -= len(books)
62         if not best_places:
63             break
64     ctx['recommended_collection'] = recommended_collection
65     if best_places:
66         best.extend(
67             list(
68                 Book.objects.filter(findable=True).exclude(id__in=[b.id for b in best]).order_by('?')[:best_places]
69             )
70         )
71     ctx['best'] = best
72
73     return render(request, "main_page.html", ctx)
74
75
76 class WLLoginView(LoginView):
77     form_class = WLAuthenticationForm
78
79
80 wl_login_view = WLLoginView.as_view()
81
82
83 class LoginFormView(AjaxableFormView):
84     form_class = AuthenticationForm
85     template = "auth/login.html"
86     placeholdize = True
87     title = _('Sign in')
88     submit = _('Sign in')
89     ajax_redirect = True
90
91     def __call__(self, request):
92         if request.EXPERIMENTS['layout'].value:
93             return wl_login_view(request)
94
95         if request.user.is_authenticated:
96             return self.redirect_or_refresh(
97                 request, '/',
98                 message=_('Already logged in as user %(user)s', ) % {'user': request.user.username})
99         return super(LoginFormView, self).__call__(request)
100
101     def success(self, form, request):
102         auth.login(request, form.get_user())
103
104
105 class RegisterFormView(AjaxableFormView):
106     form_class = RegistrationForm
107     template = "auth/register.html"
108     placeholdize = True
109     title = _('Register')
110     submit = _('Register')
111     ajax_redirect = True
112     form_prefix = 'register'
113     honeypot = True
114
115     def __call__(self, request):
116         if request.user.is_authenticated:
117             return self.redirect_or_refresh(
118                 request, '/',
119                 message=_('Already logged in as user %(user)s', ) % {'user': request.user.username})
120         return super(RegisterFormView, self).__call__(request)
121
122     def success(self, form, request):
123         form.save()
124         user = auth.authenticate(
125             username=form.cleaned_data['username'],
126             password=form.cleaned_data['password1']
127         )
128         auth.login(request, user)
129
130
131 class LoginRegisterFormView(LoginFormView):
132     template = 'auth/login_register.html'
133     title = _('You have to be logged in to continue')
134
135     def extra_context(self, request, obj):
136         return {
137             "register_form": placeholdized(RegistrationForm(prefix='register')),
138             "register_submit": _('Register'),
139         }
140
141
142 @never_cache
143 def logout_then_redirect(request):
144     auth.logout(request)
145     return HttpResponseRedirect(quote_plus(request.GET.get('next', '/'), safe='/?='))
146
147
148 @never_cache
149 def clock(request):
150     """ Provides server UTC time for jquery.countdown,
151     in a format suitable for Date.parse()
152     """
153     return HttpResponse(datetime.utcnow().strftime('%Y/%m/%d %H:%M:%S UTC'))
154
155
156 def publish_plan(request):
157     cache_key = "publish_plan"
158     plan = cache.get(cache_key)
159
160     if plan is None:
161         plan = []
162         try:
163             feed = feedparser.parse(settings.PUBLISH_PLAN_FEED)
164         except:
165             pass
166         else:
167             for i in range(len(feed['entries'])):
168                 plan.append({
169                     'title': feed['entries'][i].title,
170                     'link': feed['entries'][i].link,
171                     })
172         cache.set(cache_key, plan, 1800)
173
174     return render(request, "publish_plan.html", {'plan': plan})
175
176
177 @login_required
178 def user_settings(request):
179     return render(request, "user.html")
180
181
182 def widget(request):
183     return render(request, 'widget.html')
184
185
186 class SocialSignupView(SignupView):
187     form_class = SocialSignupForm
188
189
190 def exception_test(request):
191     msg = request.GET.get('msg')
192     if msg:
193         raise Exception('Exception test: %s' % msg)
194     else:
195         raise Exception('Exception test')
196
197
198 def post_test(request):
199     return render(request, 'post_test.html', {'action': '/api/reading/jego-zasady/complete/'})