views.py 5.17 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
from . import serializers
Lukas Burgey's avatar
Lukas Burgey committed
10
from .. import models, serializers as model_serializers
Lukas Burgey's avatar
Lukas Burgey committed
11
12

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
        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()
Lukas Burgey's avatar
Lukas Burgey committed
91
92
93
                    return Response({
                        'deleted': True,
                    })
94
95
96
97
98
99
100
101
            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()
Lukas Burgey's avatar
Lukas Burgey committed
102
103
104
105
106
                    return Response(
                        model_serializers.SSHPublicKeySerializer(
                            key,
                        ).data
                    )
Lukas Burgey's avatar
Lukas Burgey committed
107

108
        LOGGER.error('SSHPublicKeyView: malformed request %s', request)
Lukas Burgey's avatar
Lukas Burgey committed
109
        return _api_error_response("malformed request")
Lukas Burgey's avatar
Lukas Burgey committed
110

Lukas Burgey's avatar
Lukas Burgey committed
111
112

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

        request_type = request.data['type']
125
126
        request_service = models.Service.objects.get(
            id=request.data['service'],
Lukas Burgey's avatar
Lukas Burgey committed
127
        )
128
129
        request_key = models.SSHPublicKey.objects.get(
            id=request.data['key'],
Lukas Burgey's avatar
Lukas Burgey committed
130
        )
Lukas Burgey's avatar
Lukas Burgey committed
131

Lukas Burgey's avatar
Lukas Burgey committed
132
133
134
135
        deployment = models.Deployment.get_deployment(
            request.user,
            request_service,
        )
Lukas Burgey's avatar
Lukas Burgey committed
136
137

        if request_type == 'add':
138
            deployment.deploy_key(request_key)
Lukas Burgey's avatar
Lukas Burgey committed
139
        elif request_type == 'remove':
140
            deployment.remove_key(request_key)
141
        else:
Lukas Burgey's avatar
Lukas Burgey committed
142
            return _api_error_response("invalid value of field 'type'")
Lukas Burgey's avatar
Lukas Burgey committed
143

144
        deployment.save()
Lukas Burgey's avatar
Lukas Burgey committed
145
146
147
        return Response(
            serializers.DeploymentSerializer(deployment).data
        )
Lukas Burgey's avatar
Lukas Burgey committed
148

149

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