Ejemplo n.º 1
0
    def get(self, request, username):
        """
        GET /api/user/v0/accounts/{username}/
        """
        existing_user, existing_user_profile = self._get_user_and_profile(
            username)
        user_serializer = AccountUserSerializer(existing_user)
        legacy_profile_serializer = AccountLegacyProfileSerializer(
            existing_user_profile)

        return Response(
            dict(user_serializer.data, **legacy_profile_serializer.data))
Ejemplo n.º 2
0
 def get(self, request, username_or_email):
     """
     Returns details for the given user, along with
     information about its username and joining date.
     """
     try:
         user = get_user_model().objects.get(
             Q(username=username_or_email) | Q(email=username_or_email)
         )
         data = AccountUserSerializer(user, context={'request': request}).data
         data['status'] = _('Usable') if user.has_usable_password() else _('Unusable')
         return JsonResponse(data)
     except get_user_model().DoesNotExist:
         return JsonResponse([])
Ejemplo n.º 3
0
    def patch(self, request, username):
        """
        PATCH /api/user/v0/accounts/{username}/

        Note that this implementation is the "merge patch" implementation proposed in
        https://tools.ietf.org/html/rfc7396. The content_type must be "application/merge-patch+json" or
        else an error response with status code 415 will be returned.
        """
        existing_user, existing_user_profile = self._get_user_and_profile(
            username)

        # Check for fields that are not editable. Marking them read-only causes them to be ignored, but we wish to 400.
        update = request.DATA
        read_only_fields = set(update.keys()).intersection(
            AccountUserSerializer.Meta.read_only_fields +
            AccountLegacyProfileSerializer.Meta.read_only_fields)
        if read_only_fields:
            field_errors = {}
            for read_only_field in read_only_fields:
                field_errors[read_only_field] = {
                    "developer_message":
                    "This field is not editable via this API",
                    "user_message":
                    _("Field '{field_name}' cannot be edited.".format(
                        field_name=read_only_field))
                }
            response_data = {"field_errors": field_errors}
            return Response(response_data, status=status.HTTP_400_BAD_REQUEST)

        user_serializer = AccountUserSerializer(existing_user, data=update)
        legacy_profile_serializer = AccountLegacyProfileSerializer(
            existing_user_profile, data=update)

        for serializer in user_serializer, legacy_profile_serializer:
            validation_errors = self._get_validation_errors(update, serializer)
            if validation_errors:
                return Response(validation_errors,
                                status=status.HTTP_400_BAD_REQUEST)
            serializer.save()

        return Response(status=status.HTTP_204_NO_CONTENT)
Ejemplo n.º 4
0
    def get_serialized_account(username):
        """Returns the user's account information serialized as JSON.

        Note:
          This method does not perform authentication so it is up to the caller
          to ensure that only the user themselves or staff can access the account.

        Args:
          username (str): The username for the desired account.

        Returns:
           A dict containing each of the account's fields.

        Raises:
           AccountUserNotFound: raised if there is no account for the specified username.
        """
        existing_user, existing_user_profile = AccountView._get_user_and_profile(username)
        user_serializer = AccountUserSerializer(existing_user)
        legacy_profile_serializer = AccountLegacyProfileSerializer(existing_user_profile)

        return dict(user_serializer.data, **legacy_profile_serializer.data)
Ejemplo n.º 5
0
    def update_account(requesting_user, username, update):
        """Update the account for the given username.

        Note:
            No authorization or permissions checks are done in this method. It is up to the caller
            of this method to enforce the contract that this method is only called if
            requesting_user.username == username or requesting_user.is_staff == True.

        Arguments:
            requesting_user (User): the user who initiated the request
            username (string): the username associated with the account to change
            update (dict): the updated account field values

        Raises:
            AccountUserNotFound: no user exists with the specified username
            AccountUpdateError: the update could not be completed, usually due to validation errors
                (for example, read-only fields were specified or field values are not legal)
        """
        existing_user, existing_user_profile = AccountView._get_user_and_profile(username)

        # If user has requested to change email, we must call the multi-step process to handle this.
        # It is not handled by the serializer (which considers email to be read-only).
        new_email = None
        if "email" in update:
            new_email = update["email"]
            del update["email"]

        # If user has requested to change name, store old name because we must update associated metadata
        # after the save process is complete.
        old_name = None
        if "name" in update:
            old_name = existing_user_profile.name

        # Check for fields that are not editable. Marking them read-only causes them to be ignored, but we wish to 400.
        read_only_fields = set(update.keys()).intersection(
            AccountUserSerializer.Meta.read_only_fields + AccountLegacyProfileSerializer.Meta.read_only_fields
        )
        if read_only_fields:
            field_errors = {}
            for read_only_field in read_only_fields:
                field_errors[read_only_field] = {
                    "developer_message": "This field is not editable via this API",
                    "user_message": _("Field '{field_name}' cannot be edited.".format(field_name=read_only_field))
                }
            raise AccountUpdateError({"field_errors": field_errors})

        # If the user asked to change email, send the request now.
        if new_email:
            try:
                do_email_change_request(existing_user, new_email)
            except ValueError as err:
                response_data = {
                    "developer_message": "Error thrown from do_email_change_request: '{}'".format(err.message),
                    "user_message": err.message
                }
                raise AccountUpdateError(response_data)

        user_serializer = AccountUserSerializer(existing_user, data=update)
        legacy_profile_serializer = AccountLegacyProfileSerializer(existing_user_profile, data=update)

        for serializer in user_serializer, legacy_profile_serializer:
            validation_errors = AccountView._get_validation_errors(update, serializer)
            if validation_errors:
                raise AccountUpdateError(validation_errors)
            serializer.save()

        # If the name was changed, store information about the change operation. This is outside of the
        # serializer so that we can store who requested the change.
        if old_name:
            meta = existing_user_profile.get_meta()
            if 'old_names' not in meta:
                meta['old_names'] = []
            meta['old_names'].append([
                old_name,
                "Name change requested through account API by {0}".format(requesting_user.username),
                datetime.datetime.now(UTC).isoformat()
            ])
            existing_user_profile.set_meta(meta)
            existing_user_profile.save()