views.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. from allauth.account.models import EmailAddress
  2. from django.core.exceptions import ObjectDoesNotExist, ValidationError
  3. from django.http import Http404
  4. from django.shortcuts import get_object_or_404
  5. from rest_framework import exceptions, mixins, status, viewsets
  6. from rest_framework.decorators import action
  7. from rest_framework.response import Response
  8. from apps.organizations_ext.models import Organization
  9. from apps.projects.models import UserProjectAlert
  10. from apps.users.utils import is_user_registration_open
  11. from .models import User
  12. from .serializers import (
  13. ConfirmEmailAddressSerializer,
  14. CurrentUserSerializer,
  15. EmailAddressSerializer,
  16. UserNotificationsSerializer,
  17. UserSerializer,
  18. )
  19. class UserViewSet(viewsets.ModelViewSet):
  20. queryset = User.objects.all()
  21. serializer_class = UserSerializer
  22. def get_queryset(self):
  23. queryset = super().get_queryset()
  24. organization_slug = self.kwargs.get("organization_slug")
  25. if organization_slug:
  26. queryset = queryset.filter(
  27. organizations_ext_organization__slug=organization_slug,
  28. organizations_ext_organization__users=self.request.user,
  29. )
  30. else:
  31. queryset = queryset.filter(id=self.request.user.id)
  32. return queryset
  33. def get_object(self):
  34. if self.kwargs.get("pk") == "me":
  35. return self.request.user
  36. return super().get_object()
  37. def get_serializer_class(self):
  38. if self.kwargs.get("pk") == "me":
  39. return CurrentUserSerializer
  40. return super().get_serializer_class()
  41. def perform_create(self, serializer):
  42. organization_slug = self.kwargs.get("organization_slug")
  43. try:
  44. Organization.objects.get(slug=organization_slug)
  45. except Organization.DoesNotExist as err:
  46. raise exceptions.ValidationError("Organization does not exist") from err
  47. # TODO deal with organization and users who aren't set up yet
  48. if not is_user_registration_open() and not self.request.user.is_superuser:
  49. raise exceptions.PermissionDenied("Registration is not open")
  50. user = serializer.save()
  51. return user
  52. def destroy(self, request, *args, **kwargs):
  53. instance = self.get_object()
  54. if instance.organizations_ext_organizationuser.filter(
  55. organizationowner__isnull=False
  56. ):
  57. return Response(
  58. data={
  59. "message": "User is organization owner. Delete organization or transfer ownership first."
  60. },
  61. status=status.HTTP_400_BAD_REQUEST,
  62. )
  63. self.perform_destroy(instance)
  64. return Response(status=status.HTTP_204_NO_CONTENT)
  65. @action(detail=True, methods=["get", "post", "put"])
  66. def notifications(self, request, pk=None):
  67. user = self.get_object()
  68. if request.method == "GET":
  69. serializer = UserNotificationsSerializer(user)
  70. return Response(serializer.data)
  71. serializer = UserNotificationsSerializer(user, data=request.data)
  72. if serializer.is_valid():
  73. serializer.save()
  74. return Response(serializer.data)
  75. else:
  76. return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
  77. @action(
  78. detail=True, methods=["get", "post", "put"], url_path="notifications/alerts"
  79. )
  80. def alerts(self, request, pk=None):
  81. """
  82. Returns dictionary of project_id: status. Now project_id status means it's "default"
  83. To update, submit `{project_id: status}` where status is -1 (default), 0, or 1
  84. """
  85. user = self.get_object()
  86. alerts = user.userprojectalert_set.all()
  87. if request.method == "GET":
  88. data = {}
  89. for alert in alerts:
  90. data[alert.project_id] = alert.status
  91. return Response(data)
  92. data = request.data
  93. try:
  94. items = [x for x in data.items()]
  95. except AttributeError as err:
  96. raise exceptions.ValidationError(
  97. "Invalid alert format, expected dictionary"
  98. ) from err
  99. if len(data) != 1:
  100. raise exceptions.ValidationError("Invalid alert format, expected one value")
  101. project_id, alert_status = items[0]
  102. if alert_status not in [1, 0, -1]:
  103. raise exceptions.ValidationError("Invalid status, must be -1, 0, or 1")
  104. alert = alerts.filter(project_id=project_id).first()
  105. if alert and alert_status == -1:
  106. alert.delete()
  107. else:
  108. UserProjectAlert.objects.update_or_create(
  109. user=user, project_id=project_id, defaults={"status": alert_status}
  110. )
  111. return Response(status=204)
  112. class EmailAddressViewSet(
  113. mixins.CreateModelMixin,
  114. mixins.ListModelMixin,
  115. viewsets.GenericViewSet,
  116. ):
  117. queryset = EmailAddress.objects.all()
  118. serializer_class = EmailAddressSerializer
  119. pagination_class = None
  120. def get_user(self, user_pk):
  121. if user_pk == "me":
  122. return self.request.user
  123. raise exceptions.ValidationError(
  124. "Can only change primary email address on own account"
  125. )
  126. def get_queryset(self):
  127. user = self.get_user(self.kwargs.get("user_pk"))
  128. queryset = super().get_queryset().filter(user=user)
  129. return queryset
  130. def put(self, request, user_pk, format=None):
  131. """
  132. Set a new primary email (must be verified) this will also set the email used when a user logs in.
  133. """
  134. user = self.get_user(user_pk)
  135. try:
  136. email_address = user.emailaddress_set.get(
  137. email=request.data.get("email"), verified=True
  138. )
  139. email_address.set_as_primary()
  140. except ObjectDoesNotExist as err:
  141. raise Http404 from err
  142. serializer = self.serializer_class(
  143. instance=email_address, data=request.data, context={"request": request}
  144. )
  145. if serializer.is_valid():
  146. serializer.save()
  147. return Response(serializer.data)
  148. return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
  149. def delete(self, request, user_pk, format=None):
  150. user = self.get_user(user_pk)
  151. try:
  152. email_address = user.emailaddress_set.get(
  153. email=request.data.get("email"), primary=False
  154. )
  155. except ObjectDoesNotExist as err:
  156. raise Http404 from err
  157. email_address.delete()
  158. return Response(status=status.HTTP_204_NO_CONTENT)
  159. @action(detail=False, methods=["post"])
  160. def confirm(self, request, user_pk):
  161. serializer = ConfirmEmailAddressSerializer(data=request.data)
  162. serializer.is_valid(raise_exception=True)
  163. email_address = get_object_or_404(
  164. self.get_queryset(), email=serializer.validated_data.get("email")
  165. )
  166. email_address.send_confirmation(request)
  167. return Response(status=204)