Merge branch 'master' of dgpo:~alex/mygpo-src
[mygpo.git] / mygpo / web / views.py
blob8697ac698cfc14586ee0915e4424c0637e306beb
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 from django.shortcuts import render_to_response
19 from django.http import HttpResponseRedirect, HttpResponse, HttpResponseBadRequest, HttpResponseNotAllowed, Http404
20 from django.contrib.auth import authenticate, login, logout
21 from django.template import RequestContext
22 from mygpo.api.models import Podcast, UserProfile, Episode, Device, EpisodeAction, SubscriptionAction, ToplistEntry, Subscription, SuggestionEntry, Rating, SyncGroup, SUBSCRIBE_ACTION, UNSUBSCRIBE_ACTION, SubscriptionMeta
23 from mygpo.web.forms import UserAccountForm, DeviceForm, SyncForm, PrivacyForm
24 from mygpo.api.opml import Exporter
25 from django.utils.translation import ugettext as _
26 from mygpo.api.basic_auth import require_valid_user
27 from django.contrib.auth.decorators import login_required
28 from django.db import IntegrityError
29 from datetime import datetime
30 from django.contrib.sites.models import Site
31 from django.conf import settings
32 from sets import Set
33 from mygpo.api.sanitizing import sanitize_url
34 import re
36 def home(request):
37 current_site = Site.objects.get_current()
38 if request.user.is_authenticated():
39 subscriptionlist = create_subscriptionlist(request)
41 return render_to_response('home-user.html', {
42 'subscriptionlist': subscriptionlist,
43 'url': current_site
44 }, context_instance=RequestContext(request))
46 else:
47 podcasts = Podcast.objects.count()
48 return render_to_response('home.html', {
49 'podcast_count': podcasts,
50 'url': current_site
53 def create_subscriptionlist(request):
54 #sync all devices first
55 for d in Device.objects.filter(user=request.user):
56 d.sync()
58 subscriptions = Subscription.objects.filter(user=request.user)
60 l = {}
61 for s in subscriptions:
62 if s.podcast in l:
63 l[s.podcast]['devices'].append(s.device)
64 else:
65 e = Episode.objects.filter(podcast=s.podcast).order_by('-timestamp')
66 episode = e[0] if e.count() > 0 else None
67 devices = [s.device]
68 l[s.podcast] = {'podcast': s.podcast, 'episode': episode, 'devices': devices}
70 return l.values()
72 def podcast(request, pid):
73 try:
74 podcast = Podcast.objects.get(pk=pid)
75 except Podcast.DoesNotExist:
76 raise Http404('There is no podcast with id %s' % pid)
78 if request.user.is_authenticated():
79 devices = Device.objects.filter(user=request.user)
80 history = SubscriptionAction.objects.filter(podcast=podcast,device__in=devices).order_by('-timestamp')
81 subscribed_devices = [s.device for s in Subscription.objects.filter(podcast=podcast,user=request.user)]
82 subscribe_targets = podcast.subscribe_targets(request.user)
83 episodes = episode_list(podcast, request.user)
84 unsubscribe = '/podcast/' + pid + '/unsubscribe'
85 success = False
87 qs = Subscription.objects.filter(podcast=podcast, user=request.user)
88 if qs.count()>0:
89 # subscription meta is valid for all subscriptions, so we get one - doesn't matter which
90 subscription = qs[0]
91 subscriptionmeta = subscription.get_meta()
92 if request.method == 'POST':
93 privacy_form = PrivacyForm(request.POST)
94 if privacy_form.is_valid():
95 subscriptionmeta.public = privacy_form.cleaned_data['public']
96 try:
97 subscriptionmeta.save()
98 success = True
99 except IntegrityError, ie:
100 error_message = _('You can\'t use the same UID for two devices.')
101 else:
102 privacy_form = PrivacyForm({
103 'public': subscriptionmeta.public
106 else:
107 privacy_form = None
109 return render_to_response('podcast.html', {
110 'history': history,
111 'podcast': podcast,
112 'privacy_form': privacy_form,
113 'devices': subscribed_devices,
114 'can_subscribe': len(subscribe_targets) > 0,
115 'episodes': episodes,
116 'unsubscribe': unsubscribe,
117 'success': success
118 }, context_instance=RequestContext(request))
119 else:
120 current_site = Site.objects.get_current()
121 return render_to_response('podcast.html', {
122 'podcast': podcast,
123 'url': current_site
124 }, context_instance=RequestContext(request))
128 def history(request, len=15, device_id=None):
129 if device_id:
130 devices = Device.objects.filter(id=device_id)
131 else:
132 devices = Device.objects.filter(user=request.user)
134 history = SubscriptionAction.objects.filter(device__in=devices).order_by('-timestamp')[:len]
135 episodehistory = EpisodeAction.objects.filter(device__in=devices).order_by('-timestamp')[:len]
137 generalhistory = []
139 for row in history:
140 generalhistory.append(row)
141 for row in episodehistory:
142 generalhistory.append(row)
144 generalhistory.sort(key=lambda x: x.timestamp,reverse=True)
146 return render_to_response('history.html', {
147 'generalhistory': generalhistory,
148 'singledevice': devices[0] if device_id else None
149 }, context_instance=RequestContext(request))
151 def devices(request):
152 devices = Device.objects.filter(user=request.user,deleted=False).order_by('sync_group')
153 return render_to_response('devicelist.html', {
154 'devices': devices,
155 }, context_instance=RequestContext(request))
157 @login_required
158 def podcast_subscribe(request, pid):
159 podcast = Podcast.objects.get(pk=pid)
160 error_message = None
162 if request.method == 'POST':
163 form = SyncForm(request.POST)
165 try:
166 target = form.get_target()
168 if isinstance(target, SyncGroup):
169 device = target.devices()[0]
170 else:
171 device = target
173 SubscriptionAction.objects.create(podcast=podcast, device=device, action=SUBSCRIBE_ACTION)
175 return HttpResponseRedirect('/podcast/%s' % podcast.id)
177 except ValueError, e:
178 error_message = _('Could not subscribe to the podcast: %s' % e)
180 targets = podcast.subscribe_targets(request.user)
182 form = SyncForm()
183 form.set_targets(targets, _('With which client do you want to subscribe?'))
185 return render_to_response('subscribe.html', {
186 'error_message': error_message,
187 'podcast': podcast,
188 'can_subscribe': len(targets) > 0,
189 'form': form
190 }, context_instance=RequestContext(request))
192 @login_required
193 def podcast_unsubscribe(request, pid, device_id):
195 return_to = request.GET.get('return_to')
197 if return_to == None:
198 raise Http404('Wrong URL')
200 podcast = Podcast.objects.get(pk=pid)
201 device = Device.objects.get(pk=device_id)
202 SubscriptionAction.objects.create(podcast=podcast, device=device, action=UNSUBSCRIBE_ACTION, timestamp=datetime.now())
204 return HttpResponseRedirect(return_to)
206 def episode_list(podcast, user):
207 list = {}
208 episodes = Episode.objects.filter(podcast=podcast).order_by('-timestamp')
209 for e in episodes:
210 list[e] = None
211 for action in EpisodeAction.objects.filter(episode=e, user=user).order_by('timestamp'):
212 list[e] = action
214 return list
216 @login_required
217 def episode(request, id):
218 episode = Episode.objects.get(pk=id)
219 history = EpisodeAction.objects.filter(user=request.user, episode=episode).order_by('-timestamp')
221 return render_to_response('episode.html', {
222 'episode': episode,
223 'history': history,
224 }, context_instance=RequestContext(request))
227 @login_required
228 def account(request):
229 success = False
231 if request.method == 'POST':
232 form = UserAccountForm(request.POST)
234 if form.is_valid():
235 request.user.email = form.cleaned_data['email']
236 request.user.save()
237 request.user.get_profile().public_profile = form.cleaned_data['public']
238 request.user.get_profile().save()
240 success = True
242 else:
243 form = UserAccountForm({
244 'email': request.user.email,
245 'public': request.user.get_profile().public_profile
248 return render_to_response('account.html', {
249 'form': form,
250 'success': success
251 }, context_instance=RequestContext(request))
254 def toplist(request, len=100):
255 entries = ToplistEntry.objects.all().order_by('-subscriptions')[:len]
256 current_site = Site.objects.get_current()
257 return render_to_response('toplist.html', {
258 'entries': entries,
259 'url': current_site
260 }, context_instance=RequestContext(request))
263 def toplist_opml(request, count):
264 entries = ToplistEntry.objects.all().order_by('-subscriptions')[:count]
265 exporter = Exporter(_('my.gpodder.org - Top %s') % count)
267 opml = exporter.generate([e.podcast for e in entries])
269 return HttpResponse(opml, mimetype='text/xml')
272 @login_required
273 def suggestions(request):
275 rated = False
277 if 'rate' in request.GET:
278 Rating.objects.create(target='suggestions', user=request.user, rating=request.GET['rate'], timestamp=datetime.now())
279 rated = True
281 entries = SuggestionEntry.forUser(request.user)
282 current_site = Site.objects.get_current()
283 return render_to_response('suggestions.html', {
284 'entries': entries,
285 'rated' : rated,
286 'url': current_site
287 }, context_instance=RequestContext(request))
290 @login_required
291 def device(request, device_id):
292 device = Device.objects.get(pk=device_id)
293 subscriptions = device.get_subscriptions()
294 synced_with = list(device.sync_group.devices()) if device.sync_group else []
295 if device in synced_with: synced_with.remove(device)
296 success = False
297 error_message = None
298 sync_form = SyncForm()
299 sync_form.set_targets(device.sync_targets(), _('Synchronize with the following devices'))
301 if request.method == 'POST':
302 device_form = DeviceForm(request.POST)
304 if device_form.is_valid():
305 device.name = device_form.cleaned_data['name']
306 device.type = device_form.cleaned_data['type']
307 device.uid = device_form.cleaned_data['uid']
308 try:
309 device.save()
310 success = True
311 except IntegrityError, ie:
312 device = Device.objects.get(pk=device_id)
313 error_message = _('You can\'t use the same UID for two devices.')
315 else:
316 device_form = DeviceForm({
317 'name': device.name,
318 'type': device.type,
319 'uid' : device.uid
322 return render_to_response('device.html', {
323 'device': device,
324 'device_form': device_form,
325 'sync_form': sync_form,
326 'success': success,
327 'error_message': error_message,
328 'subscriptions': subscriptions,
329 'synced_with': synced_with,
330 'has_sync_targets': len(device.sync_targets()) > 0
331 }, context_instance=RequestContext(request))
334 @login_required
335 def device_delete(request, device_id):
336 if request.method != 'POST':
337 return HttpResponseNotAllowed(['POST'])
339 device = Device.objects.get(pk=device_id)
340 device.deleted = True
341 device.save()
343 current_site = Site.objects.get_current()
344 subscriptionlist = create_subscriptionlist(request)
345 return render_to_response('home-user.html', {
346 'subscriptionlist': subscriptionlist,
347 'url': current_site,
348 'deletedevice_success': True,
349 'device_name': device.name
350 }, context_instance=RequestContext(request))
353 @login_required
354 def device_sync(request, device_id):
356 if request.method != 'POST':
357 return HttpResponseNotAllowed(['POST'])
359 form = SyncForm(request.POST)
360 if not form.is_valid():
361 return HttpResponseBadRequest('invalid')
363 try:
364 target = form.get_target()
366 device = Device.objects.get(pk=device_id)
367 device.sync_with(target)
369 except ValueError, e:
370 log('error while syncing device %s: %s' % (device_id, e))
372 return HttpResponseRedirect('/device/%s' % device_id)
374 @login_required
375 def device_unsync(request, device_id):
376 if request.method != 'GET':
377 return HttpResponseNotAllowed(['GET'])
379 device = Device.objects.get(pk=device_id)
380 device.unsync()
382 return HttpResponseRedirect('/device/%s' % device_id)
384 @login_required
385 def podcast_subscribe_url(request):
386 url = request.GET.get('url')
388 if url == None:
389 raise Http404('http://my.gpodder.org/subscribe?url=http://www.example.com/podcast.xml')
391 url = sanitize_url(url)
393 if url == '':
394 raise Http404('Please specify a valid url')
396 podcast, created = Podcast.objects.get_or_create(url=url)
398 return HttpResponseRedirect('/podcast/%d/subscribe' % podcast.pk)
400 @login_required
401 def delete_account(request):
402 user = request.user
403 user.delete()
404 logout
405 return render_to_response('delete_account.html')
408 def author(request):
409 current_site = Site.objects.get_current()
410 return render_to_response('authors.html', {
411 'url': current_site
412 }, context_instance=RequestContext(request))