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
, \
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
53 @cache_control(private
=True)
54 @allowed_methods(['GET', 'POST'])
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', {
83 'profile_form': profile_form
,
84 'flattr_form': flattr_form
,
86 'userpage_token': userpage_token
,
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']
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', {
118 class ProfileView(View
):
119 """ Updates the public profile and redirects back to the account view """
121 def post(self
, request
):
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'])
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
):
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
):
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
):
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
)
180 messages
.success(request
, _('Authentication successful'))
181 update_flattr_settings(user
, token
)
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'))
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'])
209 user
.is_active
= False
213 do_delete(user
=request
.user
)
216 return render(request
, 'deleted_account.html')
220 class DefaultPrivacySettings(View
):
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
236 class PodcastPrivacySettings(View
):
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'))
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
,
268 @cache_control(private
=True)
271 site
= RequestSite(request
)
273 if 'public_subscriptions' in request
.GET
:
274 @repeat_on_conflict(['user'])
276 user
.subscriptions_token
= ''
279 elif 'private_subscriptions' in request
.GET
:
280 @repeat_on_conflict(['user'])
282 user
.create_new_token('subscriptions_token')
289 _update(user
=request
.user
)
291 token
= request
.user
.get_token('subscriptions_token')
293 return render(request
, 'share.html', {