Show avg podcast update duration in admin area
[mygpo.git] / mygpo / publisher / views.py
blob5038cdf8fc237906d31a6b9bf9ecf7e796cfec67
1 from functools import wraps
2 import urllib.request, urllib.parse, urllib.error
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.urls 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.publisher.auth import require_publisher, is_publisher
19 from mygpo.publisher.forms import SearchPodcastForm
20 from mygpo.publisher.utils import listener_data, episode_listener_data, \
21 check_publisher_permission, subscriber_data
22 from mygpo.podcasts.views.episode import (
23 slug_decorator as episode_slug_decorator,
24 id_decorator as episode_id_decorator
26 from mygpo.podcasts.views.podcast import (
27 slug_decorator as podcast_slug_decorator,
28 id_decorator as podcast_id_decorator
30 from mygpo.web.utils import get_podcast_link_target, normalize_twitter, \
31 get_episode_link_target
32 from django.contrib.sites.requests import RequestSite
33 from mygpo.data.tasks import update_podcasts
34 from mygpo.data.models import PodcastUpdateResult
35 from mygpo.decorators import requires_token, allowed_methods
36 from mygpo.pubsub.models import HubSubscription
39 @vary_on_cookie
40 @cache_control(private=True)
41 def home(request):
42 if is_publisher(request.user):
43 podcasts = Podcast.objects.filter(publishedpodcast__publisher=request.user)\
44 .prefetch_related('slugs')
45 site = RequestSite(request)
46 update_token = request.user.profile.get_token('publisher_update_token')
47 form = SearchPodcastForm()
48 return render(request, 'publisher/home.html', {
49 'update_token': update_token,
50 'podcasts': podcasts,
51 'form': form,
52 'site': site,
55 else:
56 site = RequestSite(request)
57 return render(request, 'publisher/info.html', {
58 'site': site
62 @vary_on_cookie
63 @cache_control(private=True)
64 @require_publisher
65 def search_podcast(request):
66 form = SearchPodcastForm(request.POST)
67 if form.is_valid():
68 podcast_url = form.cleaned_data['url']
69 podcast = get_object_or_404(Podcast, urls__url=podcast_url)
70 url = get_podcast_link_target(podcast, 'podcast-publisher-detail')
71 else:
72 url = reverse('publisher')
74 return HttpResponseRedirect(url)
77 @vary_on_cookie
78 @cache_control(private=True)
79 @require_publisher
80 @allowed_methods(['GET', 'POST'])
81 def podcast(request, podcast):
83 if not check_publisher_permission(request.user, podcast):
84 return HttpResponseForbidden()
86 timeline_data = listener_data([podcast])
87 subscription_data = subscriber_data([podcast])[-20:]
89 update_token = request.user.profile.get_token('publisher_update_token')
91 try:
92 pubsubscription = HubSubscription.objects.get(topic_url=podcast.url)
93 except HubSubscription.DoesNotExist:
94 pubsubscription = None
96 MAX_UPDATE_RESULTS=10
98 update_results = PodcastUpdateResult.objects.filter(podcast=podcast)
99 update_results = update_results[:MAX_UPDATE_RESULTS]
101 site = RequestSite(request)
102 feedurl_quoted = urllib.parse.quote(podcast.url.encode('ascii'))
104 return render(request, 'publisher/podcast.html', {
105 'site': site,
106 'podcast': podcast,
107 'group': podcast.group,
108 'form': None,
109 'timeline_data': timeline_data,
110 'subscriber_data': subscription_data,
111 'update_token': update_token,
112 'feedurl_quoted': feedurl_quoted,
113 'pubsubscription': pubsubscription,
114 'update_results': update_results,
118 @vary_on_cookie
119 @cache_control(private=True)
120 @require_publisher
121 def group(request, group):
123 podcasts = group.podcasts
125 # users need to have publisher access for at least one of the group's podcasts
126 if not any([check_publisher_permission(request.user, p) for p in podcasts]):
127 return HttpResponseForbidden()
129 timeline_data = listener_data(podcasts)
130 subscription_data = list(subscriber_data(podcasts))[-20:]
132 return render(request, 'publisher/group.html', {
133 'group': group,
134 'timeline_data': timeline_data,
135 'subscriber_data': subscription_data,
139 @vary_on_cookie
140 @cache_control(private=True)
141 @require_publisher
142 def update_podcast(request, podcast):
144 if not check_publisher_permission(request.user, podcast):
145 return HttpResponseForbidden()
147 update_podcasts.delay([podcast.url])
148 messages.success(request, _('The update has been scheduled. It might take some time until the results are visible.'))
150 url = get_podcast_link_target(podcast, 'podcast-publisher-detail')
151 return HttpResponseRedirect(url)
154 @vary_on_cookie
155 @cache_control(private=True)
156 @require_publisher
157 def save_podcast(request, podcast):
158 twitter = normalize_twitter(request.POST.get('twitter', ''))
159 podcast.twitter = twitter
160 podcast.save()
161 messages.success(request, _('Data updated'))
162 url = get_podcast_link_target(podcast, 'podcast-publisher-detail')
163 return HttpResponseRedirect(url)
167 @never_cache
168 @require_publisher
169 def new_update_token(request, username):
170 request.user.profile.create_new_token('publisher_update_token')
171 request.user.profile.save()
172 messages.success(request, _('Publisher token updated'))
173 return HttpResponseRedirect(reverse('publisher'))
176 @never_cache
177 @requires_token(token_name='publisher_update_token')
178 def update_published_podcasts(request, username):
179 User = get_user_model()
180 user = get_object_or_404(User, username=username)
181 published_podcasts = [pp.podcast for pp in user.publishedpodcast_set.all()]
182 update_podcasts.delay([podcast.url for podcast in published_podcasts])
183 return HttpResponse('Updated:\n' + '\n'.join([p.url for p in published_podcasts]), content_type='text/plain')
186 @vary_on_cookie
187 @cache_control(private=True)
188 @require_publisher
189 def episodes(request, podcast):
191 if not check_publisher_permission(request.user, podcast):
192 return HttpResponseForbidden()
194 episodes = Episode.objects.filter(podcast=podcast).select_related('podcast').prefetch_related('slugs', 'podcast__slugs')
196 listeners = filter(None, (e.listeners for e in episodes))
197 max_listeners = max(listeners, default=0)
199 return render(request, 'publisher/episodes.html', {
200 'podcast': podcast,
201 'episodes': episodes,
202 'max_listeners': max_listeners
206 @require_publisher
207 @vary_on_cookie
208 @cache_control(private=True)
209 @allowed_methods(['GET', 'POST'])
210 def episode(request, episode):
212 site = RequestSite(request)
213 podcast = episode.podcast
215 if not check_publisher_permission(request.user, podcast):
216 return HttpResponseForbidden()
218 if request.method == 'POST':
219 form = None # EpisodeForm(request.POST, instance=e)
220 # if form.is_valid():
221 # form.save()
223 elif request.method == 'GET':
224 form = None # EpisodeForm(instance=e)
226 timeline_data = list(episode_listener_data(episode))
228 return render(request, 'publisher/episode.html', {
229 'is_secure': request.is_secure(),
230 'domain': site.domain,
231 'episode': episode,
232 'podcast': podcast,
233 'form': form,
234 'timeline_data': timeline_data,
238 @require_publisher
239 @never_cache
240 @allowed_methods(['POST'])
241 def update_episode_slug(request, episode):
242 """ sets a new "main" slug, and moves the existing to the merged slugs """
244 new_slug = request.POST.get('slug')
245 podcast = episode.podcast
247 if new_slug:
248 # remove the new slug from other episodes (of the same podcast)
249 other_episodes = Episode.objects.filter(
250 podcast=podcast,
251 slugs__slug=new_slug,
252 slugs__content_type=ContentType.objects.get_for_model(Episode),
255 for other_episode in other_episodes:
257 if other_episode == episode:
258 continue
260 other_episode.remove_slug(new_slug)
261 messages.warning(request,
262 _('Removed slug {slug} from {episode}'.format(
263 slug=new_slug, episode=other_episode.title))
266 episode.set_slug(new_slug)
268 # TODO: we should use better cache invalidation
269 cache.clear()
271 return HttpResponseRedirect(
272 get_episode_link_target(episode, podcast, 'episode-publisher-detail')
276 @vary_on_cookie
277 @cache_control(private=True)
278 def link(request):
279 current_site = RequestSite(request)
280 return render(request, 'link.html', {
281 'url': current_site
285 @vary_on_cookie
286 @cache_control(private=True)
287 def advertise(request):
288 site = RequestSite(request)
289 return render(request, 'publisher/advertise.html', {
290 'site': site
294 def group_id_decorator(f):
295 @wraps(f)
296 def _decorator(request, pg_slug, *args, **kwargs):
297 group = get_object_or_404(PodcastGroup, pk=slug_id)
298 return f(request, group, *args, **kwargs)
300 return _decorator
303 episode_slug = episode_slug_decorator(episode)
304 update_episode_slug_slug = episode_slug_decorator(update_episode_slug)
305 podcast_slug = podcast_slug_decorator(podcast)
306 episodes_slug = podcast_slug_decorator(episodes)
307 update_podcast_slug = podcast_slug_decorator(update_podcast)
308 save_podcast_slug = podcast_slug_decorator(save_podcast)
310 episode_id = episode_id_decorator(episode)
311 update_episode_slug_id = episode_id_decorator(update_episode_slug)
312 podcast_id = podcast_id_decorator(podcast)
313 episodes_id = podcast_id_decorator(episodes)
314 update_podcast_id = podcast_id_decorator(update_podcast)
315 save_podcast_id = podcast_id_decorator(save_podcast)
317 group_slug = group_id_decorator(group)
318 group_id = group_id_decorator(group)