1 from datetime
import datetime
3 from django
.urls
import reverse
4 from django
.contrib
.auth
.decorators
import login_required
5 from django
.contrib
.sites
.requests
import RequestSite
6 from django
.shortcuts
import render
, get_object_or_404
7 from django
.http
import HttpResponse
8 from django
.views
.decorators
.vary
import vary_on_cookie
9 from django
.views
.decorators
.cache
import cache_control
10 from django
.utils
.translation
import gettext
as _
11 from django
.contrib
.syndication
.views
import Feed
12 from django
.contrib
.auth
import get_user_model
14 from mygpo
.podcasts
.models
import Podcast
15 from mygpo
.subscriptions
.models
import Subscription
16 from mygpo
.users
.settings
import PUBLIC_SUB_PODCAST
17 from mygpo
.api
import simple
18 from mygpo
.subscriptions
import get_subscribed_podcasts
19 from mygpo
.decorators
import requires_token
20 from mygpo
.users
.models
import HistoryEntry
21 from mygpo
.subscriptions
import (
22 get_subscribed_podcasts
,
23 get_subscription_change_history
,
24 get_subscription_history
,
26 from mygpo
.web
.utils
import get_podcast_link_target
27 from mygpo
.utils
import parse_bool
28 from mygpo
.decorators
import requires_token
29 from mygpo
.web
.utils
import symbian_opml_changes
33 @cache_control(private
=True)
35 def show_list(request
):
36 current_site
= RequestSite(request
)
37 subscriptionlist
= create_subscriptionlist(request
)
42 "subscriptionlist": subscriptionlist
,
44 "podcast_ad": Podcast
.objects
.get_advertised_podcast(),
50 @cache_control(private
=True)
52 def download_all(request
):
53 podcasts
= get_subscribed_podcasts(request
.user
)
54 response
= simple
.format_podcast_list(podcasts
, "opml", request
.user
.username
)
55 response
["Content-Disposition"] = "attachment; filename=all-subscriptions.opml"
59 def create_subscriptionlist(request
):
62 # get all non-deleted subscriptions
64 Subscription
.objects
.filter(user
=user
)
65 .exclude(deleted
=True)
66 .select_related("podcast", "client")
67 .prefetch_related("podcast__slugs")
70 # grou clients by subscribed podcasts
71 subscription_list
= {}
72 for subscription
in subscriptions
:
73 podcast
= subscription
.podcast
75 if not podcast
in subscription_list
:
76 subscription_list
[podcast
] = {
79 "episodes": podcast
.episode_count
,
82 subscription_list
[podcast
]["devices"].append(subscription
.client
)
84 # sort most recently updated podcast first
85 subscriptions
= subscription_list
.values()
86 now
= datetime
.utcnow()
87 sort_key
= lambda s
: s
["podcast"].latest_episode_timestamp
or now
88 subscriptions
= sorted(subscriptions
, key
=sort_key
, reverse
=True)
92 @requires_token(token_name
="subscriptions_token")
93 def subscriptions_feed(request
, username
):
94 # Create to feed manually so we can wrap the token-authentication around it
95 f
= SubscriptionsFeed(username
)
96 obj
= f
.get_object(request
, username
)
97 feedgen
= f
.get_feed(obj
, request
)
98 response
= HttpResponse(content_type
=feedgen
.content_type
)
99 feedgen
.write(response
, "utf-8")
103 class SubscriptionsFeed(Feed
):
104 """A feed showing subscription changes for a certain user"""
108 def __init__(self
, username
):
109 self
.username
= username
111 def get_object(self
, request
, username
):
112 self
.site
= RequestSite(request
)
113 User
= get_user_model()
114 user
= get_object_or_404(User
, username
=username
)
117 def title(self
, user
):
118 return _("%(username)s's Podcast Subscriptions on %(site)s") % dict(
119 username
=user
.username
, site
=self
.site
122 def description(self
, user
):
124 "Recent changes to %(username)s's podcast subscriptions on %(site)s"
125 ) % dict(username
=user
.username
, site
=self
.site
)
127 def link(self
, user
):
128 return reverse("shared-subscriptions", args
=[user
.username
])
130 def items(self
, user
):
131 history
= get_subscription_history(user
, public_only
=True)
132 history
= get_subscription_change_history(history
)
133 history
= list(history
)[-self
.NUM_ITEMS
:]
136 def author_name(self
, user
):
139 def author_link(self
, user
):
140 return reverse("shared-subscriptions", args
=[user
.username
])
142 # entry-specific data below
144 description_template
= "subscription-feed-description.html"
146 def item_title(self
, entry
):
147 if entry
.action
== "subscribe":
148 s
= _("%(username)s subscribed to %(podcast)s (%(site)s)")
150 s
= _("%(username)s unsubscribed from %(podcast)s (%(site)s)")
153 username
=self
.username
, podcast
=entry
.podcast
.display_title
, site
=self
.site
156 def item_link(self
, item
):
157 return get_podcast_link_target(item
.podcast
)
159 def item_pubdate(self
, item
):
160 return item
.timestamp
164 token_name
="subscriptions_token", denied_template
="user_subscriptions_denied.html"
166 def for_user(request
, username
):
167 User
= get_user_model()
168 user
= get_object_or_404(User
, username
=username
)
169 subscriptions
= get_subscribed_podcasts(user
, only_public
=True)
170 token
= user
.profile
.get_token("subscriptions_token")
174 "user_subscriptions.html",
175 {"subscriptions": subscriptions
, "other_user": user
, "token": token
},
179 @requires_token(token_name
="subscriptions_token")
180 def for_user_opml(request
, username
):
181 User
= get_user_model()
182 user
= get_object_or_404(User
, username
=username
)
183 subscriptions
= get_subscribed_podcasts(user
, only_public
=True)
185 if parse_bool(request
.GET
.get("symbian", False)):
186 subscriptions
= map(symbian_opml_changes
, [p
.podcast
for p
in subscriptions
])
190 "user_subscriptions.opml",
191 {"subscriptions": subscriptions
, "other_user": user
},
193 response
["Content-Disposition"] = (
194 "attachment; filename=%s-subscriptions.opml" % username