Reformat urls.py
[mygpo.git] / mygpo / web / views / episode.py
blob730cc5ac8cb4c23afb792b40036013b5847fec2c
2 # This file is part of my.gpodder.org.
4 # my.gpodder.org is free software: you can redistribute it and/or modify it
5 # under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or (at your
7 # option) any later version.
9 # my.gpodder.org is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
12 # License for more details.
14 # You should have received a copy of the GNU Affero General Public License
15 # along with my.gpodder.org. If not, see <http://www.gnu.org/licenses/>.
18 from datetime import datetime
19 from functools import wraps
21 import dateutil.parser
23 from django.shortcuts import render
24 from django.http import HttpResponseRedirect, Http404
25 from django.contrib.auth.decorators import login_required
26 from django.contrib.sites.requests import RequestSite
27 from django.contrib.contenttypes.models import ContentType
28 from django.views.decorators.vary import vary_on_cookie
29 from django.views.decorators.cache import never_cache, cache_control
30 from django.contrib import messages
31 from django.utils.translation import ugettext as _
33 from mygpo.podcasts.models import Podcast, Episode
34 from mygpo.api.constants import EPISODE_ACTION_TYPES
35 from mygpo.core.tasks import flattr_thing
36 from mygpo.utils import parse_time, get_timestamp
37 from mygpo.users.settings import FLATTR_TOKEN
38 from mygpo.history.stats import last_played_episodes
39 from mygpo.publisher.utils import check_publisher_permission
40 from mygpo.web.utils import get_episode_link_target, check_restrictions
41 from mygpo.history.models import EpisodeHistoryEntry
42 from mygpo.favorites.models import FavoriteEpisode
43 from mygpo.userfeeds.feeds import FavoriteFeed
46 @vary_on_cookie
47 @cache_control(private=True)
48 def episode(request, episode):
50 podcast = episode.podcast
52 podcast = check_restrictions(podcast)
54 user = request.user
56 if not podcast:
57 raise Http404
59 if user.is_authenticated():
61 is_fav = FavoriteEpisode.objects.filter(user=user, episode=episode)\
62 .exists()
64 # pre-populate data for fetch_data
65 podcasts_dict = {podcast.get_id(): podcast}
66 episodes_dict = {episode.id.hex: episode}
68 has_history = EpisodeHistoryEntry.objects.filter(user=user,
69 episode=episode)\
70 .exists()
72 devices = {c.id.hex: c for c in user.client_set.all()}
73 can_flattr = user.profile.settings.get_wksetting(FLATTR_TOKEN) and episode.flattr_url
75 else:
76 has_history = False
77 is_fav = False
78 devices = {}
79 can_flattr = False
81 is_publisher = check_publisher_permission(user, podcast)
83 prev = None #podcast.get_episode_before(episode)
84 next = None #podcast.get_episode_after(episode)
86 return render(request, 'episode.html', {
87 'episode': episode,
88 'podcast': podcast,
89 'prev': prev,
90 'next': next,
91 'has_history': has_history,
92 'is_favorite': is_fav,
93 'actions': EPISODE_ACTION_TYPES,
94 'devices': devices,
95 'can_flattr': can_flattr,
96 'is_publisher': is_publisher,
100 @never_cache
101 @login_required
102 @vary_on_cookie
103 @cache_control(private=True)
104 def history(request, episode):
105 """ shows the history of the episode """
107 user = request.user
108 podcast = episode.podcast
110 history = EpisodeHistoryEntry.objects.filter(user=user,
111 episode=episode,)\
112 .order_by('-timestamp')\
113 .prefetch_related('episode',
114 'episode__slugs',
115 'episode__podcast',
116 'episode__podcast__slugs',
117 'client')
119 clients = user.client_set.all()
121 return render(request, 'episode-history.html', {
122 'episode': episode,
123 'podcast': podcast,
124 'history': history,
125 'actions': EPISODE_ACTION_TYPES,
126 'clients': clients,
130 @never_cache
131 @login_required
132 def toggle_favorite(request, episode):
133 user = request.user
135 fav, created = FavoriteEpisode.objects.get_or_create(
136 user=user,
137 episode=episode,
140 # if the episode was already a favorite, remove it
141 if not created:
142 fav.delete()
144 podcast = episode.podcast
145 return HttpResponseRedirect(get_episode_link_target(episode, podcast))
149 @vary_on_cookie
150 @cache_control(private=True)
151 @login_required
152 def list_favorites(request):
153 user = request.user
154 site = RequestSite(request)
156 favorites = FavoriteEpisode.episodes_for_user(user)
158 recently_listened = last_played_episodes(user)
160 favfeed = FavoriteFeed(user)
161 feed_url = favfeed.get_public_url(site.domain)
163 podcast = Podcast.objects.filter(urls__url=feed_url).first()
165 token = request.user.profile.favorite_feeds_token
167 return render(request, 'favorites.html', {
168 'episodes': favorites,
169 'feed_token': token,
170 'site': site,
171 'podcast': podcast,
172 'recently_listened': recently_listened,
176 @never_cache
177 def add_action(request, episode):
179 user = request.user
180 client = user.client_set.get(id=request.POST.get('device'))
182 action_str = request.POST.get('action')
183 timestamp = request.POST.get('timestamp', '')
185 if timestamp:
186 try:
187 timestamp = dateutil.parser.parse(timestamp)
188 except (ValueError, AttributeError, TypeError):
189 timestamp = datetime.utcnow()
190 else:
191 timestamp = datetime.utcnow()
193 EpisodeHistoryEntry.create_entry(user, episode, action_str, client,
194 timestamp)
195 podcast = episode.podcast
196 return HttpResponseRedirect(get_episode_link_target(episode, podcast))
199 @never_cache
200 @login_required
201 def flattr_episode(request, episode):
202 """ Flattrs an episode, records an event and redirects to the episode """
204 user = request.user
205 site = RequestSite(request)
207 # Flattr via the tasks queue, but wait for the result
208 task = flattr_thing.delay(user.pk, episode._id, site.domain,
209 request.is_secure(), 'Episode')
210 success, msg = task.get()
212 if success:
213 messages.success(request, _("Flattr\'d"))
215 else:
216 messages.error(request, msg)
218 podcast = episode.podcast
219 return HttpResponseRedirect(get_episode_link_target(episode, podcast))
222 # To make all view accessible via either IDs or Slugs
223 # a decorator queries the episode and passes the Id on to the
224 # regular views
226 def slug_decorator(f):
227 @wraps(f)
228 def _decorator(request, p_slug, e_slug, *args, **kwargs):
230 pquery = Podcast.objects.filter(
231 slugs__slug=p_slug,
232 slugs__scope='',
235 try:
236 podcast = pquery.prefetch_related('slugs').get()
237 except Podcast.DoesNotExist:
238 raise Http404
240 equery = Episode.objects.filter(
241 podcast = podcast,
242 slugs__slug=e_slug,
243 slugs__scope=podcast.id.hex,
246 try:
247 episode = equery.prefetch_related('urls', 'slugs').get()
249 # set previously fetched podcast, to avoid additional query
250 episode.podcast = podcast
252 except Episode.DoesNotExist:
253 raise Http404
255 # redirect when Id or a merged (non-cannonical) slug is used
256 if episode.slug and episode.slug != e_slug:
257 return HttpResponseRedirect(
258 get_episode_link_target(episode, podcast))
260 return f(request, episode, *args, **kwargs)
262 return _decorator
265 def id_decorator(f):
266 @wraps(f)
267 def _decorator(request, p_id, e_id, *args, **kwargs):
269 try:
270 query = Episode.objects.filter(id=e_id,
271 podcast_id=p_id)
272 episode = query.select_related('podcast').get()
274 except Episode.DoesNotExist:
275 raise Http404
277 # redirect when Id or a merged (non-cannonical) slug is used
278 if episode.slug and episode.slug != e_id:
279 podcast = episode.podcast
280 return HttpResponseRedirect(
281 get_episode_link_target(episode, podcast))
283 return f(request, episode, *args, **kwargs)
285 return _decorator
289 show_slug = slug_decorator(episode)
290 toggle_favorite_slug = slug_decorator(toggle_favorite)
291 add_action_slug = slug_decorator(add_action)
292 flattr_episode_slug = slug_decorator(flattr_episode)
293 episode_history_slug = slug_decorator(history)
295 show_id = id_decorator(episode)
296 toggle_favorite_id = id_decorator(toggle_favorite)
297 add_action_id = id_decorator(add_action)
298 flattr_episode_id = id_decorator(flattr_episode)
299 episode_history_id = id_decorator(history)