Merge pull request #793 from gpodder/remove-advertise
[mygpo.git] / mygpo / publisher / views.py
blobdc1b4ff94ca1dfd4dc61a8c421b096618dd60d01
1 from functools import wraps
2 import urllib.request, urllib.parse, urllib.error
4 from django.shortcuts import render
5 from django.http import (
6 HttpResponse,
7 HttpResponseRedirect,
8 HttpResponseForbidden,
9 Http404,
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 (
25 listener_data,
26 episode_listener_data,
27 check_publisher_permission,
28 subscriber_data,
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,
40 normalize_twitter,
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
50 @vary_on_cookie
51 @cache_control(private=True)
52 def home(request):
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()
60 return render(
61 request,
62 "publisher/home.html",
64 "update_token": update_token,
65 "podcasts": podcasts,
66 "form": form,
67 "site": site,
71 else:
72 site = RequestSite(request)
73 return render(request, "publisher/info.html", {"site": site})
76 @vary_on_cookie
77 @cache_control(private=True)
78 @require_publisher
79 def search_podcast(request):
80 form = SearchPodcastForm(request.POST)
81 if form.is_valid():
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")
85 else:
86 url = reverse("publisher")
88 return HttpResponseRedirect(url)
91 @vary_on_cookie
92 @cache_control(private=True)
93 @require_publisher
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")
105 try:
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"))
118 return render(
119 request,
120 "publisher/podcast.html",
122 "site": site,
123 "podcast": podcast,
124 "group": podcast.group,
125 "form": None,
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,
136 @vary_on_cookie
137 @cache_control(private=True)
138 @require_publisher
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:]
150 return render(
151 request,
152 "publisher/group.html",
154 "group": group,
155 "timeline_data": timeline_data,
156 "subscriber_data": subscription_data,
161 @vary_on_cookie
162 @cache_control(private=True)
163 @require_publisher
164 def update_podcast(request, podcast):
166 if not check_publisher_permission(request.user, podcast):
167 return HttpResponseForbidden()
169 update_podcasts.delay([podcast.url])
170 messages.success(
171 request,
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)
181 @vary_on_cookie
182 @cache_control(private=True)
183 @require_publisher
184 def save_podcast(request, podcast):
185 twitter = normalize_twitter(request.POST.get("twitter", ""))
186 podcast.twitter = twitter
187 podcast.save()
188 messages.success(request, _("Data updated"))
189 url = get_podcast_link_target(podcast, "podcast-publisher-detail")
190 return HttpResponseRedirect(url)
193 @never_cache
194 @require_publisher
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"))
202 @never_cache
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])
209 return HttpResponse(
210 "Updated:\n" + "\n".join([p.url for p in published_podcasts]),
211 content_type="text/plain",
215 @vary_on_cookie
216 @cache_control(private=True)
217 @require_publisher
218 def episodes(request, podcast):
220 if not check_publisher_permission(request.user, podcast):
221 return HttpResponseForbidden()
223 episodes = (
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)
232 return render(
233 request,
234 "publisher/episodes.html",
235 {"podcast": podcast, "episodes": episodes, "max_listeners": max_listeners},
239 @require_publisher
240 @vary_on_cookie
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():
254 # form.save()
256 elif request.method == "GET":
257 form = None # EpisodeForm(instance=e)
259 timeline_data = list(episode_listener_data(episode))
261 return render(
262 request,
263 "publisher/episode.html",
265 "is_secure": request.is_secure(),
266 "domain": site.domain,
267 "episode": episode,
268 "podcast": podcast,
269 "form": form,
270 "timeline_data": timeline_data,
275 @require_publisher
276 @never_cache
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
284 if new_slug:
285 # remove the new slug from other episodes (of the same podcast)
286 other_episodes = Episode.objects.filter(
287 podcast=podcast,
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:
295 continue
297 other_episode.remove_slug(new_slug)
298 messages.warning(
299 request,
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
310 cache.clear()
312 return HttpResponseRedirect(
313 get_episode_link_target(episode, podcast, "episode-publisher-detail")
317 @vary_on_cookie
318 @cache_control(private=True)
319 def link(request):
320 current_site = RequestSite(request)
321 return render(request, "link.html", {"url": current_site})
324 @vary_on_cookie
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):
332 @wraps(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)
337 return _decorator
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)