views.py 4.27 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
# Response for StateView, LogoutView, and all post requests
Lukas Burgey's avatar
Lukas Burgey committed
30
def _api_state_response(request):
31
    response = {
Lukas Burgey's avatar
Lukas Burgey committed
32
33
        'logged_in': request.user.is_authenticated()
    }
34
    if request.user.is_authenticated():
35
36
        response['user'] = serializers.UserSerializer(request.user).data

37

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

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

48
49
50
    return Response(response)


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

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


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


class SSHPublicKeyView(views.APIView):
Lukas Burgey's avatar
Lukas Burgey committed
65
    def post(self, request):
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
        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
86

87
        LOGGER.error('SSHPublicKeyView: malformed request %s', request)
Lukas Burgey's avatar
Lukas Burgey committed
88
        return _api_error_response()
Lukas Burgey's avatar
Lukas Burgey committed
89

Lukas Burgey's avatar
Lukas Burgey committed
90
91

class DeploymentView(views.APIView):
Lukas Burgey's avatar
Lukas Burgey committed
92
    def post(self, request):
Lukas Burgey's avatar
Lukas Burgey committed
93
94
95
96
        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
97
        ):
98
            LOGGER.error('Deployment api got invalid request %s', request.data)
Lukas Burgey's avatar
Lukas Burgey committed
99
            return _api_error_response()
Lukas Burgey's avatar
Lukas Burgey committed
100
101

        request_type = request.data['type']
102
103
        request_service = models.Service.objects.get(
            id=request.data['service'],
Lukas Burgey's avatar
Lukas Burgey committed
104
        )
105
106
        request_key = models.SSHPublicKey.objects.get(
            id=request.data['key'],
Lukas Burgey's avatar
Lukas Burgey committed
107
        )
Lukas Burgey's avatar
Lukas Burgey committed
108
109

        # check if there is already an deployment
Lukas Burgey's avatar
Lukas Burgey committed
110
        # if not request.user.deployments.filter(service=request_service).exists():
Lukas Burgey's avatar
Lukas Burgey committed
111
112
        try:
            deployment = request.user.deployments.get(service=request_service)
113
        except ObjectDoesNotExist:
Lukas Burgey's avatar
Lukas Burgey committed
114
            if request_type == 'remove':
Lukas Burgey's avatar
Lukas Burgey committed
115
                return _api_error_response()
Lukas Burgey's avatar
Lukas Burgey committed
116
117

            deployment = models.Deployment(
Lukas Burgey's avatar
Lukas Burgey committed
118
119
120
                user=request.user,
                service=request_service,
            )
Lukas Burgey's avatar
Lukas Burgey committed
121
122
123
            deployment.save()

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

130
        deployment.save()
Lukas Burgey's avatar
Lukas Burgey committed
131
        return _api_state_response(request)
Lukas Burgey's avatar
Lukas Burgey committed
132
133
134
135
136
137
138

class UserDeletionView(views.APIView):
    def delete(self, request):
        # this also logs out the user
        request.user.remove()
        logout(request)
        return _api_state_response(request)