update suggestions when subscriptions change
[mygpo.git] / mygpo / web / views / __init__.py
blobb13a3424520f3653148c7939bb7399e45d549b8c
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 import sys
19 from collections import defaultdict
20 from datetime import datetime, timedelta
22 try:
23 import gevent
24 except ImportError:
25 gevent = None
27 from django.core.urlresolvers import reverse
28 from django.http import HttpResponseRedirect
29 from django.contrib import messages
30 from django.utils.translation import ugettext as _
31 from django.contrib.auth.decorators import login_required
32 from django.shortcuts import render
33 from django.contrib.sites.models import RequestSite
34 from django.views.generic.base import View
35 from django.views.decorators.vary import vary_on_cookie
36 from django.views.decorators.cache import never_cache, cache_control
38 from mygpo.decorators import repeat_on_conflict
39 from mygpo.core.podcasts import PodcastSet
40 from mygpo.directory.toplist import PodcastToplist
41 from mygpo.users.models import Suggestions, History, HistoryEntry, \
42 DeviceDoesNotExist
43 from mygpo.users.tasks import update_suggestions
44 from mygpo.web.utils import process_lang_params
45 from mygpo.utils import parse_range
46 from mygpo.web.views.podcast import slug_id_decorator
47 from mygpo.users.settings import FLATTR_AUTO, FLATTR_TOKEN
48 from mygpo.db.couchdb.episode import favorite_episodes_for_user
49 from mygpo.db.couchdb.podcast import podcast_by_id, random_podcasts
50 from mygpo.db.couchdb.user import suggestions_for_user
51 from mygpo.db.couchdb.directory import tags_for_user
52 from mygpo.db.couchdb.podcastlist import podcastlists_for_user
55 @vary_on_cookie
56 @cache_control(private=True)
57 def home(request):
58 if request.user.is_authenticated():
59 return dashboard(request)
60 else:
61 return welcome(request)
64 @vary_on_cookie
65 @cache_control(private=True)
66 def welcome(request):
67 current_site = RequestSite(request)
69 lang = process_lang_params(request)
71 toplist = PodcastToplist(lang)
73 return render(request, 'home.html', {
74 'url': current_site,
75 'toplist': toplist,
79 @vary_on_cookie
80 @cache_control(private=True)
81 @login_required
82 def dashboard(request, episode_count=10):
84 subscribed_podcasts = list(request.user.get_subscribed_podcasts())
85 site = RequestSite(request)
87 checklist = []
89 if request.user.devices:
90 checklist.append('devices')
92 if subscribed_podcasts:
93 checklist.append('subscriptions')
95 if favorite_episodes_for_user(request.user):
96 checklist.append('favorites')
98 if not request.user.get_token('subscriptions_token'):
99 checklist.append('share')
101 if not request.user.get_token('favorite_feeds_token'):
102 checklist.append('share-favorites')
104 if not request.user.get_token('userpage_token'):
105 checklist.append('userpage')
107 if tags_for_user(request.user):
108 checklist.append('tags')
110 # TODO add podcastlist_count_for_user
111 if podcastlists_for_user(request.user._id):
112 checklist.append('lists')
114 if request.user.published_objects:
115 checklist.append('publish')
117 if request.user.get_wksetting(FLATTR_TOKEN):
118 checklist.append('flattr')
120 if request.user.get_wksetting(FLATTR_AUTO):
121 checklist.append('auto-flattr')
123 tomorrow = datetime.today() + timedelta(days=1)
125 podcasts = PodcastSet(subscribed_podcasts)
127 newest_episodes = podcasts.get_newest_episodes(tomorrow, episode_count)
129 def get_random_podcasts():
130 random_podcast = next(random_podcasts(), None)
131 if random_podcast:
132 yield random_podcast.get_podcast()
134 # we only show the "install reader" link in firefox, because we don't know
135 # yet how/if this works in other browsers.
136 # hints appreciated at https://bugs.gpodder.org/show_bug.cgi?id=58
137 show_install_reader = \
138 'firefox' in request.META.get('HTTP_USER_AGENT', '').lower()
140 return render(request, 'dashboard.html', {
141 'user': request.user,
142 'subscribed_podcasts': subscribed_podcasts,
143 'newest_episodes': list(newest_episodes),
144 'random_podcasts': get_random_podcasts(),
145 'checklist': checklist,
146 'site': site,
147 'show_install_reader': show_install_reader,
151 @vary_on_cookie
152 @cache_control(private=True)
153 @login_required
154 def history(request, count=15, uid=None):
156 page = parse_range(request.GET.get('page', None), 0, sys.maxint, 0)
158 if uid:
159 try:
160 device = request.user.get_device_by_uid(uid, only_active=False)
161 except DeviceDoesNotExist as e:
162 messages.error(request, str(e))
164 else:
165 device = None
167 history_obj = History(request.user, device)
169 start = page*count
170 end = start+count
171 entries = history_obj[start:end]
172 HistoryEntry.fetch_data(request.user, entries)
174 return render(request, 'history.html', {
175 'history': entries,
176 'device': device,
177 'page': page,
181 @never_cache
182 @login_required
183 @slug_id_decorator
184 def blacklist(request, blacklisted_podcast):
185 user = request.user
187 suggestion = suggestions_for_user(user)
189 @repeat_on_conflict(['suggestion'])
190 def _update(suggestion, podcast_id):
191 suggestion.blacklist.append(podcast_id)
192 suggestion.save()
194 _update(suggestion=suggestion, podcast_id=blacklisted_podcast.get_id())
195 update_suggestions.delay(user)
197 return HttpResponseRedirect(reverse('suggestions'))
200 @never_cache
201 @login_required
202 def rate_suggestions(request):
203 rating_val = int(request.GET.get('rate', None))
205 suggestion = suggestions_for_user(request.user)
206 suggestion.rate(rating_val, request.user._id)
207 suggestion.save()
209 messages.success(request, _('Thanks for rating!'))
211 return HttpResponseRedirect(reverse('suggestions'))
214 @vary_on_cookie
215 @cache_control(private=True)
216 @login_required
217 def suggestions(request):
218 suggestion_obj = suggestions_for_user(request.user)
219 suggestions = suggestion_obj.get_podcasts()
220 current_site = RequestSite(request)
221 return render(request, 'suggestions.html', {
222 'entries': suggestions,
223 'url': current_site
227 @vary_on_cookie
228 @cache_control(private=True)
229 @login_required
230 def mytags(request):
231 tags_podcast = {}
232 tags_tag = defaultdict(list)
234 for podcast_id, taglist in tags_for_user(request.user).items():
235 podcast = podcast_by_id(podcast_id)
236 tags_podcast[podcast] = taglist
238 for tag in taglist:
239 tags_tag[ tag ].append(podcast)
241 return render(request, 'mytags.html', {
242 'tags_podcast': tags_podcast,
243 'tags_tag': dict(tags_tag.items()),
248 class GeventView(View):
249 """ View that provides parts of the context via gevent coroutines """
251 def get_context(self, context_funs):
252 """ returns a dictionary that can be used for a template context
254 context_funs is a context-key => Greenlet object mapping """
256 if gevent:
257 jobs = {}
258 for key, fun in context_funs.items():
259 jobs[key] = gevent.spawn(fun)
261 gevent.joinall(jobs.values())
263 for key, gev in jobs.items():
264 context_funs[key] = gev.get()
266 else:
267 for key, fun in context_funs.items():
268 context_funs[key] = fun()
270 return context_funs