[UserSettings] refactor, add tests
[mygpo.git] / mygpo / api / __init__.py
blob927edc14a9d0813e9429e0e5d346fe56ca4324d9
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
34 import logging
35 logger = logging.getLogger(__name__)
38 class RequestException(Exception):
39 """ Raised if the request is malfored or otherwise invalid """
42 class APIView(View):
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 """
51 try:
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 """
63 if not request.body:
64 raise RequestException('POST data must not be empty')
66 try:
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)
81 if since_ is None:
82 raise RequestException("parameter 'since' missing")
84 try:
85 since = datetime.fromtimestamp(int(since_))
86 except ValueError:
87 raise RequestException("'since' is not a valid timestamp")
89 if since_ < 0:
90 raise RequestException("'since' must be a non-negative number")
92 return since