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))
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([])
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)
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)
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()