[Migration] use migrated users
[mygpo.git] / mygpo / web / views / subscriptions.py
blob2c0e488d88f238db44cafb65d6a518003fdc90d1
1 from datetime import datetime
3 from django.core.urlresolvers import reverse
4 from django.contrib.auth.decorators import login_required
5 from django.contrib.sites.models import RequestSite
6 from django.shortcuts import render
7 from django.contrib.syndication.views import Feed
8 from django.utils.translation import ugettext as _
9 from django.http import HttpResponse, Http404
10 from django.views.decorators.vary import vary_on_cookie
11 from django.views.decorators.cache import cache_control
13 from mygpo.podcasts.models import Podcast
14 from mygpo.utils import parse_bool, unzip, skip_pairs
15 from mygpo.decorators import requires_token
16 from mygpo.api import simple
17 from mygpo.users.models import HistoryEntry, User
18 from mygpo.users.subscriptions import get_subscribed_podcasts
19 from mygpo.web.utils import symbian_opml_changes, get_podcast_link_target
20 from mygpo.db.couchdb.podcast_state import subscriptions_by_user
23 @vary_on_cookie
24 @cache_control(private=True)
25 @login_required
26 def show_list(request):
27 current_site = RequestSite(request)
28 subscriptionlist = create_subscriptionlist(request)
29 return render(request, 'subscriptions.html', {
30 'subscriptionlist': subscriptionlist,
31 'url': current_site
35 @vary_on_cookie
36 @cache_control(private=True)
37 @login_required
38 def download_all(request):
39 podcasts = get_subscribed_podcasts(request.user)
40 response = simple.format_podcast_list(podcasts, 'opml', request.user.username)
41 response['Content-Disposition'] = 'attachment; filename=all-subscriptions.opml'
42 return response
45 @requires_token(token_name='subscriptions_token', denied_template='user_subscriptions_denied.html')
46 def for_user(request, username):
47 user = User.get_user(username)
48 if not user:
49 raise Http404
51 subscriptions = user.get_subscribed_podcasts(public=True)
52 token = user.profile.get_token('subscriptions_token')
54 return render(request, 'user_subscriptions.html', {
55 'subscriptions': subscriptions,
56 'other_user': user,
57 'token': token,
60 @requires_token(token_name='subscriptions_token')
61 def for_user_opml(request, username):
62 user = User.get_user(username)
63 if not user:
64 raise Http404
66 subscriptions = user.get_subscribed_podcasts(public=True)
68 if parse_bool(request.GET.get('symbian', False)):
69 subscriptions = map(symbian_opml_changes, subscriptions)
71 response = render(request, 'user_subscriptions.opml', {
72 'subscriptions': subscriptions,
73 'other_user': user
75 response['Content-Disposition'] = 'attachment; filename=%s-subscriptions.opml' % username
76 return response
79 def create_subscriptionlist(request):
80 user = request.user
81 subscriptions = subscriptions_by_user(user)
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 = Podcast.objects.filter(id__in=podcast_ids)
93 podcasts = {podcast.id.hex: podcast for podcast in podcasts}
94 devices = {client.id.hex: client for client in user.client_set.all()}
96 subscription_list = {}
97 for public, podcast_id, device_id in subscriptions:
98 device = devices.get(device_id)
99 if not podcast_id in subscription_list:
100 podcast = podcasts.get(podcast_id, None)
101 if podcast is None:
102 continue
104 subscription_list[podcast_id] = {
105 'podcast': podcasts[podcast_id],
106 'devices': [device] if device else [],
107 'episodes': podcast.episode_count,
109 else:
110 if device:
111 subscription_list[podcast_id]['devices'].append(device)
113 subscriptions = subscription_list.values()
114 sort_key = lambda s: s['podcast'].latest_episode_timestamp or datetime.utcnow()
115 subscriptions = sorted(subscriptions, key=sort_key, reverse=True)
116 return subscriptions
119 @requires_token(token_name='subscriptions_token')
120 def subscriptions_feed(request, username):
121 # Create to feed manually so we can wrap the token-authentication around it
122 f = SubscriptionsFeed(username)
123 obj = f.get_object(request, username)
124 feedgen = f.get_feed(obj, request)
125 response = HttpResponse(content_type=feedgen.mime_type)
126 feedgen.write(response, 'utf-8')
127 return response
130 class SubscriptionsFeed(Feed):
131 """ A feed showing subscription changes for a certain user """
133 def __init__(self, username):
134 self.username = username
136 def get_object(self, request, username):
137 self.site = RequestSite(request)
138 return User.get_user(username)
140 def title(self, user):
141 return _('%(username)s\'s Podcast Subscriptions on %(site)s') % \
142 dict(username=user.username, site=self.site)
144 def description(self, user):
145 return _('Recent changes to %(username)s\'s podcast subscriptions on %(site)s') % \
146 dict(username=user.username, site=self.site)
148 def link(self, user):
149 return reverse('shared-subscriptions', args=[user.username])
151 def items(self, user):
152 NUM_ITEMS = 20
153 history = user.get_global_subscription_history(public=True)
154 history = skip_pairs(history)
155 history = list(history)[-NUM_ITEMS:]
156 history = HistoryEntry.fetch_data(user, history)
157 history = filter(lambda e:e.podcast, history)
158 return history
160 def author_name(self, user):
161 return user.username
163 def author_link(self, user):
164 return reverse('shared-subscriptions', args=[user.username])
166 # entry-specific data below
168 description_template = "subscription-feed-description.html"
170 def item_title(self, entry):
171 if entry.action == 'subscribe':
172 s = _('%(username)s subscribed to %(podcast)s (%(site)s)')
173 else:
174 s = _('%(username)s unsubscribed from %(podcast)s (%(site)s)')
176 return s % dict(username=self.username,
177 podcast=entry.podcast.display_title,
178 site=self.site)
180 def item_link(self, item):
181 return get_podcast_link_target(item.podcast)
183 def item_pubdate(self, item):
184 return item.timestamp