[Web] refactor / fix token handling
[mygpo.git] / mygpo / share / views.py
blobf4bb3204de1459dda6dfbad960d88540b75e932a
1 from functools import wraps
2 from datetime import datetime
4 from django.core.urlresolvers import reverse
5 from django.http import Http404, HttpResponseRedirect, HttpResponseForbidden
6 from django.shortcuts import render, get_object_or_404
7 from django.utils.text import slugify
8 from django.contrib.sites.models import RequestSite
9 from django.contrib.auth.decorators import login_required
10 from django.contrib.auth import get_user_model
11 from django.contrib import messages
12 from django.utils.translation import ugettext as _
13 from django.views.decorators.vary import vary_on_cookie
14 from django.views.decorators.cache import cache_control
15 from django.views.generic.base import View
16 from django.utils.decorators import method_decorator
18 from mygpo.podcasts.models import Podcast, PodcastGroup
19 from mygpo.core.proxy import proxy_object
20 from mygpo.api.simple import format_podcast_list
21 from mygpo.share.models import PodcastList
22 from mygpo.directory.views import search as directory_search
23 from mygpo.decorators import repeat_on_conflict
24 from mygpo.flattr import Flattr
25 from mygpo.userfeeds.feeds import FavoriteFeed
26 from mygpo.db.couchdb.podcastlist import podcastlist_for_user_slug, \
27 podcastlists_for_user, add_podcast_to_podcastlist, \
28 remove_podcast_from_podcastlist, delete_podcastlist, \
29 create_podcast_list
30 from mygpo.data.feeddownloader import PodcastUpdater
32 import logging
33 logger = logging.getLogger(__name__)
36 def list_decorator(must_own=False):
37 def _tmp(f):
38 @wraps(f)
39 def _decorator(request, username, listname, *args, **kwargs):
41 User = get_user_model()
42 user = get_object_or_404(User, username=username)
44 if must_own and request.user != user:
45 return HttpResponseForbidden()
47 plist = podcastlist_for_user_slug(user.profile.uuid.hex, listname)
49 if plist is None:
50 raise Http404
52 return f(request, plist, user, *args, **kwargs)
54 return _decorator
56 return _tmp
59 @login_required
60 def search(request, username, listname):
61 return directory_search(request, 'list_search.html',
62 {'listname': listname})
65 @login_required
66 def lists_own(request):
68 lists = podcastlists_for_user(request.user.profile.uuid.hex)
70 return render(request, 'lists.html', {
71 'lists': lists
75 def lists_user(request, username):
77 User = get_user_model()
78 user = get_object_or_404(User, username=username)
79 lists = podcastlists_for_user(user.profile.uuid.hex)
81 return render(request, 'lists_user.html', {
82 'lists': lists,
83 'user': user,
87 @list_decorator(must_own=False)
88 def list_show(request, plist, owner):
90 is_own = owner == request.user
91 site = RequestSite(request)
93 plist = proxy_object(plist)
95 podcasts = get_podcasts_groups(plist.podcasts)
96 plist.podcasts = podcasts
98 max_subscribers = max([p.subscriber_count() for p in podcasts] + [0])
100 thing = plist.get_flattr_thing(site.domain, owner.username)
101 flattr = Flattr(owner, site.domain, request.is_secure())
102 flattr_autosubmit = flattr.get_autosubmit_url(thing)
104 return render(request, 'list.html', {
105 'podcastlist': plist,
106 'max_subscribers': max_subscribers,
107 'owner': owner,
108 'flattr_autosubmit': flattr_autosubmit,
109 'domain': site.domain,
110 'is_own': is_own,
114 @list_decorator(must_own=False)
115 def list_opml(request, plist, owner):
116 podcasts = get_podcasts_groups(plist.podcasts)
117 return format_podcast_list(podcasts, 'opml', plist.title)
120 @login_required
121 def create_list(request):
122 title = request.POST.get('title', None)
124 if not title:
125 messages.error(request, _('You have to specify a title.'))
126 return HttpResponseRedirect(reverse('lists-overview'))
128 slug = slugify(title)
130 if not slug:
131 messages.error(request, _('"{title}" is not a valid title').format(
132 title=title))
133 return HttpResponseRedirect(reverse('lists-overview'))
135 plist = podcastlist_for_user_slug(request.user.profile.uuid.hex, slug)
137 if plist is None:
138 create_podcast_list(title, slug, request.user.profile.uuid.hex, datetime.utcnow())
140 list_url = reverse('list-show', args=[request.user.username, slug])
141 return HttpResponseRedirect(list_url)
144 @login_required
145 @list_decorator(must_own=True)
146 def add_podcast(request, plist, owner, podcast_id):
147 add_podcast_to_podcastlist(plist, podcast_id)
148 list_url = reverse('list-show', args=[owner.username, plist.slug])
149 return HttpResponseRedirect(list_url)
152 @login_required
153 @list_decorator(must_own=True)
154 def remove_podcast(request, plist, owner, podcast_id):
155 remove_podcast_from_podcastlist(plist, podcast_id)
156 list_url = reverse('list-show', args=[owner.username, plist.slug])
157 return HttpResponseRedirect(list_url)
160 @login_required
161 @list_decorator(must_own=True)
162 def delete_list(request, plist, owner):
163 delete_podcastlist(plist)
164 return HttpResponseRedirect(reverse('lists-overview'))
167 @login_required
168 @list_decorator(must_own=False)
169 def rate_list(request, plist, owner):
170 rating_val = int(request.GET.get('rate', None))
172 @repeat_on_conflict(['plist'])
173 def _rate(plist, rating_val, user):
174 plist.rate(rating_val, user.profile.uuid.hex)
175 plist.save()
177 _rate(plist, rating_val, request.user)
179 messages.success(request, _('Thanks for rating!'))
181 list_url = reverse('list-show', args=[owner.username, plist.slug])
182 return HttpResponseRedirect(list_url)
185 class FavoritesPublic(View):
187 public = True
189 @method_decorator(vary_on_cookie)
190 @method_decorator(cache_control(private=True))
191 @method_decorator(login_required)
192 def post(self, request):
194 if self.public:
195 request.user.profile.favorite_feeds_token = ''
196 request.user.profile.save()
198 else:
199 request.user.profile.create_new_token('favorite_feeds_token', 8)
200 request.user.profile.save()
202 token = request.user.favorite_feeds_token
204 return HttpResponseRedirect(reverse('share-favorites'))
208 class ShareFavorites(View):
210 @method_decorator(vary_on_cookie)
211 @method_decorator(cache_control(private=True))
212 @method_decorator(login_required)
213 def get(self, request):
214 user = request.user
216 favfeed = FavoriteFeed(user)
217 site = RequestSite(request)
218 feed_url = favfeed.get_public_url(site.domain)
220 podcast = Podcast.objects.filter(urls__url=feed_url).first()
222 token = user.profile.favorite_feeds_token
224 return render(request, 'share/favorites.html', {
225 'feed_token': token,
226 'site': site,
227 'podcast': podcast,
231 class PublicSubscriptions(View):
233 public = True
235 @method_decorator(vary_on_cookie)
236 @method_decorator(cache_control(private=True))
237 @method_decorator(login_required)
238 def post(self, request):
240 if self.public:
241 user.profile.subscriptions_token = ''
242 else:
243 user.profile.create_new_token('subscriptions_token')
245 user.profile.save()
247 return HttpResponseRedirect(reverse('share'))
250 class FavoritesFeedCreateEntry(View):
251 """ Creates a Podcast object for the user's favorites feed """
253 @method_decorator(vary_on_cookie)
254 @method_decorator(cache_control(private=True))
255 @method_decorator(login_required)
256 def post(self, request):
257 user = request.user
259 feed = FavoriteFeed(user)
260 site = RequestSite(request)
261 feed_url = feed.get_public_url(site.domain)
263 podcast = Podcast.objects.get_or_create_for_url(feed_url)
265 if not podcast.get_id() in user.published_objects:
266 user.published_objects.append(podcast.get_id())
267 user.save()
269 updater = PodcastUpdater()
270 updater.update(feed_url)
272 return HttpResponseRedirect(reverse('share-favorites'))
275 @login_required
276 def overview(request):
277 user = request.user
278 site = RequestSite(request)
280 subscriptions_token = user.profile.get_token('subscriptions_token')
281 userpage_token = user.profile.get_token('userpage_token')
282 favfeed_token = user.profile.get_token('favorite_feeds_token')
284 favfeed = FavoriteFeed(user)
285 favfeed_url = favfeed.get_public_url(site.domain)
286 favfeed_podcast = Podcast.objects.filter(urls__url=favfeed_url).first()
288 return render(request, 'share/overview.html', {
289 'site': site,
290 'subscriptions_token': subscriptions_token,
291 'userpage_token': userpage_token,
292 'favfeed_token': favfeed_token,
293 'favfeed_podcast': favfeed_podcast,
297 @login_required
298 def set_token_public(request, token_name, public):
300 user = request.user
302 if public:
303 setattr(user.profile, token_name, '')
304 user.profile.save()
306 else:
307 user.profile.create_new_token(token_name)
308 user.profile.save()
310 return HttpResponseRedirect(reverse('share'))
313 def get_podcasts_groups(ids):
314 # this could be optimized by using a View
315 logger.info('Getting podcasts and groups for IDs %r', ids)
316 groups = PodcastGroup.objects.filter(id__in=ids)
317 podcasts = Podcast.objects.filter(id__in=ids)
318 # TODO: bring in right order, according to IDs
319 return list(groups) + list(podcasts)