fix broken subscription changes feed
[mygpo.git] / mygpo / web / views / subscriptions.py
blob7cf8025222829c10b0ec88b149ffdb8bdac27def
1 from django.core.urlresolvers import reverse
2 from django.contrib.auth.decorators import login_required
3 from django.contrib.sites.models import RequestSite
4 from django.shortcuts import render
5 from django.contrib.syndication.views import Feed
6 from django.utils.translation import ugettext as _
7 from django.http import HttpResponse, Http404
8 from django.views.decorators.vary import vary_on_cookie
9 from django.views.decorators.cache import never_cache, cache_control
11 from mygpo.core.models import Podcast
12 from mygpo.utils import parse_bool, unzip, get_to_dict, skip_pairs
13 from mygpo.decorators import requires_token
14 from mygpo.api import backend, simple
15 from mygpo.users.models import HistoryEntry, User
16 from mygpo.web import utils
17 from mygpo.cache import get_cache_or_calc
20 @vary_on_cookie
21 @cache_control(private=True)
22 @login_required
23 def show_list(request):
24 current_site = RequestSite(request)
25 subscriptionlist = create_subscriptionlist(request)
26 return render(request, 'subscriptions.html', {
27 'subscriptionlist': subscriptionlist,
28 'url': current_site
32 @vary_on_cookie
33 @cache_control(private=True)
34 @login_required
35 def download_all(request):
36 podcasts = request.user.get_subscribed_podcasts()
37 response = simple.format_podcast_list(podcasts, 'opml', request.user.username)
38 response['Content-Disposition'] = 'attachment; filename=all-subscriptions.opml'
39 return response
42 @requires_token(token_name='subscriptions_token', denied_template='user_subscriptions_denied.html')
43 def for_user(request, username):
44 user = User.get_user(username)
45 if not user:
46 raise Http404
48 subscriptions = user.get_subscribed_podcasts(public=True)
49 token = user.get_token('subscriptions_token')
51 return render(request, 'user_subscriptions.html', {
52 'subscriptions': subscriptions,
53 'other_user': user,
54 'token': token,
57 @requires_token(token_name='subscriptions_token')
58 def for_user_opml(request, username):
59 user = User.get_user(username)
60 if not user:
61 raise Http404
63 subscriptions = user.get_subscribed_podcasts(public=True)
65 if parse_bool(request.GET.get('symbian', False)):
66 subscriptions = map(utils.symbian_opml_changes, subscriptions)
68 response = render(request, 'user_subscriptions.opml', {
69 'subscriptions': subscriptions,
70 'other_user': user
72 response['Content-Disposition'] = 'attachment; filename=%s-subscriptions.opml' % username
73 return response
76 def create_subscriptionlist(request):
78 user = request.user
79 user.sync_all()
81 subscriptions = user.get_subscriptions()
83 if not subscriptions:
84 return []
86 # Load all Podcasts and Devices first to ensure that they are
87 # only loaded once, not for each occurance in a subscription
88 public, podcast_ids, device_ids = unzip(subscriptions)
89 podcast_ids= list(set(podcast_ids))
90 device_ids = list(set(device_ids))
92 podcasts = get_to_dict(Podcast, podcast_ids, get_id=Podcast.get_id)
93 devices = dict([ (id, user.get_device(id)) for id in device_ids])
95 subscription_list = {}
96 for public, podcast_id, device_id in subscriptions:
97 device = devices[device_id]
98 if not podcast_id in subscription_list:
99 podcast = podcasts.get(podcast_id, None)
100 if podcast is None:
101 continue
103 episode = get_cache_or_calc('%s-latest-episode' % podcast.get_id(),
104 60*60, podcast.get_latest_episode)
106 subscription_list[podcast_id] = {
107 'podcast': podcasts[podcast_id],
108 'devices': [device] if device else [],
109 'episode': episode
111 else:
112 if device:
113 subscription_list[podcast_id]['devices'].append(device)
115 return subscription_list.values()
118 @requires_token(token_name='subscriptions_token')
119 def subscriptions_feed(request, username):
120 # Create to feed manually so we can wrap the token-authentication around it
121 f = SubscriptionsFeed(username)
122 obj = f.get_object(request, username)
123 feedgen = f.get_feed(obj, request)
124 response = HttpResponse(mimetype=feedgen.mime_type)
125 feedgen.write(response, 'utf-8')
126 return response
129 class SubscriptionsFeed(Feed):
130 """ A feed showing subscription changes for a certain user """
132 def __init__(self, username):
133 self.username = username
135 def get_object(self, request, username):
136 self.site = RequestSite(request)
137 return User.get_user(username)
139 def title(self, user):
140 return _('%(username)s\'s Podcast Subscriptions on %(site)s') % \
141 dict(username=user.username, site=self.site)
143 def description(self, user):
144 return _('Recent changes to %(username)s\'s podcast subscriptions on %(site)s') % \
145 dict(username=user.username, site=self.site)
147 def link(self, user):
148 return reverse('shared-subscriptions', args=[user.username])
150 def items(self, user):
151 NUM_ITEMS = 20
152 history = user.get_global_subscription_history(public=True)
153 history = skip_pairs(history)
154 history = list(history)[-NUM_ITEMS:]
155 history = HistoryEntry.fetch_data(user, history)
156 history = filter(lambda e:e.podcast, history)
157 return history
159 def author_name(self, user):
160 return user.username
162 def author_link(self, user):
163 return reverse('shared-subscriptions', args=[user.username])
165 # entry-specific data below
167 description_template = "subscription-feed-description.html"
169 def item_title(self, entry):
170 if entry.action == 'subscribe':
171 s = _('%(username)s subscribed to %(podcast)s (%(site)s)')
172 else:
173 s = _('%(username)s unsubscribed from %(podcast)s (%(site)s)')
175 return s % dict(username=self.username,
176 podcast=entry.podcast.display_title,
177 site=self.site)
179 def item_link(self, item):
180 return utils.get_podcast_link_target(item.podcast)
182 def item_pubdate(self, item):
183 return item.timestamp