import logging from django.shortcuts import get_object_or_404 from django.core.exceptions import ObjectDoesNotExist from django.contrib.auth import logout from rest_framework import views from rest_framework.permissions import AllowAny from rest_framework.response import Response from rest_framework import status from . import serializers from .. import models, serializers as model_serializers LOGGER = logging.getLogger(__name__) def user_services(user): if user.is_authenticated: return ( models.Service.objects .filter(groups__user=user) .distinct() ) return [] def _api_error_response(error): return Response({'error': error}, status=status.HTTP_400_BAD_REQUEST) def user_state(user): return serializers.UserStateSerializer( user, ).data def _api_state_response_data(request): return { 'user_state': user_state(request.user), } # Response for StateView, LogoutView, and all post requests def _api_state_response(request): if not request.user.is_authenticated: return Response({ 'user_state': None, }) response = _api_state_response_data(request) if 'error' in request.session: response['error'] = request.session['error'] # we display errors only once del request.session['error'] return Response(response) def state_view_data(request): data = {} if request.user.is_authenticated: data = _api_state_response_data(request) data['user'] = serializers.UserSerializer( request.user, ).data data['services'] = serializers.ServiceSerializer( user_services(request.user), many=True, ).data else: data['user'] = None data['user_state'] = None data['services'] = [] return data class StateView(views.APIView): permission_classes = (AllowAny,) def get(self, request): return Response(state_view_data(request)) class SSHPublicKeyView(views.APIView): def post(self, request): if 'type' in request.data: if request.data['type'] == 'remove': if 'id' in request.data: key = get_object_or_404( models.SSHPublicKey, id=request.data['id'] ) # we do not delete ssh keys directly, as we need to keep track # of them until all clients have also deleted them key.delete_key() return Response({ 'deleted': True, }) elif request.data['type'] == 'add': if 'key' in request.data: key = models.SSHPublicKey( user=request.user, name=request.data['key']['name'], key=request.data['key']['key'], ) key.save() return Response( model_serializers.SSHPublicKeySerializer( key, ).data ) LOGGER.error('SSHPublicKeyView: malformed request %s', request) return _api_error_response("malformed request") class DeploymentView(views.APIView): def post(self, request): if ( 'type' not in request.data or 'key' not in request.data or 'service' not in request.data ): LOGGER.error('Deployment api got invalid request %s', request.data) return _api_error_response( "request misses fields (should have: 'type', 'key', and 'service')" ) request_type = request.data['type'] request_service = models.Service.objects.get( id=request.data['service'], ) request_key = models.SSHPublicKey.objects.get( id=request.data['key'], ) deployment = models.Deployment.get_deployment( request.user, request_service, ) if request_type == 'add': deployment.deploy_key(request_key) elif request_type == 'remove': deployment.remove_key(request_key) else: return _api_error_response("invalid value of field 'type'") deployment.save() return Response( serializers.DeploymentSerializer(deployment).data ) class QuestionnaireView(views.APIView): def post(self, request): state_item_id = request.query_params.get('id', '') if state_item_id != '': item = models.DeploymentStateItem.objects.filter( id=int(state_item_id), ) if item.exists(): item.first().user_answers( answers=request.data, ) else: LOGGER.error('Received questionnaire answer for non existing item') return _api_state_response(request) class UserDeletionView(views.APIView): def delete(self, request): # this also logs out the user request.user.remove() logout(request) return _api_state_response(request)