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
13 from django
.shortcuts
import get_object_or_404
15 from mygpo
.podcasts
.models
import PodcastGroup
, Podcast
16 from mygpo
.core
.proxy
import proxy_object
17 from mygpo
.publisher
.auth
import require_publisher
, is_publisher
18 from mygpo
.publisher
.forms
import SearchPodcastForm
19 from mygpo
.publisher
.utils
import listener_data
, episode_listener_data
, \
20 check_publisher_permission
, subscriber_data
21 from mygpo
.web
.heatmap
import EpisodeHeatmap
22 from mygpo
.web
.views
.episode
import slug_decorator
as episode_slug_decorator
23 from mygpo
.web
.views
.podcast
import slug_decorator
as podcast_slug_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 set_episode_slug
, remove_episode_slug
31 from mygpo
.db
.couchdb
.episode_state
import episode_listener_counts
32 from mygpo
.db
.couchdb
.pubsub
import subscription_for_topic
36 @cache_control(private
=True)
38 if is_publisher(request
.user
):
39 podcasts
= Podcasts
.objects
.filter(id__in
=request
.user
.published_objects
)
40 site
= RequestSite(request
)
41 update_token
= request
.user
.get_token('publisher_update_token')
42 form
= SearchPodcastForm()
43 return render(request
, 'publisher/home.html', {
44 'update_token': update_token
,
51 site
= RequestSite(request
)
52 return render(request
, 'publisher/info.html', {
58 @cache_control(private
=True)
60 def search_podcast(request
):
61 form
= SearchPodcastForm(request
.POST
)
63 podcast_url
= form
.cleaned_data
['url']
64 podcast
= get_objet_or_404(Podcast
, urls__url
=podcast_url
)
65 url
= get_podcast_link_target(podcast
, 'podcast-publisher-detail')
67 url
= reverse('publisher')
69 return HttpResponseRedirect(url
)
73 @cache_control(private
=True)
75 @allowed_methods(['GET', 'POST'])
76 def podcast(request
, podcast
):
78 if not check_publisher_permission(request
.user
, podcast
):
79 return HttpResponseForbidden()
81 timeline_data
= listener_data([podcast
])
82 subscription_data
= subscriber_data([podcast
])[-20:]
84 update_token
= request
.user
.publisher_update_token
86 heatmap
= EpisodeHeatmap(podcast
.get_id())
88 pubsubscription
= subscription_for_topic(podcast
.url
)
90 site
= RequestSite(request
)
91 feedurl_quoted
= urllib
.quote(podcast
.url
)
93 return render(request
, 'publisher/podcast.html', {
96 'group': podcast
.group
,
98 'timeline_data': timeline_data
,
99 'subscriber_data': subscription_data
,
100 'update_token': update_token
,
102 'feedurl_quoted': feedurl_quoted
,
103 'pubsubscription': pubsubscription
,
108 @cache_control(private
=True)
110 def group(request
, group
):
112 podcasts
= group
.podcasts
114 # users need to have publisher access for at least one of the group's podcasts
115 if not any([check_publisher_permission(request
.user
, p
) for p
in podcasts
]):
116 return HttpResponseForbidden()
118 timeline_data
= listener_data(podcasts
)
119 subscription_data
= list(subscriber_data(podcasts
))[-20:]
121 return render(request
, 'publisher/group.html', {
123 'timeline_data': timeline_data
,
124 'subscriber_data': subscription_data
,
129 @cache_control(private
=True)
131 def update_podcast(request
, podcast
):
133 if not check_publisher_permission(request
.user
, podcast
):
134 return HttpResponseForbidden()
136 update_podcasts
.delay([podcast
.url
])
137 messages
.success(request
, _('The update has been scheduled. It might take some time until the results are visible.'))
139 url
= get_podcast_link_target(podcast
, 'podcast-publisher-detail')
140 return HttpResponseRedirect(url
)
144 @cache_control(private
=True)
146 def save_podcast(request
, podcast
):
147 twitter
= normalize_twitter(request
.POST
.get('twitter', ''))
148 podcast
.twitter
= twitter
150 messages
.success(request
, _('Data updated'))
151 url
= get_podcast_link_target(podcast
, 'podcast-publisher-detail')
152 return HttpResponseRedirect(url
)
158 def new_update_token(request
, username
):
159 request
.user
.create_new_token('publisher_update_token')
161 messages
.success(request
, _('Publisher token updated'))
162 return HttpResponseRedirect(reverse('publisher'))
166 @requires_token(token_name
='publisher_update_token')
167 def update_published_podcasts(request
, username
):
168 user
= User
.get_user(username
)
172 published_podcasts
= Podcast
.objects
.filter(id__in
=user
.published_objects
)
173 update_podcasts
.delay([podcast
.url
for podcast
in published_podcasts
])
174 return HttpResponse('Updated:\n' + '\n'.join([p
.url
for p
in published_podcasts
]), mimetype
='text/plain')
178 @cache_control(private
=True)
180 def episodes(request
, podcast
):
182 if not check_publisher_permission(request
.user
, podcast
):
183 return HttpResponseForbidden()
185 episodes
= podcast
.episode_set().all()
186 listeners
= dict(episode_listener_counts(podcast
))
188 max_listeners
= max(listeners
.values() + [0])
190 def annotate_episode(episode
):
191 listener_count
= listeners
.get(episode
._id
, None)
192 return proxy_object(episode
, listeners
=listener_count
)
194 episodes
= map(annotate_episode
, episodes
)
196 return render(request
, 'publisher/episodes.html', {
198 'episodes': episodes
,
199 'max_listeners': max_listeners
205 @cache_control(private
=True)
206 @allowed_methods(['GET', 'POST'])
207 def episode(request
, episode
):
209 site
= RequestSite(request
)
210 podcast
= episode
.podcast
212 if not check_publisher_permission(request
.user
, podcast
):
213 return HttpResponseForbidden()
215 if request
.method
== 'POST':
216 form
= None # EpisodeForm(request.POST, instance=e)
217 # if form.is_valid():
220 elif request
.method
== 'GET':
221 form
= None # EpisodeForm(instance=e)
223 timeline_data
= list(episode_listener_data(episode
))
225 heatmap
= EpisodeHeatmap(episode
.podcast
, episode
._id
,
226 duration
=episode
.duration
)
228 return render(request
, 'publisher/episode.html', {
229 'is_secure': request
.is_secure(),
230 'domain': site
.domain
,
234 'timeline_data': timeline_data
,
241 @allowed_methods(['POST'])
242 def update_episode_slug(request
, episode
):
243 """ sets a new "main" slug, and moves the existing to the merged slugs """
245 new_slug
= request
.POST
.get('slug')
246 podcast
= episode
.podcast
249 # remove the new slug from other episodes (of the same podcast)
250 other_episodes
= Episode
.objects
.filter(podcast
=podcast
,
251 slugs__slug
=new_slug
)
253 for other_episode
in other_episodes
:
255 if other_episode
== episode
:
258 remove_episode_slug(other_episode
, new_slug
)
259 messages
.warning(request
,
260 _(u
'Removed slug {slug} from {episode}'.format(
261 slug
=new_slug
, episode
=other_episode
.title
))
264 set_episode_slug(episode
, new_slug
)
266 # TODO: we should use better cache invalidation
269 return HttpResponseRedirect(
270 get_episode_link_target(episode
, podcast
, 'episode-publisher-detail')
275 @cache_control(private
=True)
277 current_site
= RequestSite(request
)
278 return render(request
, 'link.html', {
284 @cache_control(private
=True)
285 def advertise(request
):
286 site
= RequestSite(request
)
287 return render(request
, 'publisher/advertise.html', {
292 def group_id_decorator(f
):
294 def _decorator(request
, slug_id
, *args
, **kwargs
):
295 group
= get_object_or_404(PodcastGroup
, pk
=slug_id
)
296 return f(request
, group
, *args
, **kwargs
)
301 episode_slug
= episode_slug_decorator(episode
)
302 update_episode_slug_slug
= episode_slug_decorator(update_episode_slug
)
303 podcast_slug
= podcast_slug_decorator(podcast
)
304 episodes_slug
= podcast_slug_decorator(episodes
)
305 update_podcast_slug
= podcast_slug_decorator(update_podcast
)
306 save_podcast_slug
= podcast_slug_decorator(save_podcast
)
307 group_slug
= group_id_decorator(group
)