package de.ph87.tools.group.owner; import de.ph87.tools.group.Group; import de.ph87.tools.group.GroupMapper; import de.ph87.tools.group.GroupRepository; import de.ph87.tools.group.access.GroupAccess; import de.ph87.tools.group.access.GroupAccessService; import de.ph87.tools.group.dto.GroupDto; import de.ph87.tools.group.events.GroupDeletedEvent; import de.ph87.tools.group.member.GroupMemberService; import de.ph87.tools.group.requests.GroupChangePasswordRequest; import de.ph87.tools.group.requests.GroupChangeTitleRequest; import de.ph87.tools.group.requests.GroupUserRequest; import de.ph87.tools.group.uuid.GroupUuid; import de.ph87.tools.tools.numbers.NumbersRepository; import de.ph87.tools.user.User; import de.ph87.tools.user.UserService; import de.ph87.tools.user.push.UserPushService; import de.ph87.tools.user.uuid.UserPrivateUuid; import jakarta.annotation.Nullable; import jakarta.servlet.http.HttpServletResponse; import lombok.Getter; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.ToString; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.server.ResponseStatusException; import java.util.function.BiConsumer; @Slf4j @Service @Transactional @RequiredArgsConstructor public class GroupOwnerService { private final GroupAccessService groupAccessService; private final GroupRepository groupRepository; private final UserService userService; private final GroupMemberService groupMemberService; private final NumbersRepository numbersRepository; private final UserPushService userPushService; private final GroupMapper groupMapper; @NonNull public GroupDto create(@Nullable final UserPrivateUuid privateUuid, @NonNull final HttpServletResponse response) { final User user = userService.getUserByPrivateUuidOrElseCreate(privateUuid, response); final Group group = _create_unchecked(user); return groupMemberService._add_user_to_group_unchecked(group, user); } public void delete(@NonNull final UserPrivateUuid userPrivateUuid, @NonNull final GroupUuid groupUuid) { final GroupAccess access = groupAccessService.ownerAccess(userPrivateUuid, groupUuid); numbersRepository.deleteAllByGroup(access.group); groupRepository.delete(access.group); log.info("Group deleted: group={}", access.group); final GroupDeletedEvent event = new GroupDeletedEvent(access.group); access.group.getUsers().forEach(user -> userPushService.push(user, event)); } public void kick(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUserRequest request) { final OwnerRemoveResult result = _removeUser(privateUuid, request, (group, user) -> log.info("User kicked out of group: user={}, group={}", user, group)); groupMapper.push(result.group); } public void ban(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUserRequest request) { final OwnerRemoveResult result = _removeUser(privateUuid, request, (group, user) -> log.info("User banned from group: user={}, group={}", user, group)); result.group.getBanned().add(result.kicked); groupMapper.push(result.group); } public void unban(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUserRequest request) { final GroupAccess access = groupAccessService.ownerAccess(privateUuid, request.groupUuid); final User user = access.group.getBanned().stream().filter(u -> u.getPublicUuid().equals(request.userPublicUuid)).findFirst().orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST)); access.group.getBanned().remove(user); log.info("User unbanned from group: user={}, group={}", user, access.group); groupMapper.push(access.group); } @NonNull public GroupDto changeTitle(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupChangeTitleRequest request) { final GroupAccess ug = groupAccessService.access(privateUuid, request.groupUuid); if (!ug.group.isOwnedBy(ug.principal)) { throw new ResponseStatusException(HttpStatus.FORBIDDEN); } ug.group.setTitle(request.title); return groupMapper.push(ug.group); } @NonNull public GroupDto changePassword(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupChangePasswordRequest request) { final GroupAccess access = groupAccessService.ownerAccess(privateUuid, request.groupUuid); access.group.setPassword(request.password); return groupMapper.push(access.group); } /* EXECUTORS ------------------------------------------------------------------------------------ */ @NonNull private Group _create_unchecked(@NonNull final User user) { final Group group = groupRepository.save(new Group(user)); log.info("Group CREATED: {}", group); return group; } @NonNull private OwnerRemoveResult _removeUser(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUserRequest request, @NonNull final BiConsumer beforePush) { final GroupAccess access = groupAccessService.ownerAccess(privateUuid, request.groupUuid); final User user = access.group.getUsers().stream().filter(u -> u.getPublicUuid().equals(request.userPublicUuid)).findFirst().orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST)); if (user.equals(access.principal)) { // owner cannot kick itself from group throw new ResponseStatusException(HttpStatus.BAD_REQUEST); } groupMemberService._remove_user_from_group_unchecked(access.group, user, beforePush); return new OwnerRemoveResult(access, user); } /* RESULT CLASSES ------------------------------------------------------------------------------- */ @Getter @ToString private static class OwnerRemoveResult { @NonNull public final Group group; @NonNull public final User kicked; public OwnerRemoveResult(@NonNull final GroupAccess access, @NonNull final User kicked) { this.group = access.group; this.kicked = kicked; } } }