views.py 4.23 KB
Newer Older
Lukas Burgey's avatar
Lukas Burgey committed
1
import logging
2
from django.shortcuts import get_object_or_404
Lukas Burgey's avatar
Lukas Burgey committed
3
4
5
6
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
7
8
9
10
from . import serializers
from .. import models

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

Lukas Burgey's avatar
Lukas Burgey committed
12

Lukas Burgey's avatar
Lukas Burgey committed
13
14
15
16
17
18
19
20
21
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
22
23
24

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


27
# Response for StateView, LogoutView, and all post requests
Lukas Burgey's avatar
Lukas Burgey committed
28
def _api_state_response(request):
29
    response = {
Lukas Burgey's avatar
Lukas Burgey committed
30
31
        'logged_in': request.user.is_authenticated()
    }
32
    if request.user.is_authenticated():
33
34
        response['user'] = serializers.UserSerializer(request.user).data

35

Lukas Burgey's avatar
Lukas Burgey committed
36
37
38
39
    response['services'] = serializers.ServiceSerializer(
        user_services(request.user),
        many=True,
    ).data
40

41
42
43
44
45
    if 'error' in request.session:
        response['error'] = request.session['error']
        # we display errors only once
        del request.session['error']

46
47
48
    return Response(response)


Lukas Burgey's avatar
Lukas Burgey committed
49
50
51
class StateView(views.APIView):
    permission_classes = (AllowAny,)

Lukas Burgey's avatar
Lukas Burgey committed
52
    def get(self, request):
Lukas Burgey's avatar
Lukas Burgey committed
53
        return _api_state_response(request)
Lukas Burgey's avatar
Lukas Burgey committed
54
55


56
# pylint: disable=too-many-ancestors
Lukas Burgey's avatar
Lukas Burgey committed
57
58
59
60
61
62
class ServiceViewSet(viewsets.ModelViewSet):
    serializer_class = serializers.ServiceSerializer
    queryset = models.Service.objects.all()


class SSHPublicKeyView(views.APIView):
Lukas Burgey's avatar
Lukas Burgey committed
63
    def post(self, request):
Lukas Burgey's avatar
Lukas Burgey committed
64
        if 'type' not in request.data:
65
            LOGGER.error('SSHPublicKeyView: malformed request %s', request)
Lukas Burgey's avatar
Lukas Burgey committed
66
            return _api_error_response()
Lukas Burgey's avatar
Lukas Burgey committed
67
68
69
70
71
72

        request_type = request.data['type']

        if request_type == 'remove':
            if 'name' in request.data:
                key = get_object_or_404(
Lukas Burgey's avatar
Lukas Burgey committed
73
74
75
                    models.SSHPublicKey,
                    name=request.data['name']
                )
Lukas Burgey's avatar
Lukas Burgey committed
76
77
                # we do not delete ssh keys directly, as we need to keep track
                # of them until all clients have also deleted them
78
79
80

                # key state: -> (1), if there are no deployments
                # key state: -> (5), if there are deployments
81
                key.delete_key()
Lukas Burgey's avatar
Lukas Burgey committed
82
                return _api_state_response(request)
Lukas Burgey's avatar
Lukas Burgey committed
83
84
85
        elif request_type == 'add':
            if 'key' in request.data:
                key = models.SSHPublicKey(
Lukas Burgey's avatar
Lukas Burgey committed
86
87
88
89
                    user=request.user,
                    name=request.data['key']['name'],
                    key=request.data['key']['key'],
                )
90
                # key state: -> (2)
Lukas Burgey's avatar
Lukas Burgey committed
91
                key.save()
Lukas Burgey's avatar
Lukas Burgey committed
92
                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
109

        request_type = request.data['type']
        request_service = get_object_or_404(
Lukas Burgey's avatar
Lukas Burgey committed
110
111
            models.Service, name=request.data['service']
        )
Lukas Burgey's avatar
Lukas Burgey committed
112
        request_key = get_object_or_404(
Lukas Burgey's avatar
Lukas Burgey committed
113
114
115
            models.SSHPublicKey,
            name=request.data['key'],
        )
Lukas Burgey's avatar
Lukas Burgey committed
116
117

        # check if there is already an deployment
Lukas Burgey's avatar
Lukas Burgey committed
118
        # if not request.user.deployments.filter(service=request_service).exists():
Lukas Burgey's avatar
Lukas Burgey committed
119
120
121
        try:
            deployment = request.user.deployments.get(service=request_service)
        except Exception:
Lukas Burgey's avatar
Lukas Burgey committed
122
            if request_type == 'remove':
Lukas Burgey's avatar
Lukas Burgey committed
123
                return _api_error_response()
Lukas Burgey's avatar
Lukas Burgey committed
124
125

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

        if request_type == 'add':
132
            deployment.deploy_key(request_key)
Lukas Burgey's avatar
Lukas Burgey committed
133
        elif request_type == 'remove':
134
135
            deployment.withdraw_key(request_key)
        else:
Lukas Burgey's avatar
Lukas Burgey committed
136
            return _api_error_response()
Lukas Burgey's avatar
Lukas Burgey committed
137

138
        deployment.save()
Lukas Burgey's avatar
Lukas Burgey committed
139
        return _api_state_response(request)