1 from functools
import wraps
2 from datetime
import datetime
4 from django
.core
.urlresolvers
import reverse
5 from django
.http
import Http404
, HttpResponseRedirect
, HttpResponseForbidden
6 from django
.shortcuts
import render
7 from django
.utils
.text
import slugify
8 from django
.contrib
.sites
.models
import RequestSite
9 from django
.contrib
.auth
.decorators
import login_required
10 from django
.contrib
.auth
import get_user_model
11 from django
.contrib
import messages
12 from django
.utils
.translation
import ugettext
as _
13 from django
.views
.decorators
.vary
import vary_on_cookie
14 from django
.views
.decorators
.cache
import cache_control
15 from django
.views
.generic
.base
import View
16 from django
.utils
.decorators
import method_decorator
18 from mygpo
.podcasts
.models
import Podcast
, PodcastGroup
19 from mygpo
.core
.proxy
import proxy_object
20 from mygpo
.api
.simple
import format_podcast_list
21 from mygpo
.share
.models
import PodcastList
22 from mygpo
.directory
.views
import search
as directory_search
23 from mygpo
.decorators
import repeat_on_conflict
24 from mygpo
.flattr
import Flattr
25 from mygpo
.userfeeds
.feeds
import FavoriteFeed
26 from mygpo
.db
.couchdb
.podcastlist
import podcastlist_for_user_slug
, \
27 podcastlists_for_user
, add_podcast_to_podcastlist
, \
28 remove_podcast_from_podcastlist
, delete_podcastlist
, \
30 from mygpo
.data
.feeddownloader
import PodcastUpdater
33 logger
= logging
.getLogger(__name__
)
36 def list_decorator(must_own
=False):
39 def _decorator(request
, username
, listname
, *args
, **kwargs
):
41 User
= get_user_model()
42 user
= User
.objects
.get(username
=username
)
46 if must_own
and request
.user
!= user
:
47 return HttpResponseForbidden()
49 plist
= podcastlist_for_user_slug(user
.profile
.uuid
.hex, listname
)
54 return f(request
, plist
, user
, *args
, **kwargs
)
62 def search(request
, username
, listname
):
63 return directory_search(request
, 'list_search.html',
64 {'listname': listname
})
68 def lists_own(request
):
70 lists
= podcastlists_for_user(request
.user
._id
)
72 return render(request
, 'lists.html', {
77 def lists_user(request
, username
):
79 User
= get_user_model()
80 user
= User
.objects
.get(username
=username
)
84 lists
= podcastlists_for_user(user
._id
)
86 return render(request
, 'lists_user.html', {
92 @list_decorator(must_own
=False)
93 def list_show(request
, plist
, owner
):
95 is_own
= owner
== request
.user
96 site
= RequestSite(request
)
98 plist
= proxy_object(plist
)
100 podcasts
= get_podcasts_groups(plist
.podcasts
)
101 plist
.podcasts
= podcasts
103 max_subscribers
= max([p
.subscriber_count() for p
in podcasts
] + [0])
105 thing
= plist
.get_flattr_thing(site
.domain
, owner
.username
)
106 flattr
= Flattr(owner
, site
.domain
, request
.is_secure())
107 flattr_autosubmit
= flattr
.get_autosubmit_url(thing
)
109 return render(request
, 'list.html', {
110 'podcastlist': plist
,
111 'max_subscribers': max_subscribers
,
113 'flattr_autosubmit': flattr_autosubmit
,
114 'domain': site
.domain
,
119 @list_decorator(must_own
=False)
120 def list_opml(request
, plist
, owner
):
121 podcasts
= get_podcasts_groups(plist
.podcasts
)
122 return format_podcast_list(podcasts
, 'opml', plist
.title
)
126 def create_list(request
):
127 title
= request
.POST
.get('title', None)
130 messages
.error(request
, _('You have to specify a title.'))
131 return HttpResponseRedirect(reverse('lists-overview'))
133 slug
= slugify(title
)
136 messages
.error(request
, _('"{title}" is not a valid title').format(
138 return HttpResponseRedirect(reverse('lists-overview'))
140 plist
= podcastlist_for_user_slug(request
.user
._id
, slug
)
143 create_podcast_list(title
, slug
, request
.user
._id
, datetime
.utcnow())
145 list_url
= reverse('list-show', args
=[request
.user
.username
, slug
])
146 return HttpResponseRedirect(list_url
)
150 @list_decorator(must_own
=True)
151 def add_podcast(request
, plist
, owner
, podcast_id
):
152 add_podcast_to_podcastlist(plist
, podcast_id
)
153 list_url
= reverse('list-show', args
=[owner
.username
, plist
.slug
])
154 return HttpResponseRedirect(list_url
)
158 @list_decorator(must_own
=True)
159 def remove_podcast(request
, plist
, owner
, podcast_id
):
160 remove_podcast_from_podcastlist(plist
, podcast_id
)
161 list_url
= reverse('list-show', args
=[owner
.username
, plist
.slug
])
162 return HttpResponseRedirect(list_url
)
166 @list_decorator(must_own
=True)
167 def delete_list(request
, plist
, owner
):
168 delete_podcastlist(plist
)
169 return HttpResponseRedirect(reverse('lists-overview'))
173 @list_decorator(must_own
=False)
174 def rate_list(request
, plist
, owner
):
175 rating_val
= int(request
.GET
.get('rate', None))
177 @repeat_on_conflict(['plist'])
178 def _rate(plist
, rating_val
, user
):
179 plist
.rate(rating_val
, user
._id
)
182 _rate(plist
, rating_val
, request
.user
)
184 messages
.success(request
, _('Thanks for rating!'))
186 list_url
= reverse('list-show', args
=[owner
.username
, plist
.slug
])
187 return HttpResponseRedirect(list_url
)
190 class FavoritesPublic(View
):
194 @method_decorator(vary_on_cookie
)
195 @method_decorator(cache_control(private
=True))
196 @method_decorator(login_required
)
197 def post(self
, request
):
200 request
.user
.favorite_feeds_token
= ''
204 request
.user
.create_new_token('favorite_feeds_token', 8)
207 token
= request
.user
.favorite_feeds_token
209 return HttpResponseRedirect(reverse('share-favorites'))
213 class ShareFavorites(View
):
215 @method_decorator(vary_on_cookie
)
216 @method_decorator(cache_control(private
=True))
217 @method_decorator(login_required
)
218 def get(self
, request
):
221 favfeed
= FavoriteFeed(user
)
222 site
= RequestSite(request
)
223 feed_url
= favfeed
.get_public_url(site
.domain
)
225 podcast
= Podcast
.objects
.filter(urls__url
=feed_url
).first()
227 token
= request
.user
.favorite_feeds_token
229 return render(request
, 'share/favorites.html', {
236 class PublicSubscriptions(View
):
240 @method_decorator(vary_on_cookie
)
241 @method_decorator(cache_control(private
=True))
242 @method_decorator(login_required
)
243 def post(self
, request
):
245 self
.update(request
.user
)
247 return HttpResponseRedirect(reverse('share'))
250 @repeat_on_conflict(['user'])
251 def update(self
, user
):
253 user
.subscriptions_token
= ''
255 user
.create_new_token('subscriptions_token')
260 class FavoritesFeedCreateEntry(View
):
261 """ Creates a Podcast object for the user's favorites feed """
263 @method_decorator(vary_on_cookie
)
264 @method_decorator(cache_control(private
=True))
265 @method_decorator(login_required
)
266 def post(self
, request
):
269 feed
= FavoriteFeed(user
)
270 site
= RequestSite(request
)
271 feed_url
= feed
.get_public_url(site
.domain
)
273 podcast
= Podcast
.objects
.get_or_create_for_url(feed_url
)
275 if not podcast
.get_id() in user
.published_objects
:
276 user
.published_objects
.append(podcast
.get_id())
279 updater
= PodcastUpdater()
280 updater
.update(feed_url
)
282 return HttpResponseRedirect(reverse('share-favorites'))
286 def overview(request
):
288 site
= RequestSite(request
)
290 subscriptions_token
= user
.profile
.get_token('subscriptions_token')
291 userpage_token
= user
.profile
.get_token('userpage_token')
292 favfeed_token
= user
.profile
.get_token('favorite_feeds_token')
294 favfeed
= FavoriteFeed(user
)
295 favfeed_url
= favfeed
.get_public_url(site
.domain
)
296 favfeed_podcast
= Podcast
.objects
.filter(urls__url
=favfeed_url
).first()
298 return render(request
, 'share/overview.html', {
300 'subscriptions_token': subscriptions_token
,
301 'userpage_token': userpage_token
,
302 'favfeed_token': favfeed_token
,
303 'favfeed_podcast': favfeed_podcast
,
308 def set_token_public(request
, token_name
, public
):
311 @repeat_on_conflict(['user'])
313 setattr(user
, token_name
, '')
317 @repeat_on_conflict(['user'])
319 user
.create_new_token(token_name
)
322 _update(user
=request
.user
)
324 return HttpResponseRedirect(reverse('share'))
327 def get_podcasts_groups(ids
):
328 # this could be optimized by using a View
329 logger
.info('Getting podcasts and groups for IDs %r', ids
)
330 groups
= PodcastGroup
.objects
.filter(id__in
=ids
)
331 podcasts
= Podcast
.objects
.filter(id__in
=ids
)
332 # TODO: bring in right order, according to IDs
333 return list(groups
) + list(podcasts
)