class GuestLoginRequestSerializer(serializers.Serializer): page = serializers.PrimaryKeyRelatedField( queryset=Page.objects.all(), many=False ) email = serializers.EmailField() def save(self, **kwargs): email = self.validated_data['email'] page = self.validated_data['page'] group = page.group try: user = User.objects.get(username=email) if group.is_guest(user): generate_user_magic_link.delay(user_id=str(user.id), page_id=str(page.id)) return True except Exception: # ToDo: Probably add some sort of instrumentation here return True class Meta: model = User fields = ( 'name', 'group' )
class TicketSerializer(serializers.ModelSerializer): id = serializers.CharField() activation_link = serializers.SerializerMethodField() scanned = serializers.BooleanField(read_only=True) included_serializers = { 'offline_lecture': OfflineLectureSerializer, } customer_email = serializers.EmailField(source='customer.email') offline_lecture_id = serializers.CharField(source='offline_lecture.id') offline_lecture = serializers.ResourceRelatedField(read_only=True) class Meta: model = Ticket fields = [ 'id', 'customer_email', 'activation_link', 'offline_lecture', 'scanned', 'offline_lecture_id', ] def get_activation_link(self, obj): if obj.get_qr_code(): return f"{settings.SITE_URL}/api/tickets/activate/{obj.qrcode.code}" return "" def create(self, validated_data): customer = validated_data.get('customer') offline_lecture = validated_data.get('offline_lecture') customer = User.objects.get(email=customer.get('email')) offline_lecture = OfflineLecture.objects.get( id=offline_lecture.get('id')) return Ticket.objects.create(customer=customer, offline_lecture=offline_lecture)
class UserSerializer(serializers.HyperlinkedModelSerializer): basicprofile = ResourceRelatedField(read_only=True) email = serializers.EmailField() class Meta: model = User fields = ('url', 'username', 'email', 'is_staff', 'basicprofile')
class EmploymentSummarySerializer(BaseModelSerializer): class Meta: model = Employment fields = ['id', 'url', 'created', 'updated', 'name', 'email', 'role'] create_only_fields = ['email'] name = serializers.CharField(source='user.get_full_name', read_only=True) email = serializers.EmailField(source='user.email')
class PermissionLinkCreateSerializer(PermissionLinkSerializer): emails = serializers.ListField(child=serializers.EmailField(), min_length=0, required=False) class Meta: model = PermissionLink fields = ('name', 'expiration_date', 'emails') read_only = ('shipment', )
class NotifySerializer(serializers.Serializer): from_email = serializers.EmailField(max_length=200, required=True) subject = serializers.CharField(max_length=500, required=True) message = serializers.CharField(max_length=1000, required=True) is_consent = serializers.BooleanField(default=False, required=False) def create(self, validated_data): """Create an RT ticket. If this is a consent approval then the procedure is: - create ticket in ENA-MG queue otherwise: - create ticket in EMG queue """ import requests n = ena_models.Notify(**validated_data) emg_queue = settings.RT["emg_queue"] ena_queue = settings.RT["ena_queue"] ticket = { "id": "ticket/new", "Requestor": n.from_email, "Priority": "4", "Subject": n.subject, "Text": n.message.replace("\n", ';') } if n.is_consent: ticket["Queue"] = ena_queue else: ticket["Queue"] = emg_queue logger.info("Ticket %r" % ticket) content = [ "{key}: {value}".format( key=key, value=value) for key, value in ticket.items() ] payload = { 'user': settings.RT['user'], 'pass': settings.RT['pass'], 'content': "\n".join(content), } headers = { 'Content-Type': 'application/x-www-form-urlencoded' } r = requests.post(settings.RT['url'], data=payload, headers=headers) return r.status_code class Meta: model = ena_models.Notify fields = '__all__'
class UserSerializer(serializers.Serializer): id = serializers.CharField(read_only=True) username = serializers.CharField() email = serializers.EmailField() class Meta: model = User class JSONAPIMeta: resource_name = 'users' def create(self, validated_data): return User.objects.create_user(password='******', **validated_data)
class EmailSerializer(serializers.Serializer): from_email = serializers.EmailField(required=True) subject = serializers.CharField(required=True) message = serializers.CharField(required=True) def create(self, validated_data): validated_data['recipient_list'] = (settings.EMAIL_HELPDESK,) logger.info("Email %r" % validated_data) send_mail(**validated_data) class Meta: model = ena_models.Notify fields = '__all__'
class GuestUserCreateSerializer(serializers.Serializer): """ TODO: Matt rewrite with gin """ organization = serializers.PrimaryKeyRelatedField( queryset=Organization.objects.get_queryset(), many=False ) email = serializers.EmailField() name = serializers.CharField() # I don't know why, but setting this to be a pk related field errors... page = serializers.PrimaryKeyRelatedField( queryset=Page.objects.all(), many=False ) def save(self, **kwargs): email = self.validated_data['email'] user, created = User.objects.get_or_create(username=email) if created: user.name = self.validated_data['name'] organization = self.validated_data['organization'] org_user, _ = organization.get_or_add_user(user) org_user.is_guest = True org_user.is_admin = False user.save() org_user.save() page = self.validated_data['page'] page.viewers.add(user) page.save() return user class Meta: model = User fields = ( 'name', 'group' )
class ResetPasswordRequestSerializer(serializers.Serializer): """ Request a new password. Sends an email. """ email = serializers.EmailField() def save(self, **kwargs): # We don't want to expose that a user may or may not exist # Using the password reset form. So we load the user during save # and fail silently if we can't find it. try: user = User.objects.get(username=self.validated_data['email']) except User.DoesNotExist: return True # # Again, don't tell the requestor anything about the # permissions of the user. if user.is_staff or user.is_superuser: return True # Check to make sure the user isn't _only_ a guest and actually belongs to an org orgs = Organization.objects.filter(organization_users=user) org_count = orgs.count() if org_count < 1: return True # This is pretty confusing. but if the user is only a guest user, we don't allow them to reset their password. is_not_guest = False for org in orgs: if not org.is_guest(user): is_not_guest = True if not is_not_guest: return True token = token_encode(user, action='reset_password') email_user_password_reset_request(user.username, token=token) return True class Meta: model = User
class CartOrderItemSerializer(serializers.ModelSerializer): item_type = serializers.CharField() object_id = serializers.IntegerField() customer_email = serializers.EmailField() class Meta: model = OrderItem fields = ['item_type', 'object_id', 'customer_email'] def create(self, validated_data): content_type = ContentType.objects.get( model=validated_data['item_type']) user = User.objects.get(email=validated_data['customer_email']) order_item = OrderItem.objects.create( customer=user, content_type=content_type, object_id=validated_data['object_id']) return order_item
class UserSerializer(serializers.ModelSerializer): email = serializers.EmailField(required=True, allow_blank=False, allow_null=False) class Meta: model = User fields = ('id', 'first_name', 'last_name', 'email', 'create_at', 'update_at') def create(self, validated_data): user = super().create(validated_data) user.set_password(validated_data['password']) user.save() return user def validate_email(self, email): if email: if User.objects.filter(email=email).exists(): raise serializers.ValidationError('Email already used.') return email
class LoginBackOfficeSerializer(serializers.Serializer): email = serializers.EmailField(required=True) password = serializers.CharField(max_length=20, required=True) def validate(self, validate_data): try: user = User.objects.get(email=validate_data["email"]) except User.DoesNotExist: raise AuthenticationFailed() if not user.check_password(validate_data["password"]): raise AuthenticationFailed() return validate_data def get_user(self, data): """ return user object """ return User.objects.get(email__exact=data.get('email'))
class UserSerializer(BaseInternalModelSerializer): """ Model: User """ organizations = ResourceRelatedField( many=True, read_only=True, source='organizations_organization' ) username = serializers.EmailField( validators=[ UniqueValidator( queryset=User.objects.all(), message="Email address is already in use", )] ) avatar = RemoteFileField(required=False) organization_role = serializers.SerializerMethodField() def get_organization_role(self, obj): request = self.context.get('request') if not request: return None if not hasattr(request, 'organization'): return None organization = request.organization if not organization: return None if organization.is_owner(obj): return "Owner" if organization.is_admin(obj): return "Admin" if organization.is_guest(obj): return "Guest" if organization.organization_users.filter(user=obj): return "Member" return None class Meta: model = User fields = ( 'id', 'created', 'modified', 'name', 'username', 'is_staff', 'is_active', 'is_superuser', 'organizations', 'date_joined', 'avatar', 'metadata', 'organization_role', 'features', 'notification_preferences' ) read_only_fields = ( 'id', 'is_staff', 'is_superuser', 'organizations', 'date_joined', ) lookup_field = 'id'
class RegistrationSerializer(serializers.Serializer): """ User registration serializer. Creates a user and an org. """ # User Fields name = serializers.CharField() username = serializers.EmailField( validators=[ UniqueValidator( queryset=User.objects.all(), message="Email address is already in use", )] ) confirm_password = serializers.CharField() password = serializers.CharField() # Organization Fields organization_name = serializers.CharField() def validate(self, data): """ TODO: We're currently passing org data into the user serializer model. This might cause conflicts. Consider doing something smarter. :param data: :return: """ # # User Validation # Perform server side validation if data['password'] != data['confirm_password']: raise serializers.ValidationError( 'Password and Confirm Password should be the same' ) user_serializer = UserSerializer(data=data) user_serializer.is_valid(raise_exception=True) organization_data = { 'name': data['organization_name'] } organization_serializer = OrganizationSerializer(data=organization_data) organization_serializer.is_valid(raise_exception=True) data['user_serializer'] = user_serializer data['organization_serializer'] = organization_serializer return data def save(self, **kwargs): user_serializer = self.validated_data['user_serializer'] organization_serializer = self.validated_data['organization_serializer'] # # Make the user first user_serializer.save() user = user_serializer.instance user.set_password(self.validated_data['password']) user.save() # # Do organization things organization_serializer.save() organization = organization_serializer.instance organization.add_user(user) # # Holy shit this is real frustrating that I can't do this any other way... # Lets see here... # 1) Can't just let the normal celery tasks handle this because # We save the org so many times we get duplicate tasks trying to create # Multiple resources # # 2) Can't use kwargs.created in a signal because the owner hasn't been added # to the organization at that point (until we run organization.add_user # and we can't do that until we create, because we need an organization id. # Intercom IntercomOrganizationSync().execute(organization, "create_or_update") # Stripe StripeOrganizationSync().execute(organization, "create_or_update") return True class Meta: model = User
class UserProfileSerializer(serializers.ModelSerializer): """ Serializer class for UserProfile model """ first_name = serializers.CharField(source="user.first_name") last_name = serializers.CharField(source="user.last_name") email = serializers.EmailField(source="user.email") password = serializers.CharField( source="user.password", allow_null=True, default=None, required=False, write_only=True, ) last_login = serializers.DateTimeField( source="user.last_login", read_only=True) submission_count = serializers.SerializerMethodField() amount_earned = SerializableAmountField(read_only=True) avg_amount_earned = SerializableAvgAmountEarnedField(read_only=True) metadata = serializers.JSONField(read_only=True) class Meta: # pylint: disable=too-few-public-methods """ class meta options """ model = UserProfile fields = [ "id", "created", "modified", "role_display", "gender_display", "expertise_display", "first_name", "last_name", "password", "email", "ona_pk", "ona_username", "payment_number", "approved_submissions", "rejected_submissions", "approval_rate", "amount_earned", "last_login", "avg_submissions", "avg_approved_submissions", "avg_rejected_submissions", "avg_approval_rate", "avg_amount_earned", "phone_number", "role", "expertise", "gender", "national_id", "submission_count", "address", "metadata", ] owner_only_fields = ("metadata", ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if self.instance and hasattr(self.Meta, "owner_only_fields"): request = self.context.get("request") is_permitted = (request and request.user and request.user == self.instance.user) if isinstance(self.instance, QuerySet) or not is_permitted or not request: for field in getattr(self.Meta, "owner_only_fields"): self.fields.pop(field) def get_submission_count(self, obj): # pylint: disable=no-self-use """ Get the submission count """ return obj.user.submission_set.count() def validate_password(self, value): """ Custom validation for Password Field """ if not self.instance: # On create of a new user Password shouldn't be none if value is None: raise serializers.ValidationError(NEED_PASSWORD_ON_CREATE) if value is not None: validate_password(value) return value def create(self, validated_data): """ Custom create method to create User object then UserProfile object """ user_data = validated_data.pop("user") user_data["username"] = validated_data.get("ona_username") first_name = user_data.get("first_name") last_name = user_data.get("last_name") email = user_data.get("email") password = user_data.get("password") created, data = create_ona_user( settings.ONA_BASE_URL, user_data["username"], first_name, last_name, email, password, ) if not created: raise serializers.ValidationError(data) if not data: raise serializers.ValidationError(CANNOT_ACCESS_ONADATA) ona_pk = data.get("id") metadata = data.get("metadata") add_team_member(settings.ONA_BASE_URL, user_data["username"], settings.ONA_MEMBERS_TEAM_ID) # make user an admin of organisation at ona if validated_data.get("role") == UserProfile.ADMIN: updated = change_user_role( settings.ONA_BASE_URL, settings.ONA_ORG_NAME, user_data["username"], settings.ONA_OWNER_ROLE, ) if not updated: # default to contributor role incase admin fails validated_data["role"] = UserProfile.CONTRIBUTOR elif validated_data["role"] == UserProfile.CONTRIBUTOR: change_user_role( settings.ONA_BASE_URL, settings.ONA_ORG_NAME, user_data["username"], settings.ONA_CONTRIBUTER_ROLE, ) # set an unusable password by not passing the password to the create # method. Why, you ask? Because we don't want to store passwords # on the Kaznet site. Ona is the source of truth for this. try: del user_data["password"] except KeyError: pass # create the User object user = UserSerializer.create( UserSerializer(), validated_data=user_data) # populate the UserProfile object userprofile = user.userprofile userprofile.ona_pk = ona_pk userprofile.ona_username = user.username userprofile.payment_number = validated_data.get("payment_number") userprofile.phone_number = validated_data.get("phone_number") if validated_data.get("role"): userprofile.role = validated_data.get("role") userprofile.gender = validated_data.get("gender") if validated_data.get("national_id"): userprofile.national_id = validated_data.get("national_id") userprofile.expertise = validated_data.get("expertise") if metadata: userprofile.metadata["last_password_edit"] = metadata.get( settings.ONA_LAST_PASSWORD_EDIT_FIELD) userprofile.metadata["gravatar"] = data.get("gravatar") userprofile.save() return userprofile # pylint: disable=too-many-branches, too-many-statements def update(self, instance, validated_data): """ Custom update method for UserProfiles """ # deal with the user object user = instance.user user_data = validated_data.pop("user") username = user.username first_name = user_data.get("first_name") last_name = user_data.get("last_name") data = {} # you can't change username try: del user_data["username"] except KeyError: pass # you can't change email # this is because Onadata requires your current password when changing # the email. And we cannot get the user's current password try: del user_data["email"] except KeyError: pass # you can't change password # this is because Onadata requires your current password when changing # the password. And we cannot get the user's current password try: del user_data["password"] except KeyError: pass # only pick changed values significant to ona profile update_data = {} if first_name != instance.user.first_name: update_data["first_name"] = first_name if last_name != instance.user.last_name: update_data["last_name"] = last_name # update on ona only if there is are changes made significant to ona if any(update_data): updated, data = update_details(settings.ONA_BASE_URL, username, update_data) if not updated: raise serializers.ValidationError(data) if not data: raise serializers.ValidationError(CANNOT_ACCESS_ONADATA) # change role to admin if the user is not initially an admin if (validated_data.get("role") == UserProfile.ADMIN and instance.role != UserProfile.ADMIN): updated = change_user_role( settings.ONA_BASE_URL, settings.ONA_ORG_NAME, username, settings.ONA_OWNER_ROLE, ) if not updated: # default to previous role incase change to admin fails validated_data["role"] = instance.role # change role to contributor if user was admin initially elif (validated_data.get("role") != UserProfile.ADMIN and instance.role == UserProfile.ADMIN): updated = change_user_role( settings.ONA_BASE_URL, settings.ONA_ORG_NAME, username, settings.ONA_CONTRIBUTER_ROLE, ) if not updated: # default to previous role incase change to contributor fails validated_data["role"] = instance.role UserSerializer().update(instance=user, validated_data=user_data) # deal with the userprofile object instance.payment_number = validated_data.get("payment_number", instance.payment_number) instance.phone_number = validated_data.get("phone_number", instance.phone_number) instance.role = validated_data.get("role", instance.role) instance.gender = validated_data.get("gender", instance.gender) if instance.national_id: instance.national_id = validated_data.get("national_id", instance.national_id) instance.expertise = validated_data.get("expertise", instance.expertise) if any(data): metadata = data.get("metadata") gravatar = data.get("gravatar") try: instance.metadata["last_password_edit"] = metadata.get( settings.ONA_LAST_PASSWORD_EDIT_FIELD) except AttributeError: pass instance.metadata["gravatar"] = gravatar instance.save() return instance