views.py 6.8 KB

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