[Web] refactor / fix token handling
[mygpo.git] / mygpo / publisher / views.py
blobee93daff50b767dcacd85c07494543e05e4610aa
1 from functools import wraps
2 import urllib
4 from django.shortcuts import render
5 from django.http import HttpResponse, HttpResponseRedirect, \
6 HttpResponseForbidden, Http404
7 from django.core.cache import cache
8 from django.views.decorators.cache import never_cache, cache_control
9 from django.views.decorators.vary import vary_on_cookie
10 from django.core.urlresolvers import reverse
11 from django.utils.translation import ugettext as _
12 from django.contrib import messages
13 from django.contrib.auth import get_user_model
14 from django.contrib.contenttypes.models import ContentType
15 from django.shortcuts import get_object_or_404
17 from mygpo.podcasts.models import PodcastGroup, Podcast, Episode
18 from mygpo.core.proxy import proxy_object
19 from mygpo.publisher.auth import require_publisher, is_publisher
20 from mygpo.publisher.forms import SearchPodcastForm
21 from mygpo.publisher.utils import listener_data, episode_listener_data, \
22 check_publisher_permission, subscriber_data
23 from mygpo.web.heatmap import EpisodeHeatmap
24 from mygpo.web.views.episode import (slug_decorator as episode_slug_decorator,
25 id_decorator as episode_id_decorator)
26 from mygpo.web.views.podcast import (slug_decorator as podcast_slug_decorator,
27 id_decorator as podcast_id_decorator)
28 from mygpo.web.utils import get_podcast_link_target, normalize_twitter, \
29 get_episode_link_target
30 from django.contrib.sites.models import RequestSite
31 from mygpo.data.tasks import update_podcasts
32 from mygpo.decorators import requires_token, allowed_methods
33 from mygpo.db.couchdb.episode_state import episode_listener_counts
34 from mygpo.db.couchdb.pubsub import subscription_for_topic
37 @vary_on_cookie
38 @cache_control(private=True)
39 def home(request):
40 if is_publisher(request.user):
41 podcasts = Podcast.objects.filter(publishedpodcast__publisher=request.user)\
42 .prefetch_related('slugs')
43 site = RequestSite(request)
44 update_token = request.user.profile.get_token('publisher_update_token')
45 form = SearchPodcastForm()
46 return render(request, 'publisher/home.html', {
47 'update_token': update_token,
48 'podcasts': podcasts,
49 'form': form,
50 'site': site,
53 else:
54 site = RequestSite(request)
55 return render(request, 'publisher/info.html', {
56 'site': site
60 @vary_on_cookie
61 @cache_control(private=True)
62 @require_publisher
63 def search_podcast(request):
64 form = SearchPodcastForm(request.POST)
65 if form.is_valid():
66 podcast_url = form.cleaned_data['url']
67 podcast = get_objet_or_404(Podcast, urls__url=podcast_url)
68 url = get_podcast_link_target(podcast, 'podcast-publisher-detail')
69 else:
70 url = reverse('publisher')
72 return HttpResponseRedirect(url)
75 @vary_on_cookie
76 @cache_control(private=True)
77 @require_publisher
78 @allowed_methods(['GET', 'POST'])
79 def podcast(request, podcast):
81 if not check_publisher_permission(request.user, podcast):
82 return HttpResponseForbidden()
84 timeline_data = listener_data([podcast])
85 subscription_data = subscriber_data([podcast])[-20:]
87 update_token = request.user.publisher_update_token
89 heatmap = EpisodeHeatmap(podcast.get_id())
91 pubsubscription = subscription_for_topic(podcast.url)
93 site = RequestSite(request)
94 feedurl_quoted = urllib.quote(podcast.url)
96 return render(request, 'publisher/podcast.html', {
97 'site': site,
98 'podcast': podcast,
99 'group': podcast.group,
100 'form': None,
101 'timeline_data': timeline_data,
102 'subscriber_data': subscription_data,
103 'update_token': update_token,
104 'heatmap': heatmap,
105 'feedurl_quoted': feedurl_quoted,
106 'pubsubscription': pubsubscription,
110 @vary_on_cookie
111 @cache_control(private=True)
112 @require_publisher
113 def group(request, group):
115 podcasts = group.podcasts
117 # users need to have publisher access for at least one of the group's podcasts
118 if not any([check_publisher_permission(request.user, p) for p in podcasts]):
119 return HttpResponseForbidden()
121 timeline_data = listener_data(podcasts)
122 subscription_data = list(subscriber_data(podcasts))[-20:]
124 return render(request, 'publisher/group.html', {
125 'group': group,
126 'timeline_data': timeline_data,
127 'subscriber_data': subscription_data,
131 @vary_on_cookie
132 @cache_control(private=True)
133 @require_publisher
134 def update_podcast(request, podcast):
136 if not check_publisher_permission(request.user, podcast):
137 return HttpResponseForbidden()
139 update_podcasts.delay([podcast.url])
140 messages.success(request, _('The update has been scheduled. It might take some time until the results are visible.'))
142 url = get_podcast_link_target(podcast, 'podcast-publisher-detail')
143 return HttpResponseRedirect(url)
146 @vary_on_cookie
147 @cache_control(private=True)
148 @require_publisher
149 def save_podcast(request, podcast):
150 twitter = normalize_twitter(request.POST.get('twitter', ''))
151 podcast.twitter = twitter
152 podcast.save()
153 messages.success(request, _('Data updated'))
154 url = get_podcast_link_target(podcast, 'podcast-publisher-detail')
155 return HttpResponseRedirect(url)
159 @never_cache
160 @require_publisher
161 def new_update_token(request, username):
162 request.user.profile.create_new_token('publisher_update_token')
163 request.user.profile.save()
164 messages.success(request, _('Publisher token updated'))
165 return HttpResponseRedirect(reverse('publisher'))
168 @never_cache
169 @requires_token(token_name='publisher_update_token')
170 def update_published_podcasts(request, username):
171 User = get_user_model()
172 user = get_object_or_404(User, username=username)
173 published_podcasts = Podcast.objects.filter(id__in=user.published_objects)
174 update_podcasts.delay([podcast.url for podcast in published_podcasts])
175 return HttpResponse('Updated:\n' + '\n'.join([p.url for p in published_podcasts]), mimetype='text/plain')
178 @vary_on_cookie
179 @cache_control(private=True)
180 @require_publisher
181 def episodes(request, podcast):
183 if not check_publisher_permission(request.user, podcast):
184 return HttpResponseForbidden()
186 episodes = Episode.objects.filter(podcast=podcast).select_related('podcast').prefetch_related('slugs', 'podcast__slugs')
188 max_listeners = max([e.listeners for e in episodes] + [0])
190 return render(request, 'publisher/episodes.html', {
191 'podcast': podcast,
192 'episodes': episodes,
193 'max_listeners': max_listeners
197 @require_publisher
198 @vary_on_cookie
199 @cache_control(private=True)
200 @allowed_methods(['GET', 'POST'])
201 def episode(request, episode):
203 site = RequestSite(request)
204 podcast = episode.podcast
206 if not check_publisher_permission(request.user, podcast):
207 return HttpResponseForbidden()
209 if request.method == 'POST':
210 form = None # EpisodeForm(request.POST, instance=e)
211 # if form.is_valid():
212 # form.save()
214 elif request.method == 'GET':
215 form = None # EpisodeForm(instance=e)
217 timeline_data = list(episode_listener_data(episode))
219 heatmap = EpisodeHeatmap(episode.podcast, episode.id,
220 duration=episode.duration)
222 return render(request, 'publisher/episode.html', {
223 'is_secure': request.is_secure(),
224 'domain': site.domain,
225 'episode': episode,
226 'podcast': podcast,
227 'form': form,
228 'timeline_data': timeline_data,
229 'heatmap': heatmap,
233 @require_publisher
234 @never_cache
235 @allowed_methods(['POST'])
236 def update_episode_slug(request, episode):
237 """ sets a new "main" slug, and moves the existing to the merged slugs """
239 new_slug = request.POST.get('slug')
240 podcast = episode.podcast
242 if new_slug:
243 # remove the new slug from other episodes (of the same podcast)
244 other_episodes = Episode.objects.filter(
245 podcast=podcast,
246 slugs__slug=new_slug,
247 slugs__content_type=ContentType.objects.get_for_model(Episode),
250 for other_episode in other_episodes:
252 if other_episode == episode:
253 continue
255 other_episode.remove_slug(new_slug)
256 messages.warning(request,
257 _(u'Removed slug {slug} from {episode}'.format(
258 slug=new_slug, episode=other_episode.title))
261 episode.set_slug(new_slug)
263 # TODO: we should use better cache invalidation
264 cache.clear()
266 return HttpResponseRedirect(
267 get_episode_link_target(episode, podcast, 'episode-publisher-detail')
271 @vary_on_cookie
272 @cache_control(private=True)
273 def link(request):
274 current_site = RequestSite(request)
275 return render(request, 'link.html', {
276 'url': current_site
280 @vary_on_cookie
281 @cache_control(private=True)
282 def advertise(request):
283 site = RequestSite(request)
284 return render(request, 'publisher/advertise.html', {
285 'site': site
289 def group_id_decorator(f):
290 @wraps(f)
291 def _decorator(request, pg_slug, *args, **kwargs):
292 group = get_object_or_404(PodcastGroup, pk=slug_id)
293 return f(request, group, *args, **kwargs)
295 return _decorator
298 episode_slug = episode_slug_decorator(episode)
299 update_episode_slug_slug = episode_slug_decorator(update_episode_slug)
300 podcast_slug = podcast_slug_decorator(podcast)
301 episodes_slug = podcast_slug_decorator(episodes)
302 update_podcast_slug = podcast_slug_decorator(update_podcast)
303 save_podcast_slug = podcast_slug_decorator(save_podcast)
305 episode_id = episode_id_decorator(episode)
306 update_episode_slug_id = episode_id_decorator(update_episode_slug)
307 podcast_id = podcast_id_decorator(podcast)
308 episodes_id = podcast_id_decorator(episodes)
309 update_podcast_id = podcast_id_decorator(update_podcast)
310 save_podcast_id = podcast_id_decorator(save_podcast)
312 group_slug = group_id_decorator(group)