1 from functools
import wraps
2 import urllib
.request
, urllib
.parse
, urllib
.error
4 from django
.shortcuts
import render
5 from django
.http
import (
11 from django
.core
.cache
import cache
12 from django
.views
.decorators
.cache
import never_cache
, cache_control
13 from django
.views
.decorators
.vary
import vary_on_cookie
14 from django
.urls
import reverse
15 from django
.utils
.translation
import gettext
as _
16 from django
.contrib
import messages
17 from django
.contrib
.auth
import get_user_model
18 from django
.contrib
.contenttypes
.models
import ContentType
19 from django
.shortcuts
import get_object_or_404
21 from mygpo
.podcasts
.models
import PodcastGroup
, Podcast
, Episode
22 from mygpo
.publisher
.auth
import require_publisher
, is_publisher
23 from mygpo
.publisher
.forms
import SearchPodcastForm
24 from mygpo
.publisher
.utils
import (
26 episode_listener_data
,
27 check_publisher_permission
,
30 from mygpo
.podcasts
.views
.episode
import (
31 slug_decorator
as episode_slug_decorator
,
32 id_decorator
as episode_id_decorator
,
34 from mygpo
.podcasts
.views
.podcast
import (
35 slug_decorator
as podcast_slug_decorator
,
36 id_decorator
as podcast_id_decorator
,
38 from mygpo
.web
.utils
import (
39 get_podcast_link_target
,
41 get_episode_link_target
,
43 from django
.contrib
.sites
.requests
import RequestSite
44 from mygpo
.data
.tasks
import update_podcasts
45 from mygpo
.data
.models
import PodcastUpdateResult
46 from mygpo
.decorators
import requires_token
, allowed_methods
47 from mygpo
.pubsub
.models
import HubSubscription
51 @cache_control(private
=True)
53 if is_publisher(request
.user
):
54 podcasts
= Podcast
.objects
.filter(
55 publishedpodcast__publisher
=request
.user
56 ).prefetch_related("slugs")
57 site
= RequestSite(request
)
58 update_token
= request
.user
.profile
.get_token("publisher_update_token")
59 form
= SearchPodcastForm()
62 "publisher/home.html",
64 "update_token": update_token
,
72 site
= RequestSite(request
)
73 return render(request
, "publisher/info.html", {"site": site
})
77 @cache_control(private
=True)
79 def search_podcast(request
):
80 form
= SearchPodcastForm(request
.POST
)
82 podcast_url
= form
.cleaned_data
["url"]
83 podcast
= get_object_or_404(Podcast
, urls__url
=podcast_url
)
84 url
= get_podcast_link_target(podcast
, "podcast-publisher-detail")
86 url
= reverse("publisher")
88 return HttpResponseRedirect(url
)
92 @cache_control(private
=True)
94 @allowed_methods(["GET", "POST"])
95 def podcast(request
, podcast
):
97 if not check_publisher_permission(request
.user
, podcast
):
98 return HttpResponseForbidden()
100 timeline_data
= None # listener_data([podcast])
101 subscription_data
= None # subscriber_data([podcast])[-20:]
103 update_token
= request
.user
.profile
.get_token("publisher_update_token")
106 pubsubscription
= HubSubscription
.objects
.get(topic_url
=podcast
.url
)
107 except HubSubscription
.DoesNotExist
:
108 pubsubscription
= None
110 MAX_UPDATE_RESULTS
= 10
112 update_results
= PodcastUpdateResult
.objects
.filter(podcast
=podcast
)
113 update_results
= update_results
[:MAX_UPDATE_RESULTS
]
115 site
= RequestSite(request
)
116 feedurl_quoted
= urllib
.parse
.quote(podcast
.url
.encode("ascii"))
120 "publisher/podcast.html",
124 "group": podcast
.group
,
126 "timeline_data": timeline_data
,
127 "subscriber_data": subscription_data
,
128 "update_token": update_token
,
129 "feedurl_quoted": feedurl_quoted
,
130 "pubsubscription": pubsubscription
,
131 "update_results": update_results
,
137 @cache_control(private
=True)
139 def group(request
, group
):
141 podcasts
= group
.podcasts
143 # users need to have publisher access for at least one of the group's podcasts
144 if not any([check_publisher_permission(request
.user
, p
) for p
in podcasts
]):
145 return HttpResponseForbidden()
147 timeline_data
= listener_data(podcasts
)
148 subscription_data
= list(subscriber_data(podcasts
))[-20:]
152 "publisher/group.html",
155 "timeline_data": timeline_data
,
156 "subscriber_data": subscription_data
,
162 @cache_control(private
=True)
164 def update_podcast(request
, podcast
):
166 if not check_publisher_permission(request
.user
, podcast
):
167 return HttpResponseForbidden()
169 update_podcasts
.delay([podcast
.url
])
173 "The update has been scheduled. It might take some time until the results are visible."
177 url
= get_podcast_link_target(podcast
, "podcast-publisher-detail")
178 return HttpResponseRedirect(url
)
182 @cache_control(private
=True)
184 def save_podcast(request
, podcast
):
185 twitter
= normalize_twitter(request
.POST
.get("twitter", ""))
186 podcast
.twitter
= twitter
188 messages
.success(request
, _("Data updated"))
189 url
= get_podcast_link_target(podcast
, "podcast-publisher-detail")
190 return HttpResponseRedirect(url
)
195 def new_update_token(request
, username
):
196 request
.user
.profile
.create_new_token("publisher_update_token")
197 request
.user
.profile
.save()
198 messages
.success(request
, _("Publisher token updated"))
199 return HttpResponseRedirect(reverse("publisher"))
203 @requires_token(token_name
="publisher_update_token")
204 def update_published_podcasts(request
, username
):
205 User
= get_user_model()
206 user
= get_object_or_404(User
, username
=username
)
207 published_podcasts
= [pp
.podcast
for pp
in user
.publishedpodcast_set
.all()]
208 update_podcasts
.delay([podcast
.url
for podcast
in published_podcasts
])
210 "Updated:\n" + "\n".join([p
.url
for p
in published_podcasts
]),
211 content_type
="text/plain",
216 @cache_control(private
=True)
218 def episodes(request
, podcast
):
220 if not check_publisher_permission(request
.user
, podcast
):
221 return HttpResponseForbidden()
224 Episode
.objects
.filter(podcast
=podcast
)
225 .select_related("podcast")
226 .prefetch_related("slugs", "podcast__slugs")
229 listeners
= filter(None, (e
.listeners
for e
in episodes
))
230 max_listeners
= max(listeners
, default
=0)
234 "publisher/episodes.html",
235 {"podcast": podcast
, "episodes": episodes
, "max_listeners": max_listeners
},
241 @cache_control(private
=True)
242 @allowed_methods(["GET", "POST"])
243 def episode(request
, episode
):
245 site
= RequestSite(request
)
246 podcast
= episode
.podcast
248 if not check_publisher_permission(request
.user
, podcast
):
249 return HttpResponseForbidden()
251 if request
.method
== "POST":
252 form
= None # EpisodeForm(request.POST, instance=e)
253 # if form.is_valid():
256 elif request
.method
== "GET":
257 form
= None # EpisodeForm(instance=e)
259 timeline_data
= list(episode_listener_data(episode
))
263 "publisher/episode.html",
265 "is_secure": request
.is_secure(),
266 "domain": site
.domain
,
270 "timeline_data": timeline_data
,
277 @allowed_methods(["POST"])
278 def update_episode_slug(request
, episode
):
279 """sets a new "main" slug, and moves the existing to the merged slugs"""
281 new_slug
= request
.POST
.get("slug")
282 podcast
= episode
.podcast
285 # remove the new slug from other episodes (of the same podcast)
286 other_episodes
= Episode
.objects
.filter(
288 slugs__slug
=new_slug
,
289 slugs__content_type
=ContentType
.objects
.get_for_model(Episode
),
292 for other_episode
in other_episodes
:
294 if other_episode
== episode
:
297 other_episode
.remove_slug(new_slug
)
301 "Removed slug {slug} from {episode}".format(
302 slug
=new_slug
, episode
=other_episode
.title
307 episode
.set_slug(new_slug
)
309 # TODO: we should use better cache invalidation
312 return HttpResponseRedirect(
313 get_episode_link_target(episode
, podcast
, "episode-publisher-detail")
318 @cache_control(private
=True)
320 current_site
= RequestSite(request
)
321 return render(request
, "link.html", {"url": current_site
})
325 @cache_control(private
=True)
326 def advertise(request
):
327 site
= RequestSite(request
)
328 return render(request
, "publisher/advertise.html", {"site": site
})
331 def group_id_decorator(f
):
333 def _decorator(request
, pg_slug
, *args
, **kwargs
):
334 group
= get_object_or_404(PodcastGroup
, pk
=slug_id
)
335 return f(request
, group
, *args
, **kwargs
)
340 episode_slug
= episode_slug_decorator(episode
)
341 update_episode_slug_slug
= episode_slug_decorator(update_episode_slug
)
342 podcast_slug
= podcast_slug_decorator(podcast
)
343 episodes_slug
= podcast_slug_decorator(episodes
)
344 update_podcast_slug
= podcast_slug_decorator(update_podcast
)
345 save_podcast_slug
= podcast_slug_decorator(save_podcast
)
347 episode_id
= episode_id_decorator(episode
)
348 update_episode_slug_id
= episode_id_decorator(update_episode_slug
)
349 podcast_id
= podcast_id_decorator(podcast
)
350 episodes_id
= podcast_id_decorator(episodes
)
351 update_podcast_id
= podcast_id_decorator(update_podcast
)
352 save_podcast_id
= podcast_id_decorator(save_podcast
)
354 group_slug
= group_id_decorator(group
)
355 group_id
= group_id_decorator(group
)