public Mono<Void> authAndUpsertPrivateConversationReadDate(
            @NotNull Long ownerId,
            @NotNull Long targetId,
            @Nullable @PastOrPresent Date readDate) {
        try {
            Validator.notNull(ownerId, "ownerId");
            Validator.notNull(targetId, "targetId");
        } catch (ResponseException e) {
            return Mono.error(e);
        }
        if (!isReadReceiptEnabled) {
            return Mono.error(
                    ResponseException.get(ResponseStatusCode.UPDATING_READ_DATE_IS_DISABLED));
        }
        return messageService.hasPrivateMessage(targetId, ownerId)
                // TODO: This is a simple authorization implementation,
                // we can throw different status codes for different reasons
                // to have a fine-grained control in the future.
                .flatMap(hasPrivateMessage -> hasPrivateMessage
                        ? upsertPrivateConversationReadDate(ownerId,
                                targetId,
                                useServerTime
                                        ? new Date()
                                        : readDate)
                        : Mono.empty());
    }
@param groupService is lazy because conversationService -> groupService ->
                    conversationService
turms-service/src/main/java/im/turms/service/domain/conversation/service/ConversationService.java