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
.core
.urlresolvers
import reverse
20 from django
.http
import HttpResponseRedirect
, HttpResponseBadRequest
, \
21 HttpResponseForbidden
, Http404
22 from django
.template
import RequestContext
23 from django
.contrib
import messages
24 from mygpo
.web
.forms
import DeviceForm
, SyncForm
25 from mygpo
.web
import utils
26 from django
.utils
.translation
import ugettext
as _
27 from django
.contrib
.auth
.decorators
import login_required
28 from django
.shortcuts
import get_object_or_404
29 from django
.db
import IntegrityError
30 from mygpo
.log
import log
31 from mygpo
.api
import simple
32 from mygpo
.decorators
import manual_gc
, allowed_methods
, repeat_on_conflict
33 from mygpo
.users
.models
import PodcastUserState
, Device
34 from mygpo
import migrate
39 def overview(request
):
41 user
= migrate
.get_or_migrate_user(request
.user
)
42 device_groups
= user
.get_grouped_devices()
44 deleted_devices
= user
.inactive_devices
46 return render_to_response('devicelist.html', {
47 'device_groups': device_groups
,
48 'deleted_devices': deleted_devices
,
49 }, context_instance
=RequestContext(request
))
53 def device_decorator(f
):
54 def _decorator(request
, uid
, *args
, **kwargs
):
56 user
= migrate
.get_or_migrate_user(request
.user
)
57 device
= user
.get_device_by_uid(uid
)
62 return f(request
, device
, *args
, **kwargs
)
71 def show(request
, device
):
73 user
= migrate
.get_or_migrate_user(request
.user
)
74 user
.sync_group(device
)
76 subscriptions
= list(device
.get_subscribed_podcasts())
77 synced_with
= user
.get_synced(device
)
79 sync_targets
= list(user
.get_sync_targets(device
))
80 sync_form
= SyncForm()
81 sync_form
.set_targets(sync_targets
,
82 _('Synchronize with the following devices'))
84 return render_to_response('device.html', {
86 'sync_form': sync_form
,
87 'subscriptions': subscriptions
,
88 'synced_with': synced_with
,
89 'has_sync_targets': len(sync_targets
) > 0,
90 }, context_instance
=RequestContext(request
))
94 @allowed_methods(['POST'])
96 device_form
= DeviceForm(request
.POST
)
98 user
= migrate
.get_or_migrate_user(request
.user
)
100 if not device_form
.is_valid():
102 messages
.error(request
, _('Please fill out all fields.'))
104 return HttpResponseRedirect(reverse('device-edit-new'))
108 device
.name
= device_form
.cleaned_data
['name']
109 device
.type = device_form
.cleaned_data
['type']
110 device
.uid
= device_form
.cleaned_data
['uid']
112 user
.set_device(device
)
114 messages
.success(request
, _('Device saved'))
116 except IntegrityError
, ie
:
117 messages
.error(request
, _("You can't use the same Device "
118 "ID for two devices."))
120 return HttpResponseRedirect(reverse('device-edit', args
=[device
.uid
]))
126 @allowed_methods(['POST'])
127 def update(request
, device
):
128 device_form
= DeviceForm(request
.POST
)
130 user
= migrate
.get_or_migrate_user(request
.user
)
132 if device_form
.is_valid():
133 device
.name
= device_form
.cleaned_data
['name']
134 device
.type = device_form
.cleaned_data
['type']
135 device
.uid
= device_form
.cleaned_data
['uid']
137 user
.set_device(device
)
139 messages
.success(request
, _('Device updated'))
141 except IntegrityError
, ie
:
142 messages
.error(request
, _("You can't use the same Device "
143 "ID for two devices."))
145 return HttpResponseRedirect(reverse('device-edit', args
=[device
.uid
]))
149 @allowed_methods(['GET'])
150 def edit_new(request
):
154 device_form
= DeviceForm({
160 return render_to_response('device-create.html', {
162 'device_form': device_form
,
163 }, context_instance
=RequestContext(request
))
170 @allowed_methods(['GET'])
171 def edit(request
, device
):
173 device_form
= DeviceForm({
179 return render_to_response('device-edit.html', {
181 'device_form': device_form
,
182 }, context_instance
=RequestContext(request
))
187 def upload_opml(request
, device
):
189 if not 'opml' in request
.FILES
:
190 return HttpResponseRedirect(reverse('device-edit', args
=[device
.id]))
192 opml
= request
.FILES
['opml'].read()
193 subscriptions
= simple
.parse_subscription(opml
, 'opml')
194 simple
.set_subscriptions(subscriptions
, request
.user
, device
.uid
)
195 return HttpResponseRedirect(reverse('device', args
=[device
.id]))
201 def opml(request
, device
):
202 response
= simple
.format_podcast_list(simple
.get_subscriptions(request
.user
, device
.uid
), 'opml', request
.user
.username
)
203 response
['Content-Disposition'] = 'attachment; filename=%s.opml' % device
.uid
209 def symbian_opml(request
, device
):
210 subscriptions
= simple
.get_subscriptions(request
.user
, device
.uid
)
211 subscriptions
= map(utils
.symbian_opml_changes
, subscriptions
)
213 response
= simple
.format_podcast_list(subscriptions
, 'opml', request
.user
.username
)
214 response
['Content-Disposition'] = 'attachment; filename=%s.opml' % device
.uid
221 @allowed_methods(['POST'])
222 def delete(request
, device
):
224 user
= migrate
.get_or_migrate_user(request
.user
)
226 if user
.is_synced(device
):
227 user
.unsync_device(device
)
229 device
.deleted
= True
230 user
.set_device(device
)
233 return HttpResponseRedirect(reverse('devices'))
237 def delete_permanently(request
, device
):
239 @repeat_on_conflict(['state'])
240 def remove_device(state
, dev
):
241 state
.remove_device(dev
)
244 states
= PodcastUserState
.for_device(device
.id)
246 remove_device(state
=state
, dev
=device
)
250 return HttpResponseRedirect(reverse('devices'))
255 def undelete(request
, device
):
257 user
= migrate
.get_or_migrate_user(request
.user
)
259 device
.deleted
= False
260 user
.set_device(device
)
263 return HttpResponseRedirect(reverse('device', args
=[device
.uid
]))
269 @allowed_methods(['POST'])
270 def sync(request
, device
):
272 user
= migrate
.get_or_migrate_user(request
.user
)
274 form
= SyncForm(request
.POST
)
275 if not form
.is_valid():
276 return HttpResponseBadRequest('invalid')
279 target_uid
= form
.get_target()
281 sync_target
= user
.get_device_by_uid(target_uid
)
282 user
.sync_devices(device
, sync_target
)
285 except ValueError, e
:
287 log('error while syncing device %s: %s' % (device_id
, e
))
289 return HttpResponseRedirect(reverse('device', args
=[device
.uid
]))
295 @allowed_methods(['GET'])
296 def unsync(request
, device
):
297 user
= migrate
.get_or_migrate_user(request
.user
)
300 user
.unsync_device(device
)
303 except ValueError, e
:
304 messages
.error(request
, 'Could not unsync the device: {err}'.format(
307 return HttpResponseRedirect(reverse('device', args
=[device
.uid
]))
310 from mygpo
.web
import views
311 history
= views
.history