diff --git a/src/main/java/de/ph87/tools/group/AdminRemoveResult.java b/src/main/java/de/ph87/tools/group/AdminRemoveResult.java deleted file mode 100644 index d7055e0..0000000 --- a/src/main/java/de/ph87/tools/group/AdminRemoveResult.java +++ /dev/null @@ -1,23 +0,0 @@ -package de.ph87.tools.group; - -import de.ph87.tools.user.User; -import lombok.Getter; -import lombok.NonNull; -import lombok.ToString; - -@Getter -@ToString -public class AdminRemoveResult { - - @NonNull - public final Group group; - - @NonNull - public final User kicked; - - public AdminRemoveResult(@NonNull final GroupAccess access, @NonNull final User kicked) { - this.group = access.group; - this.kicked = kicked; - } - -} diff --git a/src/main/java/de/ph87/tools/group/GroupAccessController.java b/src/main/java/de/ph87/tools/group/GroupAccessController.java new file mode 100644 index 0000000..7a5bcac --- /dev/null +++ b/src/main/java/de/ph87/tools/group/GroupAccessController.java @@ -0,0 +1,26 @@ +package de.ph87.tools.group; + +import de.ph87.tools.group.uuid.GroupUuid; +import de.ph87.tools.user.uuid.UserPrivateUuid; +import jakarta.annotation.Nullable; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@CrossOrigin +@RestController +@RequiredArgsConstructor +@RequestMapping("Group") +public class GroupAccessController { + + private final GroupAccessService groupAccessService; + + @PostMapping("canAccess") + public boolean canAccess(@Nullable final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) { + return groupAccessService.canAccess(privateUuid, groupUuid); + } + +} diff --git a/src/main/java/de/ph87/tools/group/GroupAccessService.java b/src/main/java/de/ph87/tools/group/GroupAccessService.java index 5072d51..0705652 100644 --- a/src/main/java/de/ph87/tools/group/GroupAccessService.java +++ b/src/main/java/de/ph87/tools/group/GroupAccessService.java @@ -1,7 +1,6 @@ package de.ph87.tools.group; 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.uuid.UserPrivateUuid; @@ -24,8 +23,6 @@ public class GroupAccessService { private final UserService userService; - private final NumbersRepository numbersRepository; - public boolean canAccess(@Nullable final UserPrivateUuid userPrivateUuid, @NonNull final GroupUuid groupUuid) { final User user = userService.accessOrNull(userPrivateUuid); if (user == null) { @@ -35,13 +32,6 @@ public class GroupAccessService { return group.getUsers().contains(user); } - public void delete(@NonNull final UserPrivateUuid userPrivateUuid, @NonNull final GroupUuid groupUuid) { - final GroupAccess groupAccess = adminAccess(userPrivateUuid, groupUuid); - numbersRepository.deleteAllByGroup(groupAccess.group); - groupRepository.delete(groupAccess.group); - log.info("Group deleted: group={}", groupAccess.group); - } - @NonNull public GroupAccess access(@NonNull final UserPrivateUuid userPrivateUuid, @NonNull final GroupUuid groupUuid) { final User user = userService.access(userPrivateUuid); @@ -50,7 +40,7 @@ public class GroupAccessService { } @NonNull - public GroupAccess adminAccess(@NonNull final UserPrivateUuid userPrivateUuid, @NonNull final GroupUuid groupUuid) { + public GroupAccess ownerAccess(@NonNull final UserPrivateUuid userPrivateUuid, @NonNull final GroupUuid groupUuid) { final GroupAccess groupAccess = access(userPrivateUuid, groupUuid); if (!groupAccess.group.isOwnedBy(groupAccess.user)) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST); diff --git a/src/main/java/de/ph87/tools/group/GroupController.java b/src/main/java/de/ph87/tools/group/GroupController.java deleted file mode 100644 index 1015cdf..0000000 --- a/src/main/java/de/ph87/tools/group/GroupController.java +++ /dev/null @@ -1,95 +0,0 @@ -package de.ph87.tools.group; - -import de.ph87.tools.group.requests.GroupChangePasswordRequest; -import de.ph87.tools.group.requests.GroupChangeTitleRequest; -import de.ph87.tools.group.requests.GroupJoinRequest; -import de.ph87.tools.group.requests.GroupUserRequest; -import de.ph87.tools.group.uuid.GroupUuid; -import de.ph87.tools.user.uuid.UserPrivateUuid; -import de.ph87.tools.user.uuid.UserPublicUuid; -import jakarta.annotation.Nullable; -import jakarta.servlet.http.HttpServletResponse; -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.*; - -import java.util.Set; - -@CrossOrigin -@RestController -@RequiredArgsConstructor -@RequestMapping("Group") -public class GroupController { - - private final GroupService groupService; - - private final GroupAccessService groupAccessService; - - @GetMapping("create") - public GroupDto create(@Nullable final UserPrivateUuid privateUuid, @NonNull final HttpServletResponse response) { - return groupService.create(privateUuid, response); - } - - @PostMapping("canAccess") - public boolean canAccess(@Nullable final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) { - return groupAccessService.canAccess(privateUuid, groupUuid); - } - - @PostMapping("delete") - public void delete(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) { - groupAccessService.delete(privateUuid, groupUuid); - } - - @PostMapping("get") - public GroupDto get(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) { - return groupService.get(privateUuid, groupUuid); - } - - @NonNull - @GetMapping("findAllJoined") - public Set findAllJoined(@NonNull final UserPrivateUuid userUuid) { - return groupService.findAllJoined(userUuid); - } - - @NonNull - @PostMapping("findAllCommon") - public Set findAllCommon(@NonNull final UserPrivateUuid userUuid, @NonNull final UserPublicUuid targetUuid) { - return groupService.findAllCommon(userUuid, targetUuid); - } - - @PostMapping("join") - public GroupDto join(@Nullable final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupJoinRequest request, @NonNull final HttpServletResponse response) { - return groupService.join(privateUuid, request, response); - } - - @PostMapping("kick") - public void kick(@NonNull final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupUserRequest request) { - groupService.kick(privateUuid, request); - } - - @PostMapping("ban") - public void ban(@NonNull final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupUserRequest request) { - groupService.ban(privateUuid, request); - } - - @PostMapping("unban") - public void unban(@NonNull final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupUserRequest request) { - groupService.unban(privateUuid, request); - } - - @PostMapping("changeTitle") - public GroupDto changeTitle(@NonNull final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupChangeTitleRequest request) { - return groupService.changeTitle(privateUuid, request); - } - - @PostMapping("changePassword") - public GroupDto changePassword(@NonNull final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupChangePasswordRequest request) { - return groupService.changePassword(privateUuid, request); - } - - @PostMapping("leave") - public void leave(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) { - groupService.leave(privateUuid, groupUuid); - } - -} diff --git a/src/main/java/de/ph87/tools/group/GroupMemberController.java b/src/main/java/de/ph87/tools/group/GroupMemberController.java new file mode 100644 index 0000000..4f9884c --- /dev/null +++ b/src/main/java/de/ph87/tools/group/GroupMemberController.java @@ -0,0 +1,31 @@ +package de.ph87.tools.group; + +import de.ph87.tools.group.dto.GroupDto; +import de.ph87.tools.group.requests.GroupJoinRequest; +import de.ph87.tools.group.uuid.GroupUuid; +import de.ph87.tools.user.uuid.UserPrivateUuid; +import jakarta.annotation.Nullable; +import jakarta.servlet.http.HttpServletResponse; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +@CrossOrigin +@RestController +@RequiredArgsConstructor +@RequestMapping("Group") +public class GroupMemberController { + + private final GroupMemberService groupMemberService; + + @PostMapping("join") + public GroupDto join(@Nullable final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupJoinRequest request, @NonNull final HttpServletResponse response) { + return groupMemberService.join(privateUuid, request, response); + } + + @PostMapping("leave") + public void leave(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) { + groupMemberService.leave(privateUuid, groupUuid); + } + +} diff --git a/src/main/java/de/ph87/tools/group/GroupMemberService.java b/src/main/java/de/ph87/tools/group/GroupMemberService.java new file mode 100644 index 0000000..59aca21 --- /dev/null +++ b/src/main/java/de/ph87/tools/group/GroupMemberService.java @@ -0,0 +1,71 @@ +package de.ph87.tools.group; + +import de.ph87.tools.group.dto.GroupDto; +import de.ph87.tools.group.requests.GroupJoinRequest; +import de.ph87.tools.group.uuid.GroupUuid; +import de.ph87.tools.user.User; +import de.ph87.tools.user.UserService; +import de.ph87.tools.user.uuid.UserPrivateUuid; +import jakarta.annotation.Nullable; +import jakarta.servlet.http.HttpServletResponse; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +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; + +@Slf4j +@Service +@Transactional +@RequiredArgsConstructor +public class GroupMemberService { + + private final UserService userService; + + private final GroupReadService groupReadService; + + @NonNull + public GroupDto join(@Nullable final UserPrivateUuid privateUuid, @NonNull final GroupJoinRequest request, @NonNull final HttpServletResponse response) { + final User user = userService.getUserByPrivateUuidOrElseCreate(privateUuid, response); + final Group group = groupReadService.getGroupByGroupUuid(request.groupUuid); + if (group.isBanned(user)) { + log.error("User is banned from Group and cannot join it: user={}, group={}", user, group); + throw new ResponseStatusException(HttpStatus.FORBIDDEN); + } + if (!group.getPassword().equals(request.password)) { + log.error("Wrong password: user={}, group={}", user, group); + throw new ResponseStatusException(HttpStatus.FORBIDDEN); + } + return _join_unchecked(group, user); + } + + public void leave(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) { + final User user = userService.access(privateUuid); + final Group group = groupReadService.getGroupByGroupUuid(groupUuid); + if (group.isOwnedBy(user)) { + // owner cannot remove itself from group + throw new ResponseStatusException(HttpStatus.BAD_REQUEST); + } + _leave_unchecked(group, user); + } + + @NonNull + public GroupDto _join_unchecked(@NonNull final Group group, @NonNull final User user) { + group.getUsers().add(user); + group.touch(); + user.touch(); + log.info("User joined Group: user={}, group={}", user, group); + return groupReadService.publish(group); + } + + private void _leave_unchecked(final Group group, final User user) { + group.getUsers().remove(user); + group.touch(); + user.touch(); + log.info("User left Group: user={}, group={}", user, group); + groupReadService.publish(group); + } + +} diff --git a/src/main/java/de/ph87/tools/group/GroupOwnerController.java b/src/main/java/de/ph87/tools/group/GroupOwnerController.java new file mode 100644 index 0000000..e2815df --- /dev/null +++ b/src/main/java/de/ph87/tools/group/GroupOwnerController.java @@ -0,0 +1,58 @@ +package de.ph87.tools.group; + +import de.ph87.tools.group.dto.GroupDto; +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.user.uuid.UserPrivateUuid; +import jakarta.annotation.Nullable; +import jakarta.servlet.http.HttpServletResponse; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +@CrossOrigin +@RestController +@RequiredArgsConstructor +@RequestMapping("Group") +public class GroupOwnerController { + + private final GroupOwnerService groupOwnerService; + + @GetMapping("create") + public GroupDto create(@Nullable final UserPrivateUuid privateUuid, @NonNull final HttpServletResponse response) { + return groupOwnerService.create(privateUuid, response); + } + + @PostMapping("delete") + public void delete(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) { + groupOwnerService.delete(privateUuid, groupUuid); + } + + @PostMapping("kick") + public void kick(@NonNull final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupUserRequest request) { + groupOwnerService.kick(privateUuid, request); + } + + @PostMapping("ban") + public void ban(@NonNull final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupUserRequest request) { + groupOwnerService.ban(privateUuid, request); + } + + @PostMapping("unban") + public void unban(@NonNull final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupUserRequest request) { + groupOwnerService.unban(privateUuid, request); + } + + @PostMapping("changeTitle") + public GroupDto changeTitle(@NonNull final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupChangeTitleRequest request) { + return groupOwnerService.changeTitle(privateUuid, request); + } + + @PostMapping("changePassword") + public GroupDto changePassword(@NonNull final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupChangePasswordRequest request) { + return groupOwnerService.changePassword(privateUuid, request); + } + +} diff --git a/src/main/java/de/ph87/tools/group/GroupOwnerService.java b/src/main/java/de/ph87/tools/group/GroupOwnerService.java new file mode 100644 index 0000000..92b7de8 --- /dev/null +++ b/src/main/java/de/ph87/tools/group/GroupOwnerService.java @@ -0,0 +1,141 @@ +package de.ph87.tools.group; + +import de.ph87.tools.group.dto.GroupDto; +import de.ph87.tools.group.events.GroupDeletedEvent; +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; + +@Slf4j +@Service +@Transactional +@RequiredArgsConstructor +public class GroupOwnerService { + + private final GroupAccessService groupAccessService; + + private final GroupRepository groupRepository; + + private final UserService userService; + + private final GroupReadService groupReadService; + + private final GroupMemberService groupMemberService; + + private final NumbersRepository numbersRepository; + + private final UserPushService userPushService; + + @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._join_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); + log.info("User kicked out of group: user={}, group={}", result.kicked, result.group); + groupReadService.publish(result.group); + } + + public void ban(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUserRequest request) { + final OwnerRemoveResult result = _removeUser(privateUuid, request); + result.group.getBanned().add(result.kicked); + log.info("User banned from group: user={}, group={}", result.kicked, result.group); + groupReadService.publish(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); + groupReadService.publish(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.user)) { + throw new ResponseStatusException(HttpStatus.FORBIDDEN); + } + ug.group.setTitle(request.title); + return groupReadService.publish(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 groupReadService.publish(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 GroupOwnerService.OwnerRemoveResult _removeUser(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUserRequest request) { + 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.user)) { + // owner cannot kick itself from group + throw new ResponseStatusException(HttpStatus.BAD_REQUEST); + } + access.group.getUsers().remove(user); + 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; + } + + } + +} diff --git a/src/main/java/de/ph87/tools/group/GroupReadController.java b/src/main/java/de/ph87/tools/group/GroupReadController.java new file mode 100644 index 0000000..84c794c --- /dev/null +++ b/src/main/java/de/ph87/tools/group/GroupReadController.java @@ -0,0 +1,38 @@ +package de.ph87.tools.group; + +import de.ph87.tools.group.dto.GroupDto; +import de.ph87.tools.group.uuid.GroupUuid; +import de.ph87.tools.user.uuid.UserPrivateUuid; +import de.ph87.tools.user.uuid.UserPublicUuid; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.Set; + +@CrossOrigin +@RestController +@RequiredArgsConstructor +@RequestMapping("Group") +public class GroupReadController { + + private final GroupReadService groupReadService; + + @PostMapping("get") + public GroupDto get(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) { + return groupReadService.get(privateUuid, groupUuid); + } + + @NonNull + @GetMapping("findAllJoined") + public Set findAllJoined(@NonNull final UserPrivateUuid userUuid) { + return groupReadService.findAllJoined(userUuid); + } + + @NonNull + @PostMapping("findAllCommon") + public Set findAllCommon(@NonNull final UserPrivateUuid userUuid, @NonNull final UserPublicUuid targetUuid) { + return groupReadService.findAllCommon(userUuid, targetUuid); + } + +} diff --git a/src/main/java/de/ph87/tools/group/GroupReadService.java b/src/main/java/de/ph87/tools/group/GroupReadService.java new file mode 100644 index 0000000..03b79c9 --- /dev/null +++ b/src/main/java/de/ph87/tools/group/GroupReadService.java @@ -0,0 +1,86 @@ +package de.ph87.tools.group; + +import de.ph87.tools.group.dto.GroupDto; +import de.ph87.tools.group.uuid.GroupUuid; +import de.ph87.tools.user.User; +import de.ph87.tools.user.UserPublicDto; +import de.ph87.tools.user.UserService; +import de.ph87.tools.user.push.UserPushService; +import de.ph87.tools.user.uuid.UserPrivateUuid; +import de.ph87.tools.user.uuid.UserPublicUuid; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +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.Set; +import java.util.stream.Collectors; + +@Slf4j +@Service +@Transactional +@RequiredArgsConstructor +public class GroupReadService { + + private final GroupAccessService groupAccessService; + + private final GroupRepository groupRepository; + + private final UserPushService userPushService; + + private final UserService userService; + + @NonNull + public GroupDto get(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) { + final GroupAccess ug = groupAccessService.access(privateUuid, groupUuid); + return toDto(ug.group); + } + + @NonNull + public Group getGroupByGroupUuid(@NonNull final GroupUuid groupUuid) { + return groupRepository.findByUuid(groupUuid.uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST)); + } + + /* DTO ------------------------------------------------------------------------------------------ */ + + @NonNull + public GroupDto toDto(@NonNull final Group group) { + final UserPublicDto owner = new UserPublicDto(group.getOwner()); + final Set users = group.getUsers().stream().map(UserPublicDto::new).collect(Collectors.toSet()); + final Set banned = group.getBanned().stream().map(UserPublicDto::new).collect(Collectors.toSet()); + return new GroupDto(group, owner, users, banned); + } + + /* PUBLISH -------------------------------------------------------------------------------------- */ + + @NonNull + public GroupDto publish(@NonNull final Group group) { + final GroupDto dto = toDto(group); + group.getUsers().forEach(user -> userPushService.push(user, dto)); + return dto; + } + + /* FIND & GET ----------------------------------------------------------------------------------- */ + + @NonNull + public Set findAllCommonGroups(@NonNull final User a, @NonNull final User b) { + return groupRepository.findAllByUsersContainsAndUsersContains(a, b).stream().map(this::toDto).collect(Collectors.toSet()); + } + + @NonNull + public Set findAllJoined(@NonNull final UserPrivateUuid privateUuid) { + final User principal = userService.access(privateUuid); + return groupRepository.findAllByUsersContains(principal).stream().map(this::toDto).collect(Collectors.toSet()); + } + + @NonNull + public Set findAllCommon(@NonNull final UserPrivateUuid privateUuid, @NonNull final UserPublicUuid targetUuid) { + final User principal = userService.access(privateUuid); + final User target = userService.getByPublicUuid(targetUuid); + return findAllCommonGroups(principal, target); + } + +} diff --git a/src/main/java/de/ph87/tools/group/GroupService.java b/src/main/java/de/ph87/tools/group/GroupService.java deleted file mode 100644 index 92d8867..0000000 --- a/src/main/java/de/ph87/tools/group/GroupService.java +++ /dev/null @@ -1,199 +0,0 @@ -package de.ph87.tools.group; - -import de.ph87.tools.group.requests.GroupChangePasswordRequest; -import de.ph87.tools.group.requests.GroupChangeTitleRequest; -import de.ph87.tools.group.requests.GroupJoinRequest; -import de.ph87.tools.group.requests.GroupUserRequest; -import de.ph87.tools.group.uuid.GroupUuid; -import de.ph87.tools.user.User; -import de.ph87.tools.user.UserPublicDto; -import de.ph87.tools.user.UserService; -import de.ph87.tools.user.push.UserPushService; -import de.ph87.tools.user.uuid.UserPrivateUuid; -import de.ph87.tools.user.uuid.UserPublicUuid; -import jakarta.annotation.Nullable; -import jakarta.servlet.http.HttpServletResponse; -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -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.Set; -import java.util.stream.Collectors; - -@Slf4j -@Service -@Transactional -@RequiredArgsConstructor -public class GroupService { - - private final GroupAccessService groupAccessService; - - private final GroupRepository groupRepository; - - private final UserPushService userPushService; - - private final UserService userService; - - @NonNull - public GroupDto create(@Nullable final UserPrivateUuid privateUuid, @NonNull final HttpServletResponse response) { - final User user = userService.getUserByPrivateUuidOrElseCreate(privateUuid, response); - final Group group = createUnchecked(user); - return _join_unchecked(group, user); - } - - @NonNull - public GroupDto get(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) { - final GroupAccess ug = groupAccessService.access(privateUuid, groupUuid); - return toDto(ug.group); - } - - @NonNull - public GroupDto join(@Nullable final UserPrivateUuid privateUuid, @NonNull final GroupJoinRequest request, @NonNull final HttpServletResponse response) { - final User user = userService.getUserByPrivateUuidOrElseCreate(privateUuid, response); - final Group group = getGroupByGroupUuid(request.groupUuid); - if (group.isBanned(user)) { - log.error("User is banned from Group and cannot join it: user={}, group={}", user, group); - throw new ResponseStatusException(HttpStatus.FORBIDDEN); - } - if (!group.getPassword().equals(request.password)) { - log.error("Wrong password: user={}, group={}", user, group); - throw new ResponseStatusException(HttpStatus.FORBIDDEN); - } - return _join_unchecked(group, user); - } - - public void leave(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) { - final User user = userService.access(privateUuid); - final Group group = getGroupByGroupUuid(groupUuid); - if (group.isOwnedBy(user)) { - // owner cannot remove itself from group - throw new ResponseStatusException(HttpStatus.BAD_REQUEST); - } - doLeaveUnchecked(group, user); - } - - public void kick(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUserRequest request) { - final AdminRemoveResult result = adminRemoveUser(privateUuid, request); - log.info("User kicked out of group: user={}, group={}", result.kicked, result.group); - publish(result.group); - } - - public void ban(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUserRequest request) { - final AdminRemoveResult result = adminRemoveUser(privateUuid, request); - result.group.getBanned().add(result.kicked); - log.info("User banned from group: user={}, group={}", result.kicked, result.group); - publish(result.group); - } - - public void unban(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUserRequest request) { - final GroupAccess access = groupAccessService.adminAccess(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); - publish(access.group); - } - - @NonNull - private AdminRemoveResult adminRemoveUser(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUserRequest request) { - final GroupAccess access = groupAccessService.adminAccess(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.user)) { - // owner cannot kick itself from group - throw new ResponseStatusException(HttpStatus.BAD_REQUEST); - } - access.group.getUsers().remove(user); - return new AdminRemoveResult(access, user); - } - - @NonNull - private Group getGroupByGroupUuid(@NonNull final GroupUuid groupUuid) { - return groupRepository.findByUuid(groupUuid.uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST)); - } - - @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.user)) { - throw new ResponseStatusException(HttpStatus.FORBIDDEN); - } - ug.group.setTitle(request.title); - return publish(ug.group); - } - - @NonNull - public GroupDto changePassword(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupChangePasswordRequest request) { - final GroupAccess access = groupAccessService.adminAccess(privateUuid, request.groupUuid); - access.group.setPassword(request.password); - return publish(access.group); - } - - /* CREATE, JOIN, LEAVE -------------------------------------------------------------------------- */ - - @NonNull - private Group createUnchecked(@NonNull final User user) { - final Group group = groupRepository.save(new Group(user)); - log.info("Group CREATED: {}", group); - return group; - } - - @NonNull - private GroupDto _join_unchecked(@NonNull final Group group, @NonNull final User user) { - group.getUsers().add(user); - group.touch(); - user.touch(); - log.info("User joined Group: user={}, group={}", user, group); - return publish(group); - } - - private void doLeaveUnchecked(final Group group, final User user) { - group.getUsers().remove(user); - group.touch(); - user.touch(); - log.info("User left Group: user={}, group={}", user, group); - publish(group); - } - - /* DTO ------------------------------------------------------------------------------------------ */ - - @NonNull - public GroupDto toDto(@NonNull final Group group) { - final UserPublicDto owner = new UserPublicDto(group.getOwner()); - final Set users = group.getUsers().stream().map(UserPublicDto::new).collect(Collectors.toSet()); - final Set banned = group.getBanned().stream().map(UserPublicDto::new).collect(Collectors.toSet()); - return new GroupDto(group, owner, users, banned); - } - - /* PUBLISH -------------------------------------------------------------------------------------- */ - - @NonNull - public GroupDto publish(@NonNull final Group group) { - final GroupDto dto = toDto(group); - group.getUsers().forEach(user -> userPushService.push(user, dto)); - return dto; - } - - /* FIND & GET ----------------------------------------------------------------------------------- */ - - @NonNull - public Set findAllCommonGroups(@NonNull final User a, @NonNull final User b) { - return groupRepository.findAllByUsersContainsAndUsersContains(a, b).stream().map(this::toDto).collect(Collectors.toSet()); - } - - @NonNull - public Set findAllJoined(@NonNull final UserPrivateUuid privateUuid) { - final User principal = userService.access(privateUuid); - return groupRepository.findAllByUsersContains(principal).stream().map(this::toDto).collect(Collectors.toSet()); - } - - @NonNull - public Set findAllCommon(@NonNull final UserPrivateUuid privateUuid, @NonNull final UserPublicUuid targetUuid) { - final User principal = userService.access(privateUuid); - final User target = userService.getByPublicUuid(targetUuid); - return findAllCommonGroups(principal, target); - } - -} diff --git a/src/main/java/de/ph87/tools/group/GroupDto.java b/src/main/java/de/ph87/tools/group/dto/GroupDto.java similarity index 94% rename from src/main/java/de/ph87/tools/group/GroupDto.java rename to src/main/java/de/ph87/tools/group/dto/GroupDto.java index 289f605..ad99001 100644 --- a/src/main/java/de/ph87/tools/group/GroupDto.java +++ b/src/main/java/de/ph87/tools/group/dto/GroupDto.java @@ -1,7 +1,8 @@ -package de.ph87.tools.group; +package de.ph87.tools.group.dto; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import de.ph87.tools.common.uuid.UuidSerializer; +import de.ph87.tools.group.Group; import de.ph87.tools.group.uuid.GroupUuid; import de.ph87.tools.user.UserPublicDto; import lombok.Getter; diff --git a/src/main/java/de/ph87/tools/group/events/GroupDeletedEvent.java b/src/main/java/de/ph87/tools/group/events/GroupDeletedEvent.java new file mode 100644 index 0000000..7d2312a --- /dev/null +++ b/src/main/java/de/ph87/tools/group/events/GroupDeletedEvent.java @@ -0,0 +1,19 @@ +package de.ph87.tools.group.events; + +import de.ph87.tools.group.Group; +import de.ph87.tools.group.uuid.GroupUuid; +import lombok.Getter; +import lombok.NonNull; +import lombok.ToString; + +@Getter +@ToString +public class GroupDeletedEvent { + + public final GroupUuid groupUuid; + + public GroupDeletedEvent(@NonNull final Group group) { + this.groupUuid = group.getUuid(); + } + +} diff --git a/src/main/java/de/ph87/tools/tools/numbers/NumbersDto.java b/src/main/java/de/ph87/tools/tools/numbers/NumbersDto.java index a3857c8..3c73507 100644 --- a/src/main/java/de/ph87/tools/tools/numbers/NumbersDto.java +++ b/src/main/java/de/ph87/tools/tools/numbers/NumbersDto.java @@ -2,7 +2,7 @@ package de.ph87.tools.tools.numbers; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import de.ph87.tools.common.uuid.UuidSerializer; -import de.ph87.tools.group.GroupDto; +import de.ph87.tools.group.dto.GroupDto; import de.ph87.tools.tools.numbers.uuid.NumbersAbstract; import de.ph87.tools.tools.numbers.uuid.NumbersUuid; import jakarta.annotation.Nullable; diff --git a/src/main/java/de/ph87/tools/tools/numbers/NumbersService.java b/src/main/java/de/ph87/tools/tools/numbers/NumbersService.java index 6bb7b44..6f0ba22 100644 --- a/src/main/java/de/ph87/tools/tools/numbers/NumbersService.java +++ b/src/main/java/de/ph87/tools/tools/numbers/NumbersService.java @@ -2,8 +2,8 @@ package de.ph87.tools.tools.numbers; import de.ph87.tools.group.GroupAccess; import de.ph87.tools.group.GroupAccessService; -import de.ph87.tools.group.GroupDto; -import de.ph87.tools.group.GroupService; +import de.ph87.tools.group.dto.GroupDto; +import de.ph87.tools.group.GroupReadService; import de.ph87.tools.group.uuid.GroupUuid; import de.ph87.tools.tools.numbers.uuid.NumbersUuid; import de.ph87.tools.user.User; @@ -41,14 +41,14 @@ public class NumbersService { private final UserReferenceService userReferenceService; - private final GroupService groupService; + private final GroupReadService groupReadService; private final UserPushService userPushService; private final UserService userService; public void create(@NonNull final UserPrivateUuid userPrivateUuid, @NonNull final GroupUuid groupUuid) { - final GroupAccess access = groupAccessService.adminAccess(userPrivateUuid, groupUuid); + final GroupAccess access = groupAccessService.ownerAccess(userPrivateUuid, groupUuid); final List users = access.getGroup().getUsers().stream().map(userReferenceService::create).collect(Collectors.toList()); Collections.shuffle(users); final Numbers numbers = numbersRepository.save(new Numbers(access.getGroup(), users)); @@ -71,7 +71,7 @@ public class NumbersService { @NonNull public NumbersDto toDto(@NonNull final Numbers numbers, @NonNull final User user) { - final GroupDto group = groupService.toDto(numbers.getGroup()); + final GroupDto group = groupReadService.toDto(numbers.getGroup()); final Integer number = numbers.getNumberForUser(user); return new NumbersDto(numbers, group, number); }