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/>.
19 from collections
import defaultdict
20 from datetime
import datetime
, timedelta
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
, \
43 from mygpo
.web
.utils
import process_lang_params
44 from mygpo
.utils
import parse_range
45 from mygpo
.web
.views
.podcast
import slug_id_decorator
46 from mygpo
.users
.settings
import FLATTR_AUTO
, FLATTR_TOKEN
47 from mygpo
.db
.couchdb
.episode
import favorite_episodes_for_user
48 from mygpo
.db
.couchdb
.podcast
import podcast_by_id
, random_podcasts
49 from mygpo
.db
.couchdb
.user
import suggestions_for_user
50 from mygpo
.db
.couchdb
.directory
import tags_for_user
51 from mygpo
.db
.couchdb
.podcastlist
import podcastlists_for_user
55 @cache_control(private
=True)
57 if request
.user
.is_authenticated():
58 return dashboard(request
)
60 return welcome(request
)
64 @cache_control(private
=True)
66 current_site
= RequestSite(request
)
68 lang
= process_lang_params(request
)
70 toplist
= PodcastToplist(lang
)
72 return render(request
, 'home.html', {
79 @cache_control(private
=True)
81 def dashboard(request
, episode_count
=10):
83 subscribed_podcasts
= list(request
.user
.get_subscribed_podcasts())
84 site
= RequestSite(request
)
88 if request
.user
.devices
:
89 checklist
.append('devices')
91 if subscribed_podcasts
:
92 checklist
.append('subscriptions')
94 if favorite_episodes_for_user(request
.user
):
95 checklist
.append('favorites')
97 if not request
.user
.get_token('subscriptions_token'):
98 checklist
.append('share')
100 if not request
.user
.get_token('favorite_feeds_token'):
101 checklist
.append('share-favorites')
103 if not request
.user
.get_token('userpage_token'):
104 checklist
.append('userpage')
106 if tags_for_user(request
.user
):
107 checklist
.append('tags')
109 # TODO add podcastlist_count_for_user
110 if podcastlists_for_user(request
.user
._id
):
111 checklist
.append('lists')
113 if request
.user
.published_objects
:
114 checklist
.append('publish')
116 if request
.user
.get_wksetting(FLATTR_TOKEN
):
117 checklist
.append('flattr')
119 if request
.user
.get_wksetting(FLATTR_AUTO
):
120 checklist
.append('auto-flattr')
122 tomorrow
= datetime
.today() + timedelta(days
=1)
124 podcasts
= PodcastSet(subscribed_podcasts
)
126 newest_episodes
= podcasts
.get_newest_episodes(tomorrow
, episode_count
)
128 def get_random_podcasts():
129 random_podcast
= next(random_podcasts(), None)
131 yield random_podcast
.get_podcast()
133 # we only show the "install reader" link in firefox, because we don't know
134 # yet how/if this works in other browsers.
135 # hints appreciated at https://bugs.gpodder.org/show_bug.cgi?id=58
136 show_install_reader
= \
137 'firefox' in request
.META
.get('HTTP_USER_AGENT', '').lower()
139 return render(request
, 'dashboard.html', {
140 'user': request
.user
,
141 'subscribed_podcasts': subscribed_podcasts
,
142 'newest_episodes': list(newest_episodes
),
143 'random_podcasts': get_random_podcasts(),
144 'checklist': checklist
,
146 'show_install_reader': show_install_reader
,
151 @cache_control(private
=True)
153 def history(request
, count
=15, uid
=None):
155 page
= parse_range(request
.GET
.get('page', None), 0, sys
.maxint
, 0)
159 device
= request
.user
.get_device_by_uid(uid
, only_active
=False)
160 except DeviceDoesNotExist
as e
:
161 messages
.error(request
, str(e
))
166 history_obj
= History(request
.user
, device
)
170 entries
= history_obj
[start
:end
]
171 HistoryEntry
.fetch_data(request
.user
, entries
)
173 return render(request
, 'history.html', {
183 def blacklist(request
, blacklisted_podcast
):
184 suggestion
= suggestions_for_user(request
.user
)
186 @repeat_on_conflict(['suggestion'])
187 def _update(suggestion
, podcast_id
):
188 suggestion
.blacklist
.append(podcast_id
)
191 @repeat_on_conflict(['user'])
192 def _not_uptodate(user
):
193 user
.suggestions_up_to_date
= False
196 _update(suggestion
=suggestion
, podcast_id
=blacklisted_podcast
.get_id())
197 _not_uptodate(user
=request
.user
)
199 return HttpResponseRedirect(reverse('suggestions'))
204 def rate_suggestions(request
):
205 rating_val
= int(request
.GET
.get('rate', None))
207 suggestion
= suggestions_for_user(request
.user
)
208 suggestion
.rate(rating_val
, request
.user
._id
)
211 messages
.success(request
, _('Thanks for rating!'))
213 return HttpResponseRedirect(reverse('suggestions'))
217 @cache_control(private
=True)
219 def suggestions(request
):
220 suggestion_obj
= suggestions_for_user(request
.user
)
221 suggestions
= suggestion_obj
.get_podcasts()
222 current_site
= RequestSite(request
)
223 return render(request
, 'suggestions.html', {
224 'entries': suggestions
,
230 @cache_control(private
=True)
234 tags_tag
= defaultdict(list)
236 for podcast_id
, taglist
in tags_for_user(request
.user
).items():
237 podcast
= podcast_by_id(podcast_id
)
238 tags_podcast
[podcast
] = taglist
241 tags_tag
[ tag
].append(podcast
)
243 return render(request
, 'mytags.html', {
244 'tags_podcast': tags_podcast
,
245 'tags_tag': dict(tags_tag
.items()),
250 class GeventView(View
):
251 """ View that provides parts of the context via gevent coroutines """
253 def get_context(self
, context_funs
):
254 """ returns a dictionary that can be used for a template context
256 context_funs is a context-key => Greenlet object mapping """
260 for key
, fun
in context_funs
.items():
261 jobs
[key
] = gevent
.spawn(fun
)
263 gevent
.joinall(jobs
.values())
265 for key
, gev
in jobs
.items():
266 context_funs
[key
] = gev
.get()
269 for key
, fun
in context_funs
.items():
270 context_funs
[key
] = fun()