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 mygpo
.podcasts
.models
import Podcast
34 from mygpo
.core
.podcasts
import PODCAST_SORT
35 from mygpo
.decorators
import allowed_methods
, repeat_on_conflict
36 from mygpo
.web
.forms
import UserAccountForm
, ProfileForm
, FlattrForm
37 from mygpo
.web
.utils
import normalize_twitter
38 from mygpo
.flattr
import Flattr
39 from mygpo
.users
.settings
import PUBLIC_SUB_USER
, \
40 FLATTR_TOKEN
, FLATTR_AUTO
, FLATTR_MYGPO
, FLATTR_USERNAME
41 from mygpo
.db
.couchdb
.podcast_state
import podcast_state_for_user_podcast
, \
42 subscriptions_by_user
, set_podcast_privacy_settings
43 from mygpo
.db
.couchdb
.user
import set_users_google_email
49 @cache_control(private
=True)
50 @allowed_methods(['GET', 'POST'])
53 if request
.method
== 'GET':
55 site
= RequestSite(request
)
56 flattr
= Flattr(request
.user
, site
.domain
, request
.is_secure())
57 userpage_token
= request
.user
.profile
.get_token('userpage_token')
59 profile_form
= ProfileForm({
60 'twitter': request
.user
.profile
.twitter
,
61 'about': request
.user
.profile
.about
,
64 form
= UserAccountForm({
65 'email': request
.user
.email
,
66 'public': request
.user
.profile
.get_wksetting(PUBLIC_SUB_USER
)
69 flattr_form
= FlattrForm({
70 'enable': request
.user
.profile
.get_wksetting(FLATTR_AUTO
),
71 'token': request
.user
.profile
.get_wksetting(FLATTR_TOKEN
),
72 'flattr_mygpo': request
.user
.profile
.get_wksetting(FLATTR_MYGPO
),
73 'username': request
.user
.profile
.get_wksetting(FLATTR_USERNAME
),
76 return render(request
, 'account.html', {
79 'profile_form': profile_form
,
80 'flattr_form': flattr_form
,
82 'userpage_token': userpage_token
,
86 form
= UserAccountForm(request
.POST
)
88 if not form
.is_valid():
89 raise ValueError(_('Oops! Something went wrong. Please double-check the data you entered.'))
91 if form
.cleaned_data
['password_current']:
92 if not request
.user
.check_password(form
.cleaned_data
['password_current']):
93 raise ValueError('Current password is incorrect')
95 request
.user
.set_password(form
.cleaned_data
['password1'])
97 request
.user
.email
= form
.cleaned_data
['email']
101 except Exception as ex
:
102 # TODO: which exception?
103 messages
.error(request
, str(ex
))
105 messages
.success(request
, 'Account updated')
107 except (ValueError, ValidationError
) as e
:
108 messages
.error(request
, str(e
))
110 return render(request
, 'account.html', {
115 class ProfileView(View
):
116 """ Updates the public profile and redirects back to the account view """
118 def post(self
, request
):
121 form
= ProfileForm(request
.POST
)
123 if not form
.is_valid():
124 raise ValueError(_('Oops! Something went wrong. Please double-check the data you entered.'))
126 request
.user
.twitter
= normalize_twitter(form
.cleaned_data
['twitter'])
127 request
.user
.about
= strip_tags(form
.cleaned_data
['about'])
130 messages
.success(request
, _('Data updated'))
132 return HttpResponseRedirect(reverse('account') + '#profile')
135 class FlattrSettingsView(View
):
136 """ Updates Flattr settings and redirects back to the Account page """
138 def post(self
, request
):
141 form
= FlattrForm(request
.POST
)
143 if not form
.is_valid():
144 raise ValueError('asdf')
146 auto_flattr
= form
.cleaned_data
.get('enable', False)
147 flattr_mygpo
= form
.cleaned_data
.get('flattr_mygpo', False)
148 username
= form
.cleaned_data
.get('username', '')
150 user
.settings
[FLATTR_AUTO
.name
] = auto_flattr
151 user
.settings
[FLATTR_MYGPO
.name
] = flattr_mygpo
152 user
.settings
[FLATTR_USERNAME
.name
] = username
155 return HttpResponseRedirect(reverse('account') + '#flattr')
158 class FlattrLogout(View
):
159 """ Removes Flattr authentication token """
161 def get(self
, request
):
163 user
.settings
[FLATTR_AUTO
.name
] = False
164 user
.settings
[FLATTR_TOKEN
.name
] = False
165 user
.settings
[FLATTR_MYGPO
.name
] = False
167 return HttpResponseRedirect(reverse('account') + '#flattr')
170 class FlattrTokenView(View
):
171 """ Callback for the Flattr authentication
173 Updates the user's Flattr token and redirects back to the account page """
175 def get(self
, request
):
178 site
= RequestSite(request
)
179 flattr
= Flattr(user
, site
.domain
, request
.is_secure())
181 url
= request
.build_absolute_uri()
182 token
= flattr
.process_retrieved_code(url
)
184 messages
.success(request
, _('Authentication successful'))
185 user
.settings
[FLATTR_TOKEN
.name
] = token
189 messages
.error(request
, _('Authentication failed. Try again later'))
191 return HttpResponseRedirect(reverse('account') + '#flattr')
194 class AccountRemoveGoogle(View
):
195 """ Removes the connected Google account """
197 @method_decorator(login_required
)
198 def post(self
, request
):
199 set_users_google_email(request
.user
, None)
200 messages
.success(request
, _('Your account has been disconnected'))
201 return HttpResponseRedirect(reverse('account'))
206 @allowed_methods(['GET', 'POST'])
207 def delete_account(request
):
209 if request
.method
== 'GET':
210 return render(request
, 'delete_account.html')
212 @repeat_on_conflict(['user'])
214 user
.is_active
= False
218 do_delete(user
=request
.user
)
221 return render(request
, 'deleted_account.html')
225 class DefaultPrivacySettings(View
):
229 @method_decorator(login_required
)
230 @method_decorator(never_cache
)
231 def post(self
, request
):
232 self
.set_privacy_settings(user
=request
.user
)
233 return HttpResponseRedirect(reverse('privacy'))
235 @repeat_on_conflict(['user'])
236 def set_privacy_settings(self
, user
):
237 user
.settings
[PUBLIC_SUB_USER
.name
] = self
.public
241 class PodcastPrivacySettings(View
):
245 @method_decorator(login_required
)
246 @method_decorator(never_cache
)
247 def post(self
, request
, podcast_id
):
248 podcast
= Podcast
.objects
.get(id=podcast_id
)
249 state
= podcast_state_for_user_podcast(request
.user
, podcast
)
250 set_podcast_privacy_settings(state
, self
.public
)
251 return HttpResponseRedirect(reverse('privacy'))
256 def privacy(request
):
257 site
= RequestSite(request
)
259 subscriptions
= subscriptions_by_user(request
.user
)
260 podcast_ids
= [x
[1] for x
in subscriptions
]
261 podcasts
= Podcast
.objects
.filter(id__in
=podcast_ids
).prefetch_related('slugs')
262 podcasts
= {podcast
.id.hex: podcast
for podcast
in podcasts
}
264 subs
= set((podcasts
.get(x
[1], None), not x
[0]) for x
in subscriptions
)
265 subs
= sorted(subs
, key
=lambda (p
, _
): PODCAST_SORT(p
))
267 return render(request
, 'privacy.html', {
268 'private_subscriptions': not request
.user
.get_wksetting(PUBLIC_SUB_USER
),
269 'subscriptions': subs
,
270 'domain': site
.domain
,
275 @cache_control(private
=True)
278 site
= RequestSite(request
)
280 if 'public_subscriptions' in request
.GET
:
281 @repeat_on_conflict(['user'])
283 user
.subscriptions_token
= ''
286 elif 'private_subscriptions' in request
.GET
:
287 @repeat_on_conflict(['user'])
289 user
.create_new_token('subscriptions_token')
296 _update(user
=request
.user
)
298 token
= request
.user
.profile
.get_token('subscriptions_token')
300 return render(request
, 'share.html', {