refactoring well-known settings
[mygpo.git] / mygpo / web / views / settings.py
blobe31ac665231745a3e60c2b034c6a51d465f02fde
2 # This file is part of my.gpodder.org.
4 # my.gpodder.org is free software: you can redistribute it and/or modify it
5 # under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or (at your
7 # option) any later version.
9 # my.gpodder.org is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
12 # License for more details.
14 # You should have received a copy of the GNU Affero General Public License
15 # along with my.gpodder.org. If not, see <http://www.gnu.org/licenses/>.
18 from django.shortcuts import render
19 from django.core.urlresolvers import reverse
20 from django.http import HttpResponseRedirect
21 from django.contrib.auth import logout
22 from django.contrib import messages
23 from django.forms import ValidationError
24 from django.utils.translation import ugettext as _
25 from django.contrib.auth.decorators import login_required
26 from django.contrib.sites.models import RequestSite
27 from django.views.decorators.vary import vary_on_cookie
28 from django.views.decorators.cache import never_cache, cache_control
29 from django.utils.decorators import method_decorator
30 from django.views.generic.base import View
31 from django.utils.html import strip_tags
33 from django_couchdb_utils.auth.models import UsernameException, \
34 PasswordException
36 from mygpo.decorators import allowed_methods, repeat_on_conflict
37 from mygpo.web.forms import UserAccountForm, ProfileForm, FlattrForm
38 from mygpo.web.utils import normalize_twitter
39 from mygpo.flattr import Flattr
40 from mygpo.users.settings import PUBLIC_SUB_PODCAST, PUBLIC_SUB_USER, \
41 FLATTR_TOKEN, FLATTR_AUTO
42 from mygpo.db.couchdb.podcast import podcast_by_id, podcasts_to_dict
43 from mygpo.db.couchdb.podcast_state import podcast_state_for_user_podcast, \
44 subscriptions_by_user
45 from mygpo.db.couchdb.user import update_flattr_settings
48 @login_required
49 @vary_on_cookie
50 @cache_control(private=True)
51 @allowed_methods(['GET', 'POST'])
52 def account(request):
54 if request.method == 'GET':
56 site = RequestSite(request)
57 flattr = Flattr(request.user, site.domain)
58 userpage_token = request.user.get_token('userpage_token')
60 profile_form = ProfileForm({
61 'twitter': request.user.twitter,
62 'about': request.user.about,
65 form = UserAccountForm({
66 'email': request.user.email,
67 'public': request.user.get_wksetting(PUBLIC_SUB_USER)
70 flattr_form = FlattrForm({
71 'enable': request.user.get_wksetting(FLATTR_AUTO),
72 'token': request.user.get_wksetting(FLATTR_TOKEN),
75 return render(request, 'account.html', {
76 'form': form,
77 'profile_form': profile_form,
78 'flattr_form': flattr_form,
79 'flattr': flattr,
80 'userpage_token': userpage_token,
83 try:
84 form = UserAccountForm(request.POST)
86 if not form.is_valid():
87 raise ValueError(_('Oops! Something went wrong. Please double-check the data you entered.'))
89 if form.cleaned_data['password_current']:
90 if not request.user.check_password(form.cleaned_data['password_current']):
91 raise ValueError('Current password is incorrect')
93 request.user.set_password(form.cleaned_data['password1'])
95 request.user.email = form.cleaned_data['email']
97 try:
98 request.user.save()
99 except (UsernameException, PasswordException) as ex:
100 messages.error(request, str(ex))
102 messages.success(request, 'Account updated')
104 except (ValueError, ValidationError) as e:
105 messages.error(request, str(e))
107 return render(request, 'account.html', {
108 'form': form,
112 class ProfileView(View):
113 """ Updates the public profile and redirects back to the account view """
115 def post(self, request):
116 user = request.user
118 form = ProfileForm(request.POST)
120 if not form.is_valid():
121 raise ValueError(_('Oops! Something went wrong. Please double-check the data you entered.'))
123 request.user.twitter = normalize_twitter(form.cleaned_data['twitter'])
124 request.user.about = strip_tags(form.cleaned_data['about'])
126 request.user.save()
127 messages.success(request, _('Data updated'))
129 return HttpResponseRedirect(reverse('account'))
132 class FlattrSettingsView(View):
133 """ Updates Flattr settings and redirects back to the Account page """
135 def post(self, request):
136 user = request.user
138 form = FlattrForm(request.POST)
140 if not form.is_valid():
141 raise ValueError('asdf')
143 auto_flattr = form.cleaned_data.get('enable', False)
144 update_flattr_settings(user, None, auto_flattr)
146 return HttpResponseRedirect(reverse('account'))
149 class FlattrTokenView(View):
150 """ Callback for the Flattr authentication
152 Updates the user's Flattr token and redirects back to the account page """
154 def get(self, request):
156 user = request.user
157 site = RequestSite(request)
158 flattr = Flattr(user, site.domain)
160 url = request.build_absolute_uri()
161 token = flattr.process_retrieved_code(url)
162 if token:
163 messages.success(request, _('Authentication successful'))
164 update_flattr_settings(user, token)
166 else:
167 messages.error(request, _('Authentication failed. Try again later'))
169 return HttpResponseRedirect(reverse('account'))
173 @login_required
174 @never_cache
175 @allowed_methods(['GET', 'POST'])
176 def delete_account(request):
178 if request.method == 'GET':
179 return render(request, 'delete_account.html')
181 @repeat_on_conflict(['user'])
182 def do_delete(user):
183 user.is_active = False
184 user.deleted = True
185 user.save()
187 do_delete(user=request.user)
188 logout(request)
190 return render(request, 'deleted_account.html')
194 class DefaultPrivacySettings(View):
196 public = True
198 @method_decorator(login_required)
199 @method_decorator(never_cache)
200 def post(self, request):
201 self.set_privacy_settings(user=request.user)
202 messages.success(request, 'Success')
203 return HttpResponseRedirect(reverse('privacy'))
205 @repeat_on_conflict(['user'])
206 def set_privacy_settings(self, user):
207 user.settings[PUBLIC_SUB_USER.name] = self.public
208 user.save()
211 class PodcastPrivacySettings(View):
213 public = True
215 @method_decorator(login_required)
216 @method_decorator(never_cache)
217 def post(self, request, podcast_id):
218 podcast = podcast_by_id(podcast_id)
219 state = podcast_state_for_user_podcast(request.user, podcast)
220 self.set_privacy_settings(state=state)
221 messages.success(request, 'Success')
222 return HttpResponseRedirect(reverse('privacy'))
224 @repeat_on_conflict(['state'])
225 def set_privacy_settings(self, state):
226 state.settings[PUBLIC_SUB_PODCAST.name] = self.public
227 state.save()
231 @login_required
232 @never_cache
233 def privacy(request):
234 site = RequestSite(request)
236 subscriptions = subscriptions_by_user(request.user)
237 podcasts = podcasts_to_dict([x[1] for x in subscriptions])
239 included_subscriptions = set(filter(None, [podcasts.get(x[1], None) for x in subscriptions if x[0] == True]))
240 excluded_subscriptions = set(filter(None, [podcasts.get(x[1], None) for x in subscriptions if x[0] == False]))
242 return render(request, 'privacy.html', {
243 'public_subscriptions': request.user.get_wksetting(PUBLIC_SUB_USER),
244 'included_subscriptions': included_subscriptions,
245 'excluded_subscriptions': excluded_subscriptions,
246 'domain': site.domain,
250 @vary_on_cookie
251 @cache_control(private=True)
252 @login_required
253 def share(request):
254 site = RequestSite(request)
256 if 'public_subscriptions' in request.GET:
257 @repeat_on_conflict(['user'])
258 def _update(user):
259 user.subscriptions_token = ''
260 user.save()
262 elif 'private_subscriptions' in request.GET:
263 @repeat_on_conflict(['user'])
264 def _update(user):
265 user.create_new_token('subscriptions_token')
266 user.save()
268 else:
269 _update = None
271 if _update:
272 _update(user=request.user)
274 token = request.user.get_token('subscriptions_token')
276 return render(request, 'share.html', {
277 'site': site,
278 'token': token,