1 from functools
import wraps
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
14 from mygpo
.core
.proxy
import proxy_object
15 from mygpo
.publisher
.auth
import require_publisher
, is_publisher
16 from mygpo
.publisher
.forms
import SearchPodcastForm
17 from mygpo
.publisher
.utils
import listener_data
, episode_listener_data
, \
18 check_publisher_permission
, subscriber_data
19 from mygpo
.web
.heatmap
import EpisodeHeatmap
20 from mygpo
.web
.views
.episode
import oldid_decorator
, slug_id_decorator
21 from mygpo
.web
.views
.podcast
import \
22 slug_id_decorator
as podcast_slug_id_decorator
, \
23 oldid_decorator
as podcast_oldid_decorator
24 from mygpo
.web
.utils
import get_podcast_link_target
, normalize_twitter
, \
25 get_episode_link_target
26 from django
.contrib
.sites
.models
import RequestSite
27 from mygpo
.data
.tasks
import update_podcasts
28 from mygpo
.decorators
import requires_token
, allowed_methods
29 from mygpo
.users
.models
import User
30 from mygpo
.db
.couchdb
.episode
import episodes_for_podcast
, episodes_for_slug
, \
31 set_episode_slug
, remove_episode_slug
32 from mygpo
.db
.couchdb
.podcast
import podcast_by_id
, podcasts_by_id
, \
33 podcast_for_url
, podcastgroup_for_slug_id
, podcastgroup_for_oldid
, \
34 podcastgroup_by_id
, update_additional_data
35 from mygpo
.db
.couchdb
.episode_state
import episode_listener_counts
39 @cache_control(private
=True)
41 if is_publisher(request
.user
):
42 podcasts
= podcasts_by_id(request
.user
.published_objects
)
43 site
= RequestSite(request
)
44 update_token
= request
.user
.get_token('publisher_update_token')
45 form
= SearchPodcastForm()
46 return render(request
, 'publisher/home.html', {
47 'update_token': update_token
,
54 site
= RequestSite(request
)
55 return render(request
, 'publisher/info.html', {
61 @cache_control(private
=True)
63 def search_podcast(request
):
64 form
= SearchPodcastForm(request
.POST
)
66 url
= form
.cleaned_data
['url']
68 podcast
= podcast_for_url(url
)
72 url
= get_podcast_link_target(podcast
, 'podcast-publisher-detail')
74 url
= reverse('publisher')
76 return HttpResponseRedirect(url
)
80 @cache_control(private
=True)
82 @allowed_methods(['GET', 'POST'])
83 def podcast(request
, podcast
):
85 if not check_publisher_permission(request
.user
, podcast
):
86 return HttpResponseForbidden()
88 timeline_data
= listener_data([podcast
])
89 subscription_data
= subscriber_data([podcast
])[-20:]
92 group
= podcastgroup_by_id(podcast
.group
)
96 update_token
= request
.user
.publisher_update_token
98 heatmap
= EpisodeHeatmap(podcast
.get_id())
100 site
= RequestSite(request
)
101 feedurl_quoted
= urllib
.quote(podcast
.url
)
103 return render(request
, 'publisher/podcast.html', {
108 'timeline_data': timeline_data
,
109 'subscriber_data': subscription_data
,
110 'update_token': update_token
,
112 'feedurl_quoted': feedurl_quoted
,
117 @cache_control(private
=True)
119 def group(request
, group
):
121 podcasts
= group
.podcasts
123 # users need to have publisher access for at least one of the group's podcasts
124 if not any([check_publisher_permission(request
.user
, p
) for p
in podcasts
]):
125 return HttpResponseForbidden()
127 timeline_data
= listener_data(podcasts
)
128 subscription_data
= list(subscriber_data(podcasts
))[-20:]
130 return render(request
, 'publisher/group.html', {
132 'timeline_data': timeline_data
,
133 'subscriber_data': subscription_data
,
138 @cache_control(private
=True)
140 def update_podcast(request
, podcast
):
142 if not check_publisher_permission(request
.user
, podcast
):
143 return HttpResponseForbidden()
145 update_podcasts
.delay([podcast
.url
])
146 messages
.success(request
, _('The update has been scheduled. It might take some time until the results are visible.'))
148 url
= get_podcast_link_target(podcast
, 'podcast-publisher-detail')
149 return HttpResponseRedirect(url
)
153 @cache_control(private
=True)
155 def save_podcast(request
, podcast
):
156 twitter
= normalize_twitter(request
.POST
.get('twitter', ''))
157 update_additional_data(podcast
, twitter
)
158 messages
.success(request
, _('Data updated'))
159 url
= get_podcast_link_target(podcast
, 'podcast-publisher-detail')
160 return HttpResponseRedirect(url
)
166 def new_update_token(request
, username
):
167 request
.user
.create_new_token('publisher_update_token')
169 messages
.success(request
, _('Publisher token updated'))
170 return HttpResponseRedirect(reverse('publisher'))
174 @requires_token(token_name
='publisher_update_token')
175 def update_published_podcasts(request
, username
):
176 user
= User
.get_user(username
)
180 published_podcasts
= podcasts_by_id(user
.published_objects
)
181 update_podcasts
.delay([podcast
.url
for podcast
in published_podcasts
])
182 return HttpResponse('Updated:\n' + '\n'.join([p
.url
for p
in published_podcasts
]), mimetype
='text/plain')
186 @cache_control(private
=True)
188 def episodes(request
, podcast
):
190 if not check_publisher_permission(request
.user
, podcast
):
191 return HttpResponseForbidden()
193 episodes
= episodes_for_podcast(podcast
, descending
=True)
194 listeners
= dict(episode_listener_counts(podcast
))
196 max_listeners
= max(listeners
.values() + [0])
198 def annotate_episode(episode
):
199 listener_count
= listeners
.get(episode
._id
, None)
200 return proxy_object(episode
, listeners
=listener_count
)
202 episodes
= map(annotate_episode
, episodes
)
204 return render(request
, 'publisher/episodes.html', {
206 'episodes': episodes
,
207 'max_listeners': max_listeners
213 @cache_control(private
=True)
214 @allowed_methods(['GET', 'POST'])
215 def episode(request
, episode
):
217 site
= RequestSite(request
)
218 podcast
= podcast_by_id(episode
.podcast
)
220 if not check_publisher_permission(request
.user
, podcast
):
221 return HttpResponseForbidden()
223 if request
.method
== 'POST':
224 form
= None #EpisodeForm(request.POST, instance=e)
228 elif request
.method
== 'GET':
229 form
= None #EpisodeForm(instance=e)
231 timeline_data
= list(episode_listener_data(episode
))
233 heatmap
= EpisodeHeatmap(episode
.podcast
, episode
._id
,
234 duration
=episode
.duration
)
236 return render(request
, 'publisher/episode.html', {
237 'is_secure': request
.is_secure(),
238 'domain': site
.domain
,
242 'timeline_data': timeline_data
,
249 @allowed_methods(['POST'])
250 def update_episode_slug(request
, episode
):
251 """ sets a new "main" slug, and moves the existing to the merged slugs """
253 new_slug
= request
.POST
.get('slug')
254 podcast
= podcast_by_id(episode
.podcast
)
257 # remove the new slug from other episodes (of the same podcast)
258 other_episodes
= episodes_for_slug(podcast
.get_id(), new_slug
)
260 for other_episode
in other_episodes
:
262 if other_episode
== episode
:
265 remove_episode_slug(other_episode
, new_slug
)
266 messages
.warning(request
,
267 _(u
'Removed slug {slug} from {episode}'.format(
268 slug
=new_slug
, episode
=other_episode
.title
))
271 set_episode_slug(episode
, new_slug
)
273 # TODO: we should use better cache invalidation
276 return HttpResponseRedirect(
277 get_episode_link_target(episode
, podcast
, 'episode-publisher-detail')
282 @cache_control(private
=True)
284 current_site
= RequestSite(request
)
285 return render(request
, 'link.html', {
291 @cache_control(private
=True)
292 def advertise(request
):
293 site
= RequestSite(request
)
294 return render(request
, 'publisher/advertise.html', {
299 def group_slug_id_decorator(f
):
301 def _decorator(request
, slug_id
, *args
, **kwargs
):
302 group
= podcastgroup_for_slug_id(slug_id
)
307 return f(request
, group
, *args
, **kwargs
)
312 def group_oldid_decorator(f
):
314 def _decorator(request
, pid
, *args
, **kwargs
):
317 except (TypeError, ValueError):
320 group
= podcastgroup_for_oldid(pid
)
325 return f(request
, group
, *args
, **kwargs
)
331 episode_oldid
= oldid_decorator(episode
)
332 podcast_oldid
= podcast_oldid_decorator(podcast
)
333 update_podcast_oldid
= podcast_oldid_decorator(update_podcast
)
334 save_podcast_oldid
= podcast_oldid_decorator(save_podcast
)
335 episodes_oldid
= podcast_oldid_decorator(episodes
)
336 group_oldid
= group_oldid_decorator(group
)
338 episode_slug_id
= slug_id_decorator(episode
)
339 update_episode_slug_slug_id
= slug_id_decorator(update_episode_slug
)
340 podcast_slug_id
= podcast_slug_id_decorator(podcast
)
341 episodes_slug_id
= podcast_slug_id_decorator(episodes
)
342 update_podcast_slug_id
= podcast_slug_id_decorator(update_podcast
)
343 save_podcast_slug_id
= podcast_slug_id_decorator(save_podcast
)
344 group_slug_id
= group_slug_id_decorator(group
)