views.py 4.53 KB
Newer Older
Lukas Burgey's avatar
Lukas Burgey committed
1
import logging
2
from django.shortcuts import get_object_or_404
3
from django.core.exceptions import ObjectDoesNotExist
Lukas Burgey's avatar
Lukas Burgey committed
4
from django.contrib.auth import logout
Lukas Burgey's avatar
Lukas Burgey committed
5
6
7
8
from rest_framework import views, viewsets
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework import status
Lukas Burgey's avatar
Lukas Burgey committed
9
10
11
12
from . import serializers
from .. import models

LOGGER = logging.getLogger(__name__)
Lukas Burgey's avatar
Lukas Burgey committed
13

Lukas Burgey's avatar
Lukas Burgey committed
14

Lukas Burgey's avatar
Lukas Burgey committed
15
16
17
18
19
20
21
22
23
def user_services(user):
    if user.is_authenticated:
        return (
            models.Service.objects
            .filter(groups__user=user)
            .distinct()
        )

    return []
Lukas Burgey's avatar
Lukas Burgey committed
24
25
26

def _api_error_response():
    return Response({'ok': False}, status=status.HTTP_400_BAD_REQUEST)
Lukas Burgey's avatar
Lukas Burgey committed
27

28
29
def user_state_dict(user):
    return serializers.UserSerializer(user).data
Lukas Burgey's avatar
Lukas Burgey committed
30

31
# Response for StateView, LogoutView, and all post requests
Lukas Burgey's avatar
Lukas Burgey committed
32
def _api_state_response(request):
33
34
35
36
37
38
39
    if not request.user.is_authenticated:
        return Response(
            {
                'logged_in': False,
            }
        )

40
    response = {
41
        'logged_in': True,
42
        'user': user_state_dict(request.user),
43
44
45
46
        'services': serializers.ServiceSerializer(
            user_services(request.user),
            many=True,
        ).data,
47

Lukas Burgey's avatar
Lukas Burgey committed
48
    }
49

50
51
52
53
54
    if 'error' in request.session:
        response['error'] = request.session['error']
        # we display errors only once
        del request.session['error']

55
56
57
    return Response(response)


Lukas Burgey's avatar
Lukas Burgey committed
58
59
60
class StateView(views.APIView):
    permission_classes = (AllowAny,)

Lukas Burgey's avatar
Lukas Burgey committed
61
    def get(self, request):
Lukas Burgey's avatar
Lukas Burgey committed
62
        return _api_state_response(request)
Lukas Burgey's avatar
Lukas Burgey committed
63
64


65
# pylint: disable=too-many-ancestors
Lukas Burgey's avatar
Lukas Burgey committed
66
67
68
69
70
71
class ServiceViewSet(viewsets.ModelViewSet):
    serializer_class = serializers.ServiceSerializer
    queryset = models.Service.objects.all()


class SSHPublicKeyView(views.APIView):
Lukas Burgey's avatar
Lukas Burgey committed
72
    def post(self, request):
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
        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 _api_state_response(request)
            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 _api_state_response(request)
Lukas Burgey's avatar
Lukas Burgey committed
93

94
        LOGGER.error('SSHPublicKeyView: malformed request %s', request)
Lukas Burgey's avatar
Lukas Burgey committed
95
        return _api_error_response()
Lukas Burgey's avatar
Lukas Burgey committed
96

Lukas Burgey's avatar
Lukas Burgey committed
97
98

class DeploymentView(views.APIView):
Lukas Burgey's avatar
Lukas Burgey committed
99
    def post(self, request):
Lukas Burgey's avatar
Lukas Burgey committed
100
101
102
103
        if (
                'type' not in request.data or
                'key' not in request.data or
                'service' not in request.data
Lukas Burgey's avatar
Lukas Burgey committed
104
        ):
105
            LOGGER.error('Deployment api got invalid request %s', request.data)
Lukas Burgey's avatar
Lukas Burgey committed
106
            return _api_error_response()
Lukas Burgey's avatar
Lukas Burgey committed
107
108

        request_type = request.data['type']
109
110
        request_service = models.Service.objects.get(
            id=request.data['service'],
Lukas Burgey's avatar
Lukas Burgey committed
111
        )
112
113
        request_key = models.SSHPublicKey.objects.get(
            id=request.data['key'],
Lukas Burgey's avatar
Lukas Burgey committed
114
        )
Lukas Burgey's avatar
Lukas Burgey committed
115

Lukas Burgey's avatar
Lukas Burgey committed
116
117
118
119
        deployment = models.Deployment.get_deployment(
            request.user,
            request_service,
        )
Lukas Burgey's avatar
Lukas Burgey committed
120
121

        if request_type == 'add':
122
            deployment.deploy_key(request_key)
Lukas Burgey's avatar
Lukas Burgey committed
123
        elif request_type == 'remove':
124
125
            deployment.withdraw_key(request_key)
        else:
Lukas Burgey's avatar
Lukas Burgey committed
126
            return _api_error_response()
Lukas Burgey's avatar
Lukas Burgey committed
127

128
        deployment.save()
Lukas Burgey's avatar
Lukas Burgey committed
129
        return _api_state_response(request)
Lukas Burgey's avatar
Lukas Burgey committed
130

131

132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
class QuestionnaireView(views.APIView):
    def post(self, request):
        task_item_id = request.query_params.get('id', '')
        if task_item_id != '':
            item = models.DeploymentTaskItem.objects.filter(id=int(task_item_id))
            if item.exists():
                item.first().questionnaire_answered(
                    answers=request.data,
                )
            else:
                LOGGER.error('Received questionnaire answer for non existing item')

        return _api_state_response(request)


Lukas Burgey's avatar
Lukas Burgey committed
147
148
149
150
151
152
class UserDeletionView(views.APIView):
    def delete(self, request):
        # this also logs out the user
        request.user.remove()
        logout(request)
        return _api_state_response(request)