-
Notifications
You must be signed in to change notification settings - Fork 89
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'developer' into 'master'
0.1.8 Closes #28, #30, #31, and #32 See merge request polemarch/ce!11
- Loading branch information
Showing
357 changed files
with
2,282 additions
and
86,589 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,21 @@ | ||
from .environment import prepare_environment | ||
from vstutils.environment import prepare_environment, cmd_execution, os | ||
|
||
__version__ = "0.1.7" | ||
default_settings = { | ||
# ansible specific environment variables | ||
"ANSIBLE_HOST_KEY_CHECKING": 'False', | ||
"ANSIBLE_FORCE_COLOR": "true", | ||
# celery specific | ||
"C_FORCE_ROOT": "true", | ||
# django settings module | ||
"DJANGO_SETTINGS_MODULE": os.getenv( | ||
"DJANGO_SETTINGS_MODULE", 'polemarch.main.settings' | ||
), | ||
# VSTUTILS settings | ||
"VST_PROJECT": os.getenv("VST_PROJECT", 'polemarch'), | ||
"VST_ROOT_URLCONF": os.getenv("VST_ROOT_URLCONF", 'polemarch.main.urls'), | ||
"VST_WSGI": os.getenv("VST_WSGI", 'polemarch.main.wsgi') | ||
} | ||
|
||
def _main(**kwargs): | ||
# pylint: disable=unused-variable | ||
import sys | ||
from django.core.management import execute_from_command_line | ||
prepare_environment(**kwargs) | ||
execute_from_command_line(sys.argv) | ||
__version__ = "0.1.8" | ||
|
||
def get_app(**kwargs): | ||
from celery import Celery | ||
prepare_environment(**kwargs) | ||
celery_app = Celery('polemarch') | ||
celery_app.config_from_object('django.conf:settings', namespace='CELERY') | ||
celery_app.autodiscover_tasks() | ||
return celery_app | ||
prepare_environment(**default_settings) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
from polemarch import _main | ||
from vstutils.environment import cmd_execution, sys | ||
sys.path.append('./') | ||
|
||
_main() | ||
cmd_execution() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,176 +1,22 @@ | ||
from collections import namedtuple | ||
import six | ||
from django.db.models.query import QuerySet | ||
from rest_framework import viewsets, views as rest_views | ||
from rest_framework.decorators import detail_route, list_route | ||
from rest_framework.response import Response as RestResponse | ||
from rest_framework.reverse import reverse | ||
|
||
|
||
_ResponseClass = namedtuple("ResponseData", [ | ||
"data", "status" | ||
]) | ||
|
||
|
||
class Response(_ResponseClass): | ||
|
||
def _asdict(self): | ||
data = super(Response, self)._asdict() | ||
data["status"] = data.get("status", 200) | ||
if isinstance(data["data"], (six.string_types, six.text_type)): | ||
data["data"] = dict(detail=self.data) | ||
return data | ||
|
||
@property | ||
def resp(self): | ||
return RestResponse(**self._asdict()) | ||
|
||
@property | ||
def resp_dict(self): # nocv | ||
return self._asdict() | ||
|
||
|
||
class QuerySetMixin(rest_views.APIView): | ||
queryset = None | ||
model = None | ||
|
||
def _base_get_queryset(self): | ||
assert self.queryset is not None, ( | ||
"'%s' should either include a `queryset` attribute, " | ||
"or override the `get_queryset()` method." | ||
% self.__class__.__name__ | ||
) | ||
|
||
queryset = self.queryset | ||
if isinstance(queryset, QuerySet): | ||
# Ensure queryset is re-evaluated on each request. | ||
queryset = queryset.all() | ||
return queryset | ||
|
||
def get_extra_queryset(self): | ||
return self.queryset | ||
|
||
def get_queryset(self): | ||
if self.queryset is None: | ||
assert self.model is not None, ( | ||
"'%s' should either include a `queryset` or `model` attribute," | ||
" or override the `get_queryset()` method." | ||
% self.__class__.__name__ | ||
) | ||
qs = self.model.objects.all() | ||
self.queryset = getattr(qs, 'cleared', qs.all)() | ||
if self.kwargs.get("pk", None) is None: | ||
self.queryset = self.get_extra_queryset() | ||
return self._base_get_queryset() | ||
|
||
|
||
class GenericViewSet(QuerySetMixin, viewsets.GenericViewSet): | ||
serializer_class_one = None | ||
model = None | ||
|
||
def get_serializer_class(self): | ||
if self.kwargs.get("pk", False) or self.action in ["create"] or \ | ||
int(self.request.query_params.get("detail", u"0")): | ||
if self.serializer_class_one is not None: | ||
return self.serializer_class_one | ||
return super(GenericViewSet, self).get_serializer_class() | ||
|
||
def filter_route_queryset(self, queryset, filter_classes=None): | ||
if filter_classes is not None: | ||
if not isinstance(filter_classes, (list, tuple)): | ||
filter_classes = [filter_classes] | ||
for filter_class in list(filter_classes): | ||
queryset = filter_class(self.request.query_params, | ||
queryset=queryset, | ||
request=self.request).qs | ||
return queryset | ||
|
||
def get_paginated_route_response(self, queryset, serializer_class, | ||
filter_classes=None, **kwargs): | ||
queryset = self.filter_route_queryset(queryset, filter_classes) | ||
|
||
page = self.paginate_queryset(queryset) | ||
if page is not None: | ||
serializer = serializer_class(page, many=True, **kwargs) | ||
return self.get_paginated_response(serializer.data) | ||
|
||
serializer = serializer_class(queryset, many=True, **kwargs) | ||
return RestResponse(serializer.data) | ||
|
||
@list_route(methods=["post"]) | ||
def filter(self, request): | ||
queryset = self.filter_queryset(self.get_queryset()) | ||
queryset = queryset.filter(**request.data.get("filter", {})) | ||
queryset = queryset.exclude(**request.data.get("exclude", {})) | ||
|
||
return self.get_paginated_route_response( | ||
queryset=queryset, | ||
serializer_class=self.get_serializer_class(), | ||
context=self.get_serializer_context() | ||
) | ||
from vstutils.api.base import action | ||
|
||
|
||
class LimitedPermissionMixin(object): | ||
POST_WHITE_LIST = [] | ||
|
||
def get_extra_queryset(self): | ||
return self.queryset.user_filter(self.request.user) | ||
|
||
|
||
class PermissionMixin(LimitedPermissionMixin): # nocv | ||
@detail_route(methods=["put", "get"]) | ||
@action(methods=["put", "get"], detail=True) | ||
def owner(self, request, pk=None): | ||
# pylint: disable=unused-argument | ||
serializer = self.get_serializer(self.get_object()) | ||
return serializer.owner(request).resp | ||
|
||
@detail_route(methods=["post", "put", "delete", "get"]) | ||
@action(methods=["post", "put", "delete", "get"], detail=True) | ||
def permissions(self, request, pk=None): | ||
# pylint: disable=unused-argument | ||
serializer = self.get_serializer(self.get_object()) | ||
return serializer.permissions(request).resp | ||
|
||
|
||
class ReadOnlyModelViewSet(GenericViewSet, | ||
viewsets.ReadOnlyModelViewSet): | ||
pass | ||
|
||
|
||
class HistoryModelViewSet(GenericViewSet, | ||
viewsets.ReadOnlyModelViewSet, | ||
viewsets.mixins.DestroyModelMixin): | ||
pass | ||
|
||
|
||
class ModelViewSetSet(GenericViewSet, viewsets.ModelViewSet): | ||
POST_WHITE_LIST = [] | ||
|
||
|
||
class NonModelsViewSet(GenericViewSet): | ||
base_name = None | ||
|
||
def get_queryset(self): | ||
return QuerySet() # nocv | ||
|
||
|
||
class ListNonModelViewSet(NonModelsViewSet, | ||
viewsets.mixins.ListModelMixin): | ||
# pylint: disable=abstract-method | ||
schema = None | ||
|
||
@property | ||
def methods(self): | ||
this_class_dict = ListNonModelViewSet.__dict__ | ||
obj_class_dict = self.__class__.__dict__ | ||
new_methods = list() | ||
for name, attr in obj_class_dict.items(): | ||
detail = getattr(attr, 'detail', True) | ||
if name not in this_class_dict and not detail: | ||
new_methods.append(name.replace('_', "-")) | ||
return new_methods | ||
|
||
def list(self, request, *args, **kwargs): | ||
routes = { | ||
method: reverse("{}-{}".format(self.base_name, method), | ||
request=request) | ||
for method in self.methods | ||
} | ||
return Response(routes, 200).resp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,57 +0,0 @@ | ||
import logging | ||
import sys | ||
import traceback | ||
from django.core.exceptions import PermissionDenied | ||
|
||
from django.core import exceptions as djexcs | ||
from django.http.response import Http404 | ||
from rest_framework import exceptions, status, views | ||
from rest_framework.response import Response | ||
|
||
from ..main import exceptions as mexcs | ||
|
||
logger = logging.getLogger("polemarch") | ||
|
||
|
||
def polemarch_exception_handler(exc, context): | ||
# pylint: disable=too-many-return-statements | ||
logger.info(traceback.format_exc()) | ||
default_exc = (exceptions.APIException, djexcs.PermissionDenied) | ||
|
||
if isinstance(exc, PermissionDenied): # pragma: no cover | ||
return Response({"detail": str(exc)}, | ||
status=status.HTTP_403_FORBIDDEN) | ||
|
||
elif isinstance(exc, mexcs.DataNotReady): | ||
return Response({"detail": exc.msg}, | ||
status=status.HTTP_424_FAILED_DEPENDENCY) | ||
|
||
elif isinstance(exc, (mexcs.NotApplicable, Http404)): | ||
return Response({"detail": getattr(exc, 'msg', str(exc))}, | ||
status=status.HTTP_404_NOT_FOUND) | ||
|
||
elif isinstance(exc, djexcs.ValidationError): | ||
if hasattr(exc, 'error_dict'): | ||
errors = dict(exc) | ||
elif hasattr(exc, 'error_list'): # nocv | ||
errors = {'other_errors': list(exc)} | ||
else: | ||
errors = {'other_errors': str(exc)} # nocv | ||
return Response({"detail": errors}, | ||
status=status.HTTP_400_BAD_REQUEST) | ||
|
||
elif isinstance(exc, mexcs.UnknownTypeException): | ||
return Response({"detail": exc.msg}, | ||
status=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE) | ||
|
||
elif not isinstance(exc, default_exc) and isinstance(exc, Exception): | ||
return Response({'detail': str(sys.exc_info()[1]), | ||
'error_type': sys.exc_info()[0].__name__}, | ||
status=status.HTTP_400_BAD_REQUEST) | ||
|
||
default_response = views.exception_handler(exc, context) | ||
|
||
if isinstance(exc, exceptions.NotAuthenticated): | ||
default_response["X-Anonymous"] = "true" | ||
|
||
return default_response | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.