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 functools
import partial
19 from datetime
import datetime
21 from django
.http
import HttpResponse
, HttpResponseBadRequest
, \
23 from django
.views
.decorators
.csrf
import csrf_exempt
24 from django
.core
.urlresolvers
import reverse
25 from django
.contrib
.sites
.models
import RequestSite
26 from django
.contrib
.auth
import get_user_model
27 from django
.utils
.text
import slugify
28 from django
.views
.decorators
.cache
import never_cache
29 from django
.http
import Http404
30 from django
.shortcuts
import get_object_or_404
32 from mygpo
.podcasts
.models
import Podcast
33 from mygpo
.utils
import get_timestamp
34 from mygpo
.api
.advanced
.directory
import podcast_data
35 from mygpo
.api
.httpresponse
import JsonResponse
36 from mygpo
.share
.models
import PodcastList
37 from mygpo
.api
.basic_auth
import require_valid_user
, check_username
38 from mygpo
.decorators
import allowed_methods
, repeat_on_conflict
, cors_origin
39 from mygpo
.api
.simple
import parse_subscription
, format_podcast_list
, \
41 from mygpo
.share
.views
import list_decorator
42 from mygpo
.db
.couchdb
.podcastlist
import podcastlist_for_user_slug
, \
52 @allowed_methods(['POST'])
54 def create(request
, username
, format
):
55 """ Creates a new podcast list and links to it in the Location header """
57 title
= request
.GET
.get('title', None)
60 return HttpResponseBadRequest('Title missing')
65 return HttpResponseBadRequest('Invalid title')
67 plist
= podcastlist_for_user_slug(request
.user
._id
, slug
)
70 return HttpResponse('List already exists', status
=409)
72 urls
= parse_subscription(request
.body
, format
)
73 podcasts
= [Podcast
.objects
.get_or_create_for_url(url
) for url
in urls
]
74 podcast_ids
= [podcast
.id.hex for podcast
in podcasts
]
77 plist
.created_timestamp
= get_timestamp(datetime
.utcnow())
80 plist
.user
= request
.user
._id
81 plist
.podcasts
= podcast_ids
84 response
= HttpResponse(status
=201)
85 list_url
= reverse('api-get-list', args
=[request
.user
.username
, slug
, format
])
86 response
['Location'] = list_url
92 def _get_list_data(l
, username
, domain
):
96 web
= 'http://%s%s' % (domain
,
97 reverse('list-show', args
=[username
, l
.slug
])),
103 @allowed_methods(['GET'])
105 def get_lists(request
, username
):
106 """ Returns a list of all podcast lists by the given user """
108 User
= get_user_model()
109 user
= User
.objects
.get(username
=username
)
113 lists
= podcastlists_for_user(user
._id
)
115 site
= RequestSite(request
)
117 get_data
= partial(_get_list_data
, username
=user
.username
,
119 lists_data
= map(get_data
, lists
)
121 return JsonResponse(lists_data
)
127 @allowed_methods(['GET', 'PUT', 'DELETE'])
129 def podcast_list(request
, *args
, **kwargs
):
134 DELETE
= delete_list
,
137 return handlers
[request
.method
](request
, *args
, **kwargs
)
141 @list_decorator(must_own
=False)
143 def get_list(request
, plist
, owner
, format
):
144 """ Returns the contents of the podcast list """
147 scale
= int(request
.GET
.get('scale_logo', 64))
148 except (TypeError, ValueError):
149 return HttpResponseBadRequest('scale_logo has to be a numeric value')
151 podcasts
= Podcast
.objects
.filter(id__in
=plist
.podcasts
)
153 domain
= RequestSite(request
).domain
154 p_data
= lambda p
: podcast_data(p
, domain
, scale
)
155 title
= '{title} by {username}'.format(title
=plist
.title
,
156 username
=owner
.username
)
158 return format_podcast_list(podcasts
, format
, title
, json_map
=p_data
,
159 jsonp_padding
=request
.GET
.get('jsonp', ''),
160 xml_template
='podcasts.xml', request
=request
)
165 @list_decorator(must_own
=True)
167 def update_list(request
, plist
, owner
, format
):
168 """ Replaces the podcasts in the list and returns 204 No Content """
170 is_own
= owner
== request
.uuser
173 return HttpResponseForbidden()
175 urls
= parse_subscription(request
.body
, format
)
176 podcasts
= [Podcast
.objects
.get_or_create_for_url(url
) for url
in urls
]
177 podcast_ids
= [podcast
.id.hex for podcast
in podcasts
]
179 @repeat_on_conflict(['podcast_ids'])
180 def _update(plist
, podcast_ids
):
181 plist
.podcasts
= podcast_ids
184 _update(plist
=plist
, podcast_ids
=podcast_ids
)
186 return HttpResponse(status
=204)
191 @list_decorator(must_own
=True)
193 def delete_list(request
, plist
, owner
, format
):
194 """ Delete the podcast list and returns 204 No Content """
196 is_own
= owner
== request
.user
199 return HttpResponseForbidden()
201 @repeat_on_conflict(['plist'])
207 return HttpResponse(status
=204)