serializers.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. from allauth.account import app_settings
  2. from allauth.account.adapter import get_adapter
  3. from allauth.account.forms import default_token_generator
  4. from allauth.account.models import EmailAddress
  5. from allauth.account.utils import filter_users_by_email
  6. from allauth.socialaccount import providers
  7. from allauth.socialaccount.models import SocialApp
  8. from dj_rest_auth.registration.serializers import (
  9. RegisterSerializer as BaseRegisterSerializer,
  10. )
  11. from dj_rest_auth.registration.serializers import (
  12. SocialAccountSerializer as BaseSocialAccountSerializer,
  13. )
  14. from dj_rest_auth.serializers import PasswordResetSerializer
  15. from django.conf import settings
  16. from django.utils.translation import gettext_lazy as _
  17. from rest_framework import serializers
  18. from glitchtip.constants import SOCIAL_ADAPTER_MAP
  19. from organizations_ext.models import OrganizationUserRole
  20. from .forms import PasswordSetAndResetForm
  21. from .models import User
  22. class SocialAccountSerializer(BaseSocialAccountSerializer):
  23. email = serializers.SerializerMethodField()
  24. username = serializers.SerializerMethodField()
  25. class Meta(BaseSocialAccountSerializer.Meta):
  26. fields = (
  27. "id",
  28. "provider",
  29. "uid",
  30. "last_login",
  31. "date_joined",
  32. "email",
  33. "username",
  34. )
  35. def get_email(self, obj):
  36. if obj.extra_data:
  37. if "email" in obj.extra_data:
  38. return obj.extra_data.get("email")
  39. return obj.extra_data.get("userPrincipalName") # MS oauth uses this
  40. def get_username(self, obj):
  41. if obj.extra_data:
  42. return obj.extra_data.get("username")
  43. class SocialAppSerializer(serializers.ModelSerializer):
  44. authorize_url = serializers.SerializerMethodField()
  45. scopes = serializers.SerializerMethodField()
  46. class Meta:
  47. model = SocialApp
  48. fields = ("provider", "name", "client_id", "authorize_url", "scopes")
  49. def get_authorize_url(self, obj):
  50. adapter = SOCIAL_ADAPTER_MAP.get(obj.provider, None)
  51. request = self.context.get("request")
  52. if adapter:
  53. return adapter(request).authorize_url
  54. def get_scopes(self, obj):
  55. request = self.context.get("request")
  56. if request:
  57. provider = providers.registry.by_id(obj.provider, request)
  58. return provider.get_scope(request)
  59. class ConfirmEmailAddressSerializer(serializers.Serializer):
  60. email = serializers.EmailField()
  61. class EmailAddressSerializer(serializers.ModelSerializer):
  62. isPrimary = serializers.BooleanField(source="primary", read_only=True)
  63. email = serializers.EmailField() # Remove default unique validation
  64. isVerified = serializers.BooleanField(source="verified", read_only=True)
  65. class Meta:
  66. model = EmailAddress
  67. fields = ("isPrimary", "email", "isVerified")
  68. def clean_email(self):
  69. """Validate email as done in allauth.account.forms.AddEmailForm"""
  70. value = self.cleaned_data["email"]
  71. value = get_adapter().clean_email(value)
  72. errors = {
  73. "this_account": _(
  74. "This e-mail address is already associated" " with this account."
  75. ),
  76. "different_account": _(
  77. "This e-mail address is already associated" " with another account."
  78. ),
  79. }
  80. users = filter_users_by_email(value)
  81. on_this_account = [u for u in users if u.pk == self.user.pk]
  82. on_diff_account = [u for u in users if u.pk != self.user.pk]
  83. if on_this_account:
  84. raise serializers.ValidationError(errors["this_account"])
  85. if on_diff_account and app_settings.UNIQUE_EMAIL:
  86. raise serializers.ValidationError(errors["different_account"])
  87. return value
  88. def validate(self, attrs):
  89. if self.context["request"].method == "POST":
  90. # Run extra validation on create
  91. self.user = self.context["request"].user
  92. self.cleaned_data = attrs
  93. attrs["email"] = self.clean_email()
  94. return attrs
  95. def create(self, validated_data):
  96. return EmailAddress.objects.add_email(
  97. self.context["request"], self.user, validated_data["email"], confirm=True
  98. )
  99. def update(self, instance, validated_data):
  100. instance.primary = True
  101. instance.save()
  102. return instance
  103. class UserSerializer(serializers.ModelSerializer):
  104. username = serializers.CharField(source="email", read_only=True)
  105. lastLogin = serializers.DateTimeField(source="last_login", read_only=True)
  106. isSuperuser = serializers.BooleanField(source="is_superuser")
  107. emails = EmailAddressSerializer(many=True, default=[])
  108. identities = SocialAccountSerializer(
  109. source="socialaccount_set", many=True, read_only=True
  110. )
  111. id = serializers.CharField()
  112. isActive = serializers.BooleanField(source="is_active")
  113. dateJoined = serializers.DateTimeField(source="created", read_only=True)
  114. hasPasswordAuth = serializers.BooleanField(
  115. source="has_usable_password", read_only=True
  116. )
  117. ownsOrg = serializers.SerializerMethodField()
  118. class Meta:
  119. model = User
  120. fields = (
  121. "username",
  122. "lastLogin",
  123. "isSuperuser",
  124. "ownsOrg",
  125. "emails",
  126. "identities",
  127. "id",
  128. "isActive",
  129. "name",
  130. "dateJoined",
  131. "hasPasswordAuth",
  132. "email",
  133. "options",
  134. )
  135. def get_ownsOrg(self, obj):
  136. userOrgUsers = obj.organizations_ext_organizationuser.all()
  137. for orgUser in userOrgUsers:
  138. if orgUser.role == OrganizationUserRole.OWNER:
  139. return True
  140. return False
  141. class RegisterSerializer(BaseRegisterSerializer):
  142. tags = serializers.CharField(
  143. write_only=True,
  144. allow_blank=True,
  145. required=False,
  146. help_text="Additional UTM (analytics) data",
  147. )
  148. def custom_signup(self, request, user):
  149. tags = self.validated_data.get("tags")
  150. if tags:
  151. user.set_register_analytics_tags(tags)
  152. user.save(update_fields=["analytics"])
  153. class UserNotificationsSerializer(serializers.ModelSerializer):
  154. subscribeByDefault = serializers.BooleanField(source="subscribe_by_default")
  155. class Meta:
  156. model = User
  157. fields = ("subscribeByDefault",)
  158. class NoopTokenSerializer(serializers.Serializer):
  159. """dj-rest-auth requires tokens, but we don't use them."""
  160. class PasswordSetResetSerializer(PasswordResetSerializer):
  161. password_reset_form_class = PasswordSetAndResetForm
  162. def save(self):
  163. request = self.context.get("request")
  164. opts = {
  165. "use_https": request.is_secure(),
  166. "from_email": getattr(settings, "DEFAULT_FROM_EMAIL"),
  167. "request": request,
  168. "token_generator": default_token_generator,
  169. "subject_template_name": "registration/password_reset_subject.txt",
  170. "email_template_name": "registration/password_reset_email.txt",
  171. "html_email_template_name": "registration/password_reset_email.html",
  172. }
  173. opts.update(self.get_email_options())
  174. self.reset_form.save(**opts)