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 datetime
import datetime
20 from django
.core
.exceptions
import ObjectDoesNotExist
21 from django
.http
import HttpResponseBadRequest
, HttpResponseNotFound
22 from django
.views
.decorators
.csrf
import csrf_exempt
23 from django
.views
.decorators
.cache
import never_cache
24 from django
.utils
.decorators
import method_decorator
25 from django
.views
.generic
.base
import View
27 from mygpo
.utils
import parse_request_body
28 from mygpo
.api
.exceptions
import ParameterMissing
29 from mygpo
.decorators
import cors_origin
30 from mygpo
.core
.json
import JSONDecodeError
31 from mygpo
.api
.basic_auth
import require_valid_user
, check_username
35 logger
= logging
.getLogger(__name__
)
38 class RequestException(Exception):
39 """ Raised if the request is malfored or otherwise invalid """
44 @method_decorator(csrf_exempt
)
45 @method_decorator(require_valid_user
)
46 @method_decorator(check_username
)
47 @method_decorator(never_cache
)
48 @method_decorator(cors_origin())
49 def dispatch(self
, *args
, **kwargs
):
50 """ Dispatches request and does generic error handling """
52 return super(APIView
, self
).dispatch(*args
, **kwargs
)
54 except ObjectDoesNotExist
as e
:
55 return HttpResponseNotFound(str(e
))
57 except (RequestException
, ParameterMissing
) as e
:
58 return HttpResponseBadRequest(str(e
))
60 def parsed_body(self
, request
):
61 """ Returns the object parsed from the JSON request body """
64 raise RequestException('POST data must not be empty')
67 # TODO: implementation of parse_request_body can be moved here
68 # after all views using it have been refactored
69 return parse_request_body(request
)
70 except (JSONDecodeError
, UnicodeDecodeError, ValueError) as e
:
71 msg
= u
'Could not decode request body for user {}: {}'.format(
72 request
.user
.username
,
73 request
.body
.decode('ascii', errors
='replace'))
74 logger
.warn(msg
, exc_info
=True)
75 raise RequestException(msg
)
77 def get_since(self
, request
):
78 """ Returns parsed "since" GET parameter """
79 since_
= request
.GET
.get('since', None)
82 raise RequestException("parameter 'since' missing")
85 since
= datetime
.fromtimestamp(int(since_
))
87 raise RequestException("'since' is not a valid timestamp")
90 raise RequestException("'since' must be a non-negative number")