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
33 from mygpo
.api
.sanitizing
import sanitize_url
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
,
44 }, context_instance
=RequestContext(request
))
47 podcasts
= Podcast
.objects
.count()
48 return render_to_response('home.html', {
49 'podcast_count': podcasts
,
53 def create_subscriptionlist(request
):
54 #sync all devices first
55 for d
in Device
.objects
.filter(user
=request
.user
):
58 subscriptions
= Subscription
.objects
.filter(user
=request
.user
)
61 for s
in subscriptions
:
63 l
[s
.podcast
]['devices'].append(s
.device
)
65 e
= Episode
.objects
.filter(podcast
=s
.podcast
).order_by('-timestamp')
66 episode
= e
[0] if e
.count() > 0 else None
68 l
[s
.podcast
] = {'podcast': s
.podcast
, 'episode': episode
, 'devices': devices
}
72 def podcast(request
, pid
):
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'
87 qs
= Subscription
.objects
.filter(podcast
=podcast
, user
=request
.user
)
89 # subscription meta is valid for all subscriptions, so we get one - doesn't matter which
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']
97 subscriptionmeta
.save()
99 except IntegrityError
, ie
:
100 error_message
= _('You can\'t use the same UID for two devices.')
102 privacy_form
= PrivacyForm({
103 'public': subscriptionmeta
.public
109 return render_to_response('podcast.html', {
112 'privacy_form': privacy_form
,
113 'devices': subscribed_devices
,
114 'can_subscribe': len(subscribe_targets
) > 0,
115 'episodes': episodes
,
116 'unsubscribe': unsubscribe
,
118 }, context_instance
=RequestContext(request
))
120 current_site
= Site
.objects
.get_current()
121 return render_to_response('podcast.html', {
124 }, context_instance
=RequestContext(request
))
128 def history(request
, len=15, device_id
=None):
130 devices
= Device
.objects
.filter(id=device_id
)
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]
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', {
155 }, context_instance
=RequestContext(request
))
158 def podcast_subscribe(request
, pid
):
159 podcast
= Podcast
.objects
.get(pk
=pid
)
162 if request
.method
== 'POST':
163 form
= SyncForm(request
.POST
)
166 target
= form
.get_target()
168 if isinstance(target
, SyncGroup
):
169 device
= target
.devices()[0]
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
)
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
,
188 'can_subscribe': len(targets
) > 0,
190 }, context_instance
=RequestContext(request
))
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
):
208 episodes
= Episode
.objects
.filter(podcast
=podcast
).order_by('-timestamp')
211 for action
in EpisodeAction
.objects
.filter(episode
=e
, user
=user
).order_by('timestamp'):
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', {
224 }, context_instance
=RequestContext(request
))
228 def account(request
):
231 if request
.method
== 'POST':
232 form
= UserAccountForm(request
.POST
)
235 request
.user
.email
= form
.cleaned_data
['email']
237 request
.user
.get_profile().public_profile
= form
.cleaned_data
['public']
238 request
.user
.get_profile().save()
243 form
= UserAccountForm({
244 'email': request
.user
.email
,
245 'public': request
.user
.get_profile().public_profile
248 return render_to_response('account.html', {
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', {
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')
273 def suggestions(request
):
277 if 'rate' in request
.GET
:
278 Rating
.objects
.create(target
='suggestions', user
=request
.user
, rating
=request
.GET
['rate'], timestamp
=datetime
.now())
281 entries
= SuggestionEntry
.forUser(request
.user
)
282 current_site
= Site
.objects
.get_current()
283 return render_to_response('suggestions.html', {
287 }, context_instance
=RequestContext(request
))
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
)
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']
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.')
316 device_form
= DeviceForm({
322 return render_to_response('device.html', {
324 'device_form': device_form
,
325 'sync_form': sync_form
,
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
))
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
343 current_site
= Site
.objects
.get_current()
344 subscriptionlist
= create_subscriptionlist(request
)
345 return render_to_response('home-user.html', {
346 'subscriptionlist': subscriptionlist
,
348 'deletedevice_success': True,
349 'device_name': device
.name
350 }, context_instance
=RequestContext(request
))
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')
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
)
375 def device_unsync(request
, device_id
):
376 if request
.method
!= 'GET':
377 return HttpResponseNotAllowed(['GET'])
379 device
= Device
.objects
.get(pk
=device_id
)
382 return HttpResponseRedirect('/device/%s' % device_id
)
385 def podcast_subscribe_url(request
):
386 url
= request
.GET
.get('url')
389 raise Http404('http://my.gpodder.org/subscribe?url=http://www.example.com/podcast.xml')
391 url
= sanitize_url(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
)
401 def delete_account(request
):
405 return render_to_response('delete_account.html')
409 current_site
= Site
.objects
.get_current()
410 return render_to_response('authors.html', {
412 }, context_instance
=RequestContext(request
))