public Mono<GroupJoinRequest> authAndCreateGroupJoinRequest(
            @NotNull Long requesterId,
            @NotNull Long groupId,
            @Nullable String content) {
        try {
            Validator.notNull(requesterId, "requesterId");
            Validator.notNull(groupId, "groupId");
            Validator.maxLength(content, "content", maxContentLength);
        } catch (ResponseException e) {
            return Mono.error(e);
        }
        return groupMemberService.isGroupMember(groupId, requesterId, false)
                .flatMap(isGroupMember -> isGroupMember
                        ? Mono.error(ResponseException
                                .get(ResponseStatusCode.GROUP_MEMBER_SEND_GROUP_JOIN_REQUEST))
                        : groupBlocklistService.isBlocked(groupId, requesterId))
                .flatMap(isBlocked -> isBlocked
                        ? Mono.error(ResponseException
                                .get(ResponseStatusCode.BLOCKED_USER_SEND_GROUP_JOIN_REQUEST))
                        : groupService.queryGroupTypeIdIfActiveAndNotDeleted(groupId))
                .switchIfEmpty(Mono.error(ResponseException
                        .get(ResponseStatusCode.SEND_GROUP_JOIN_REQUEST_TO_INACTIVE_GROUP)))
                .flatMap(groupTypeService::queryGroupType)
                .flatMap(type -> switch (type.getJoinStrategy()) {
                    case MEMBERSHIP_REQUEST -> Mono.error(ResponseException.get(
                            ResponseStatusCode.SEND_GROUP_JOIN_REQUEST_TO_GROUP_USING_MEMBERSHIP_REQUEST));
                    case INVITATION -> Mono.error(ResponseException.get(
                            ResponseStatusCode.SEND_GROUP_JOIN_REQUEST_TO_GROUP_USING_INVITATION));
                    case QUESTION -> Mono.error(ResponseException.get(
                            ResponseStatusCode.SEND_GROUP_JOIN_REQUEST_TO_GROUP_USING_QUESTION));
                    case JOIN_REQUEST -> {
                        long id = node.nextLargeGapId(ServiceType.GROUP_JOIN_REQUEST);
                        String finalContent = content == null
                                ? ""
                                : content;
                        GroupJoinRequest groupJoinRequest = new GroupJoinRequest(
                                id,
                                finalContent,
                                RequestStatus.PENDING,
                                new Date(),
                                null,
                                null,
                                groupId,
                                requesterId,
                                null);
                        yield groupJoinRequestRepository.insert(groupJoinRequest)
                                .then(Mono.whenDelayError(
                                        groupVersionService.updateJoinRequestsVersion(groupId)
                                                .onErrorResume(t -> {
                                                    LOGGER.error(
                                                            "Caught an error while updating the join requests version of the group ({}) after creating a join request",
                                                            groupId,
                                                            t);
                                                    return Mono.empty();
                                                }),
                                        userVersionService
                                                .updateSentGroupJoinRequestsVersion(requesterId)
                                                .onErrorResume(t -> {
                                                    LOGGER.error(
                                                            "Caught an error while updating the sent group join requests version of the requester ({}) after creating a join request",
                                                            requesterId,
                                                            t);
                                                    return Mono.empty();
                                                })))
                                .thenReturn(groupJoinRequest);
                    }
                });
    }
@author James Chen
@implNote The status of group join requests never become EXPIRED in MongoDB automatically (admins
          can specify them to expired manually though) even if there is an expireAfter property
          because Turms will not create a cron job to scan and expire requests in MongoDB.
          Instead, Turms transforms the status of requests when returning them to users or admins
          for less resource consumption and better performance to expire requests.
turms-service/src/main/java/im/turms/service/domain/group/service/GroupJoinRequestService.java