* feat: django-rest-framework + Person/Email API (#8233) * chore: djangorestframework -> requirements.txt * chore: auth/perm/schema classes for drf * chore: settings for drf and friends * chore: comment that api/serializer.py is not DRF * feat: URL router for DRF * feat: simple api/v3/person/{id} endpoint * fix: actually working demo endpoint * chore: no auth for PersonViewSet * ci: params in ci-run-tests.yml * Revert "ci: params in ci-run-tests.yml" This reverts commit 03808ddf94afe42b7382ddd3730959987389612b. * feat: email addresses for person API * feat: email update api (WIP) * fix: working Email API endpoint * chore: annotate address format in api schema * chore: api adjustments * feat: expose SpectacularAPIView At least for now... * chore: better schema_path_prefix * feat: permissions for DRF API * refactor: use permissions classes * refactor: extract NewEmailForm validation for reuse * refactor: ietfauth.validators module * refactor: send new email conf req via helper * feat: API call to issue new address request * chore: move datatracker DRF api to /api/core/ * fix: unused import * fix: lint * test: drf URL names + API tests (#8248) * refactor: better drf URL naming * test: test person-detail view * test: permissions * test: add_email tests + stubs * test: test email update * test: test 404 vs 403 * fix: fix permissions * test: test email partial update * test: assert we have a nonexistent PK * chore: disable DRF api for now * chore: fix git inanity * fix: lint * test: disable tests of disabled code * test: more lint
46 lines
1.9 KiB
Python
46 lines
1.9 KiB
Python
# Copyright The IETF Trust 2024, All Rights Reserved
|
|
"""DRF API Views"""
|
|
from rest_framework import mixins, viewsets
|
|
from rest_framework.decorators import action
|
|
from rest_framework.permissions import IsAuthenticated
|
|
from rest_framework.response import Response
|
|
|
|
from ietf.api.permissions import BelongsToOwnPerson, IsOwnPerson
|
|
from ietf.ietfauth.utils import send_new_email_confirmation_request
|
|
|
|
from .models import Email, Person
|
|
from .serializers import NewEmailSerializer, EmailSerializer, PersonSerializer
|
|
|
|
|
|
class EmailViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet):
|
|
"""Email viewset
|
|
|
|
Only allows updating an existing email for now.
|
|
"""
|
|
permission_classes = [IsAuthenticated & BelongsToOwnPerson]
|
|
queryset = Email.objects.all()
|
|
serializer_class = EmailSerializer
|
|
lookup_value_regex = '.+@.+' # allow @-sign in the pk
|
|
|
|
|
|
class PersonViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
|
|
"""Person viewset"""
|
|
permission_classes = [IsAuthenticated & IsOwnPerson]
|
|
queryset = Person.objects.all()
|
|
serializer_class = PersonSerializer
|
|
|
|
@action(detail=True, methods=["post"], serializer_class=NewEmailSerializer)
|
|
def email(self, request, pk=None):
|
|
"""Add an email address for this Person
|
|
|
|
Always succeeds if the email address is valid. Causes a confirmation email to be sent to the
|
|
requested address and completion of that handshake will actually add the email address. If the
|
|
address already exists, an alert will be sent instead of the confirmation email.
|
|
"""
|
|
person = self.get_object()
|
|
serializer = self.get_serializer(data=request.data)
|
|
serializer.is_valid(raise_exception=True)
|
|
# This may or may not actually send a confirmation, but doesn't reveal that to the user.
|
|
send_new_email_confirmation_request(person, serializer.validated_data["address"])
|
|
return Response(serializer.data)
|