avoid conflict when confirming pubsub sbuscription
[mygpo.git] / mygpo / web / views / settings.py
blob3a4eccb008e494b7f52a54796f675dc8d5d6604b
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.core.podcasts import PODCAST_SORT
37 from mygpo.decorators import allowed_methods, repeat_on_conflict
38 from mygpo.web.forms import UserAccountForm, ProfileForm, FlattrForm
39 from mygpo.web.utils import normalize_twitter
40 from mygpo.flattr import Flattr
41 from mygpo.users.settings import PUBLIC_SUB_USER, \
42 FLATTR_TOKEN, FLATTR_AUTO, FLATTR_MYGPO, FLATTR_USERNAME
43 from mygpo.db.couchdb.podcast import podcast_by_id, podcasts_to_dict
44 from mygpo.db.couchdb.podcast_state import podcast_state_for_user_podcast, \
45 subscriptions_by_user, set_podcast_privacy_settings
46 from mygpo.db.couchdb.user import update_flattr_settings, \
47 set_users_google_email
51 @login_required
52 @vary_on_cookie
53 @cache_control(private=True)
54 @allowed_methods(['GET', 'POST'])
55 def account(request):
57 if request.method == 'GET':
59 site = RequestSite(request)
60 flattr = Flattr(request.user, site.domain, request.is_secure())
61 userpage_token = request.user.get_token('userpage_token')
63 profile_form = ProfileForm({
64 'twitter': request.user.twitter,
65 'about': request.user.about,
68 form = UserAccountForm({
69 'email': request.user.email,
70 'public': request.user.get_wksetting(PUBLIC_SUB_USER)
73 flattr_form = FlattrForm({
74 'enable': request.user.get_wksetting(FLATTR_AUTO),
75 'token': request.user.get_wksetting(FLATTR_TOKEN),
76 'flattr_mygpo': request.user.get_wksetting(FLATTR_MYGPO),
77 'username': request.user.get_wksetting(FLATTR_USERNAME),
80 return render(request, 'account.html', {
81 'site': site,
82 'form': form,
83 'profile_form': profile_form,
84 'flattr_form': flattr_form,
85 'flattr': flattr,
86 'userpage_token': userpage_token,
89 try:
90 form = UserAccountForm(request.POST)
92 if not form.is_valid():
93 raise ValueError(_('Oops! Something went wrong. Please double-check the data you entered.'))
95 if form.cleaned_data['password_current']:
96 if not request.user.check_password(form.cleaned_data['password_current']):
97 raise ValueError('Current password is incorrect')
99 request.user.set_password(form.cleaned_data['password1'])
101 request.user.email = form.cleaned_data['email']
103 try:
104 request.user.save()
105 except (UsernameException, PasswordException) as ex:
106 messages.error(request, str(ex))
108 messages.success(request, 'Account updated')
110 except (ValueError, ValidationError) as e:
111 messages.error(request, str(e))
113 return render(request, 'account.html', {
114 'form': form,
118 class ProfileView(View):
119 """ Updates the public profile and redirects back to the account view """
121 def post(self, request):
122 user = request.user
124 form = ProfileForm(request.POST)
126 if not form.is_valid():
127 raise ValueError(_('Oops! Something went wrong. Please double-check the data you entered.'))
129 request.user.twitter = normalize_twitter(form.cleaned_data['twitter'])
130 request.user.about = strip_tags(form.cleaned_data['about'])
132 request.user.save()
133 messages.success(request, _('Data updated'))
135 return HttpResponseRedirect(reverse('account') + '#profile')
138 class FlattrSettingsView(View):
139 """ Updates Flattr settings and redirects back to the Account page """
141 def post(self, request):
142 user = request.user
144 form = FlattrForm(request.POST)
146 if not form.is_valid():
147 raise ValueError('asdf')
149 auto_flattr = form.cleaned_data.get('enable', False)
150 flattr_mygpo = form.cleaned_data.get('flattr_mygpo', False)
151 username = form.cleaned_data.get('username', '')
152 update_flattr_settings(user, None, auto_flattr, flattr_mygpo, username)
154 return HttpResponseRedirect(reverse('account') + '#flattr')
157 class FlattrLogout(View):
158 """ Removes Flattr authentication token """
160 def get(self, request):
161 user = request.user
162 update_flattr_settings(user, False, False, False)
163 return HttpResponseRedirect(reverse('account') + '#flattr')
166 class FlattrTokenView(View):
167 """ Callback for the Flattr authentication
169 Updates the user's Flattr token and redirects back to the account page """
171 def get(self, request):
173 user = request.user
174 site = RequestSite(request)
175 flattr = Flattr(user, site.domain, request.is_secure())
177 url = request.build_absolute_uri()
178 token = flattr.process_retrieved_code(url)
179 if token:
180 messages.success(request, _('Authentication successful'))
181 update_flattr_settings(user, token)
183 else:
184 messages.error(request, _('Authentication failed. Try again later'))
186 return HttpResponseRedirect(reverse('account') + '#flattr')
189 class AccountRemoveGoogle(View):
190 """ Removes the connected Google account """
192 @method_decorator(login_required)
193 def post(self, request):
194 set_users_google_email(request.user, None)
195 messages.success(request, _('Your account has been disconnected'))
196 return HttpResponseRedirect(reverse('account'))
199 @login_required
200 @never_cache
201 @allowed_methods(['GET', 'POST'])
202 def delete_account(request):
204 if request.method == 'GET':
205 return render(request, 'delete_account.html')
207 @repeat_on_conflict(['user'])
208 def do_delete(user):
209 user.is_active = False
210 user.deleted = True
211 user.save()
213 do_delete(user=request.user)
214 logout(request)
216 return render(request, 'deleted_account.html')
220 class DefaultPrivacySettings(View):
222 public = True
224 @method_decorator(login_required)
225 @method_decorator(never_cache)
226 def post(self, request):
227 self.set_privacy_settings(user=request.user)
228 return HttpResponseRedirect(reverse('privacy'))
230 @repeat_on_conflict(['user'])
231 def set_privacy_settings(self, user):
232 user.settings[PUBLIC_SUB_USER.name] = self.public
233 user.save()
236 class PodcastPrivacySettings(View):
238 public = True
240 @method_decorator(login_required)
241 @method_decorator(never_cache)
242 def post(self, request, podcast_id):
243 podcast = podcast_by_id(podcast_id)
244 state = podcast_state_for_user_podcast(request.user, podcast)
245 set_podcast_privacy_settings(state, self.public)
246 return HttpResponseRedirect(reverse('privacy'))
249 @login_required
250 @never_cache
251 def privacy(request):
252 site = RequestSite(request)
254 subscriptions = subscriptions_by_user(request.user)
255 podcasts = podcasts_to_dict([x[1] for x in subscriptions])
257 subs = set((podcasts.get(x[1], None), not x[0]) for x in subscriptions)
258 subs = sorted(subs, key=lambda (p, _): PODCAST_SORT(p))
260 return render(request, 'privacy.html', {
261 'private_subscriptions': not request.user.get_wksetting(PUBLIC_SUB_USER),
262 'subscriptions': subs,
263 'domain': site.domain,
267 @vary_on_cookie
268 @cache_control(private=True)
269 @login_required
270 def share(request):
271 site = RequestSite(request)
273 if 'public_subscriptions' in request.GET:
274 @repeat_on_conflict(['user'])
275 def _update(user):
276 user.subscriptions_token = ''
277 user.save()
279 elif 'private_subscriptions' in request.GET:
280 @repeat_on_conflict(['user'])
281 def _update(user):
282 user.create_new_token('subscriptions_token')
283 user.save()
285 else:
286 _update = None
288 if _update:
289 _update(user=request.user)
291 token = request.user.get_token('subscriptions_token')
293 return render(request, 'share.html', {
294 'site': site,
295 'token': token,