views.py 4.96 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
from rest_framework import views
Lukas Burgey's avatar
Lukas Burgey committed
6
7
8
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

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

Lukas Burgey's avatar
Lukas Burgey committed
28
29
30
31
32
33
34
35
36
def user_state(user):
    return serializers.UserStateSerializer(
        user,
    ).data

def _api_state_response_data(request):
    return {
        'user_state': user_state(request.user),
    }
Lukas Burgey's avatar
Lukas Burgey committed
37

38
# Response for StateView, LogoutView, and all post requests
Lukas Burgey's avatar
Lukas Burgey committed
39
def _api_state_response(request):
40
    if not request.user.is_authenticated:
Lukas Burgey's avatar
Lukas Burgey committed
41
42
43
        return Response({
            'user_state': None,
        })
44

Lukas Burgey's avatar
Lukas Burgey committed
45
    response = _api_state_response_data(request)
46

47
48
49
50
51
    if 'error' in request.session:
        response['error'] = request.session['error']
        # we display errors only once
        del request.session['error']

52
53
    return Response(response)

Lukas Burgey's avatar
Lukas Burgey committed
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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

71

Lukas Burgey's avatar
Lukas Burgey committed
72
73
74
class StateView(views.APIView):
    permission_classes = (AllowAny,)

Lukas Burgey's avatar
Lukas Burgey committed
75
    def get(self, request):
Lukas Burgey's avatar
Lukas Burgey committed
76
        return Response(state_view_data(request))
Lukas Burgey's avatar
Lukas Burgey committed
77
78
79


class SSHPublicKeyView(views.APIView):
Lukas Burgey's avatar
Lukas Burgey committed
80
    def post(self, request):
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
        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
101

102
        LOGGER.error('SSHPublicKeyView: malformed request %s', request)
Lukas Burgey's avatar
Lukas Burgey committed
103
        return _api_error_response("malformed request")
Lukas Burgey's avatar
Lukas Burgey committed
104

Lukas Burgey's avatar
Lukas Burgey committed
105
106

class DeploymentView(views.APIView):
Lukas Burgey's avatar
Lukas Burgey committed
107
    def post(self, request):
Lukas Burgey's avatar
Lukas Burgey committed
108
109
110
111
        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
112
        ):
113
            LOGGER.error('Deployment api got invalid request %s', request.data)
Lukas Burgey's avatar
Lukas Burgey committed
114
115
116
            return _api_error_response(
                "request misses fields (should have: 'type', 'key', and 'service')"
            )
Lukas Burgey's avatar
Lukas Burgey committed
117
118

        request_type = request.data['type']
119
120
        request_service = models.Service.objects.get(
            id=request.data['service'],
Lukas Burgey's avatar
Lukas Burgey committed
121
        )
122
123
        request_key = models.SSHPublicKey.objects.get(
            id=request.data['key'],
Lukas Burgey's avatar
Lukas Burgey committed
124
        )
Lukas Burgey's avatar
Lukas Burgey committed
125

Lukas Burgey's avatar
Lukas Burgey committed
126
127
128
129
        deployment = models.Deployment.get_deployment(
            request.user,
            request_service,
        )
Lukas Burgey's avatar
Lukas Burgey committed
130
131

        if request_type == 'add':
132
            deployment.deploy_key(request_key)
Lukas Burgey's avatar
Lukas Burgey committed
133
        elif request_type == 'remove':
134
            deployment.remove_key(request_key)
135
        else:
Lukas Burgey's avatar
Lukas Burgey committed
136
            return _api_error_response("invalid value of field 'type'")
Lukas Burgey's avatar
Lukas Burgey committed
137

138
        deployment.save()
Lukas Burgey's avatar
Lukas Burgey committed
139
140
141
        return Response(
            serializers.DeploymentSerializer(deployment).data
        )
Lukas Burgey's avatar
Lukas Burgey committed
142

143

144
145
class QuestionnaireView(views.APIView):
    def post(self, request):
Lukas Burgey's avatar
Lukas Burgey committed
146
147
        state_item_id = request.query_params.get('id', '')
        if state_item_id != '':
Lukas Burgey's avatar
Lukas Burgey committed
148
149
150
            item = models.DeploymentStateItem.objects.filter(
                id=int(state_item_id),
            )
151
            if item.exists():
Lukas Burgey's avatar
Lukas Burgey committed
152
                item.first().user_answers(
153
154
155
156
157
158
159
160
                    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
161
162
163
164
165
166
class UserDeletionView(views.APIView):
    def delete(self, request):
        # this also logs out the user
        request.user.remove()
        logout(request)
        return _api_state_response(request)