From a1e3a4353dca9c59b3bafeb1b077705f126a0a7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20Ha=C3=9Fel?= Date: Wed, 6 Nov 2024 14:40:27 +0100 Subject: [PATCH] NumbersLot --- .../src/app/api/tools/Numbers/Numbers.ts | 18 ++-- .../src/app/api/tools/Numbers/NumbersLot.ts | 20 +++++ .../app/api/tools/Numbers/numbers.service.ts | 4 +- .../pages/group/group/group.component.html | 4 +- .../app/pages/group/group/group.component.ts | 7 +- .../app/pages/profile/profile.component.ts | 7 +- .../tools/numbers/numbers.component.html | 2 +- .../pages/tools/numbers/numbers.component.ts | 2 +- src/main/java/de/ph87/tools/group/Group.java | 2 +- ...adController.java => GroupController.java} | 10 +-- ...roupReadService.java => GroupService.java} | 4 +- .../tools/group/{ => access}/GroupAccess.java | 5 +- .../{ => access}/GroupAccessController.java | 2 +- .../{ => access}/GroupAccessService.java | 6 +- .../{ => member}/GroupMemberController.java | 2 +- .../{ => member}/GroupMemberService.java | 11 ++- .../{ => owner}/GroupOwnerController.java | 2 +- .../group/{ => owner}/GroupOwnerService.java | 12 ++- .../de/ph87/tools/tools/numbers/Numbers.java | 43 +++------ .../tools/tools/numbers/NumbersAccess.java | 11 ++- .../tools/numbers/NumbersController.java | 6 +- .../ph87/tools/tools/numbers/NumbersDto.java | 25 +++--- .../tools/numbers/NumbersRepository.java | 4 - .../tools/tools/numbers/NumbersService.java | 89 ++++++++----------- .../tools/tools/numbers/lot/NumberLot.java | 37 ++++++++ .../tools/tools/numbers/lot/NumberLotDto.java | 25 ++++++ 26 files changed, 218 insertions(+), 142 deletions(-) create mode 100644 src/main/angular/src/app/api/tools/Numbers/NumbersLot.ts rename src/main/java/de/ph87/tools/group/{GroupReadController.java => GroupController.java} (76%) rename src/main/java/de/ph87/tools/group/{GroupReadService.java => GroupService.java} (94%) rename src/main/java/de/ph87/tools/group/{ => access}/GroupAccess.java (54%) rename src/main/java/de/ph87/tools/group/{ => access}/GroupAccessController.java (95%) rename src/main/java/de/ph87/tools/group/{ => access}/GroupAccessService.java (91%) rename src/main/java/de/ph87/tools/group/{ => member}/GroupMemberController.java (96%) rename src/main/java/de/ph87/tools/group/{ => member}/GroupMemberService.java (89%) rename src/main/java/de/ph87/tools/group/{ => owner}/GroupOwnerController.java (98%) rename src/main/java/de/ph87/tools/group/{ => owner}/GroupOwnerService.java (93%) create mode 100644 src/main/java/de/ph87/tools/tools/numbers/lot/NumberLot.java create mode 100644 src/main/java/de/ph87/tools/tools/numbers/lot/NumberLotDto.java diff --git a/src/main/angular/src/app/api/tools/Numbers/Numbers.ts b/src/main/angular/src/app/api/tools/Numbers/Numbers.ts index 5c82fd6..859025c 100644 --- a/src/main/angular/src/app/api/tools/Numbers/Numbers.ts +++ b/src/main/angular/src/app/api/tools/Numbers/Numbers.ts @@ -1,14 +1,15 @@ import {Group} from "../../group/Group"; -import {validateDate, validateDateOrNull, validateNumberOrNull, validateString} from "../../common/validators"; +import {validateDate, validateList, validateString} from "../../common/validators"; +import {NumbersLot} from "./NumbersLot"; +import {UserPrivate} from "../../User/UserPrivate"; export class Numbers { constructor( readonly uuid: string, - readonly group: Group, readonly date: Date, - readonly read: Date | null, - readonly number: number | null, + readonly lots: NumbersLot[], + readonly group: Group, ) { // - } @@ -16,11 +17,14 @@ export class Numbers { static fromJson(json: any): Numbers { return new Numbers( validateString(json['uuid']), - Group.fromJson(json['group']), validateDate(json['date']), - validateDateOrNull(json['read']), - validateNumberOrNull(json['number']), + validateList(json['lots'], NumbersLot.fromJson), + Group.fromJson(json['group']), ); } + getMine(user: UserPrivate | null): NumbersLot | null { + return this.lots.filter(u => u.user.is(user))[0]; + } + } diff --git a/src/main/angular/src/app/api/tools/Numbers/NumbersLot.ts b/src/main/angular/src/app/api/tools/Numbers/NumbersLot.ts new file mode 100644 index 0000000..42a0b8f --- /dev/null +++ b/src/main/angular/src/app/api/tools/Numbers/NumbersLot.ts @@ -0,0 +1,20 @@ +import {UserPublic} from "../../User/UserPublic"; +import {validateNumberOrNull} from "../../common/validators"; + +export class NumbersLot { + + constructor( + readonly user: UserPublic, + readonly number: number | null, + ) { + // - + } + + static fromJson(json: any): NumbersLot { + return new NumbersLot( + UserPublic.fromJson(json['user']), + validateNumberOrNull(json['number']), + ); + } + +} diff --git a/src/main/angular/src/app/api/tools/Numbers/numbers.service.ts b/src/main/angular/src/app/api/tools/Numbers/numbers.service.ts index db4e818..cd51a2d 100644 --- a/src/main/angular/src/app/api/tools/Numbers/numbers.service.ts +++ b/src/main/angular/src/app/api/tools/Numbers/numbers.service.ts @@ -28,8 +28,8 @@ export class NumbersService { this.api.getPage(['Numbers', 'page', groupUuid, page, pageSize], Numbers.fromJson, next); } - fetchAndMarkAsRead(numbersUuid: string, next: Next): void { - this.api.postSingle(['Numbers', 'fetchAndMarkAsRead'], numbersUuid, Numbers.fromJson, next); + byUuid(numbersUuid: string, next: Next): void { + this.api.postSingle(['Numbers', 'byUuid'], numbersUuid, Numbers.fromJson, next); } canAccess(numbersUuid: string, next: Next): void { diff --git a/src/main/angular/src/app/pages/group/group/group.component.html b/src/main/angular/src/app/pages/group/group/group.component.html index f654c73..e61b43f 100644 --- a/src/main/angular/src/app/pages/group/group/group.component.html +++ b/src/main/angular/src/app/pages/group/group/group.component.html @@ -118,9 +118,9 @@
- + - +
{{ numbers.date | relative:now }}{{ numbers.number || '-' }}{{ numbers.getMine(userService.user)?.number || '-' }}
diff --git a/src/main/angular/src/app/pages/group/group/group.component.ts b/src/main/angular/src/app/pages/group/group/group.component.ts index 4dbdddf..59887b8 100644 --- a/src/main/angular/src/app/pages/group/group/group.component.ts +++ b/src/main/angular/src/app/pages/group/group/group.component.ts @@ -95,10 +95,10 @@ export class GroupComponent implements OnInit, OnDestroy { ngOnDestroy(): void { this.subs.forEach(sub => sub.unsubscribe()); - this.subs.length=0; + this.subs.length = 0; this.userSubs.forEach(sub => sub.unsubscribe()); - this.userSubs.length=0; + this.userSubs.length = 0; } private setGroup(group: Group) { @@ -107,6 +107,9 @@ export class GroupComponent implements OnInit, OnDestroy { this.userSubs.length = 0; if (this.group !== null) { this.group.users.forEach(_ => this.userSubs.push(this.userService.subscribePush(UserPublic, u => this.updateUser(u)))); + this.updateNumbersList(); + } else { + this.numbersList = Page.EMPTY; } } diff --git a/src/main/angular/src/app/pages/profile/profile.component.ts b/src/main/angular/src/app/pages/profile/profile.component.ts index 2659b69..2ffb569 100644 --- a/src/main/angular/src/app/pages/profile/profile.component.ts +++ b/src/main/angular/src/app/pages/profile/profile.component.ts @@ -51,8 +51,9 @@ export class ProfileComponent implements OnInit, OnDestroy { } ngOnInit(): void { + this.updateGroupList(); this.subs.push(this.userService.subscribePush(UserPrivate, _ => { - this.groupService.findAllJoined(groups => this.groups = groups); + this.updateGroupList(); })); } @@ -61,6 +62,10 @@ export class ProfileComponent implements OnInit, OnDestroy { this.subs.length = 0; } + private updateGroupList() { + this.groupService.findAllJoined(groups => this.groups = groups); + } + protected nameValidator(name: string): boolean { return name.length >= USER_NAME_MIN_LENGTH && !/\s+|^[^a-zA-Z0-9]+$/.test(name); } diff --git a/src/main/angular/src/app/pages/tools/numbers/numbers.component.html b/src/main/angular/src/app/pages/tools/numbers/numbers.component.html index 26fc34f..322b07a 100644 --- a/src/main/angular/src/app/pages/tools/numbers/numbers.component.html +++ b/src/main/angular/src/app/pages/tools/numbers/numbers.component.html @@ -10,7 +10,7 @@
- {{ numbers.number || '-' }} + {{ numbers.getMine(userService.user)?.number || '-' }}
diff --git a/src/main/angular/src/app/pages/tools/numbers/numbers.component.ts b/src/main/angular/src/app/pages/tools/numbers/numbers.component.ts index 9e86b92..fc18bfc 100644 --- a/src/main/angular/src/app/pages/tools/numbers/numbers.component.ts +++ b/src/main/angular/src/app/pages/tools/numbers/numbers.component.ts @@ -46,7 +46,7 @@ export class NumbersComponent implements OnInit, OnDestroy { if (uuid) { this.numbersService.canAccess(uuid, granted => { if (granted) { - this.numbersService.fetchAndMarkAsRead(uuid, numbers => this.numbers = numbers); + this.numbersService.byUuid(uuid, numbers => this.numbers = numbers); } else { this.numbersService.getGroupUuid(uuid, groupUuid => this.groupService.goto(groupUuid)); } diff --git a/src/main/java/de/ph87/tools/group/Group.java b/src/main/java/de/ph87/tools/group/Group.java index 17ec5ca..25c34d1 100644 --- a/src/main/java/de/ph87/tools/group/Group.java +++ b/src/main/java/de/ph87/tools/group/Group.java @@ -79,7 +79,7 @@ public class Group extends GroupAbstract implements IWebSocketMessage { @Column(nullable = false) private ZonedDateTime lastAccess = created; - protected Group(@NonNull final User owner) { + public Group(@NonNull final User owner) { this.owner = owner; } diff --git a/src/main/java/de/ph87/tools/group/GroupReadController.java b/src/main/java/de/ph87/tools/group/GroupController.java similarity index 76% rename from src/main/java/de/ph87/tools/group/GroupReadController.java rename to src/main/java/de/ph87/tools/group/GroupController.java index 84c794c..fa7e14a 100644 --- a/src/main/java/de/ph87/tools/group/GroupReadController.java +++ b/src/main/java/de/ph87/tools/group/GroupController.java @@ -14,25 +14,25 @@ import java.util.Set; @RestController @RequiredArgsConstructor @RequestMapping("Group") -public class GroupReadController { +public class GroupController { - private final GroupReadService groupReadService; + private final GroupService groupService; @PostMapping("get") public GroupDto get(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) { - return groupReadService.get(privateUuid, groupUuid); + return groupService.get(privateUuid, groupUuid); } @NonNull @GetMapping("findAllJoined") public Set findAllJoined(@NonNull final UserPrivateUuid userUuid) { - return groupReadService.findAllJoined(userUuid); + return groupService.findAllJoined(userUuid); } @NonNull @PostMapping("findAllCommon") public Set findAllCommon(@NonNull final UserPrivateUuid userUuid, @NonNull final UserPublicUuid targetUuid) { - return groupReadService.findAllCommon(userUuid, targetUuid); + return groupService.findAllCommon(userUuid, targetUuid); } } diff --git a/src/main/java/de/ph87/tools/group/GroupReadService.java b/src/main/java/de/ph87/tools/group/GroupService.java similarity index 94% rename from src/main/java/de/ph87/tools/group/GroupReadService.java rename to src/main/java/de/ph87/tools/group/GroupService.java index e2cb0b1..2ddfc3c 100644 --- a/src/main/java/de/ph87/tools/group/GroupReadService.java +++ b/src/main/java/de/ph87/tools/group/GroupService.java @@ -1,5 +1,7 @@ package de.ph87.tools.group; +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.uuid.GroupUuid; import de.ph87.tools.user.User; @@ -22,7 +24,7 @@ import java.util.stream.Collectors; @Service @Transactional @RequiredArgsConstructor -public class GroupReadService { +public class GroupService { private final GroupAccessService groupAccessService; diff --git a/src/main/java/de/ph87/tools/group/GroupAccess.java b/src/main/java/de/ph87/tools/group/access/GroupAccess.java similarity index 54% rename from src/main/java/de/ph87/tools/group/GroupAccess.java rename to src/main/java/de/ph87/tools/group/access/GroupAccess.java index d5bd1ec..972ac6e 100644 --- a/src/main/java/de/ph87/tools/group/GroupAccess.java +++ b/src/main/java/de/ph87/tools/group/access/GroupAccess.java @@ -1,12 +1,13 @@ -package de.ph87.tools.group; +package de.ph87.tools.group.access; +import de.ph87.tools.group.Group; import de.ph87.tools.user.User; import lombok.Data; @Data public class GroupAccess { - public final User user; + public final User principal; public final Group group; diff --git a/src/main/java/de/ph87/tools/group/GroupAccessController.java b/src/main/java/de/ph87/tools/group/access/GroupAccessController.java similarity index 95% rename from src/main/java/de/ph87/tools/group/GroupAccessController.java rename to src/main/java/de/ph87/tools/group/access/GroupAccessController.java index 7a5bcac..824a895 100644 --- a/src/main/java/de/ph87/tools/group/GroupAccessController.java +++ b/src/main/java/de/ph87/tools/group/access/GroupAccessController.java @@ -1,4 +1,4 @@ -package de.ph87.tools.group; +package de.ph87.tools.group.access; import de.ph87.tools.group.uuid.GroupUuid; import de.ph87.tools.user.uuid.UserPrivateUuid; diff --git a/src/main/java/de/ph87/tools/group/GroupAccessService.java b/src/main/java/de/ph87/tools/group/access/GroupAccessService.java similarity index 91% rename from src/main/java/de/ph87/tools/group/GroupAccessService.java rename to src/main/java/de/ph87/tools/group/access/GroupAccessService.java index 0e67de4..99d4ee6 100644 --- a/src/main/java/de/ph87/tools/group/GroupAccessService.java +++ b/src/main/java/de/ph87/tools/group/access/GroupAccessService.java @@ -1,5 +1,7 @@ -package de.ph87.tools.group; +package de.ph87.tools.group.access; +import de.ph87.tools.group.Group; +import de.ph87.tools.group.GroupRepository; import de.ph87.tools.group.uuid.GroupUuid; import de.ph87.tools.user.User; import de.ph87.tools.user.UserAccessService; @@ -42,7 +44,7 @@ public class GroupAccessService { @NonNull public GroupAccess ownerAccess(@NonNull final UserPrivateUuid userPrivateUuid, @NonNull final GroupUuid groupUuid) { final GroupAccess groupAccess = access(userPrivateUuid, groupUuid); - if (!groupAccess.group.isOwnedBy(groupAccess.user)) { + if (!groupAccess.group.isOwnedBy(groupAccess.principal)) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST); } return groupAccess; diff --git a/src/main/java/de/ph87/tools/group/GroupMemberController.java b/src/main/java/de/ph87/tools/group/member/GroupMemberController.java similarity index 96% rename from src/main/java/de/ph87/tools/group/GroupMemberController.java rename to src/main/java/de/ph87/tools/group/member/GroupMemberController.java index 4f9884c..9fcaa1d 100644 --- a/src/main/java/de/ph87/tools/group/GroupMemberController.java +++ b/src/main/java/de/ph87/tools/group/member/GroupMemberController.java @@ -1,4 +1,4 @@ -package de.ph87.tools.group; +package de.ph87.tools.group.member; import de.ph87.tools.group.dto.GroupDto; import de.ph87.tools.group.requests.GroupJoinRequest; diff --git a/src/main/java/de/ph87/tools/group/GroupMemberService.java b/src/main/java/de/ph87/tools/group/member/GroupMemberService.java similarity index 89% rename from src/main/java/de/ph87/tools/group/GroupMemberService.java rename to src/main/java/de/ph87/tools/group/member/GroupMemberService.java index 1de828a..c742f63 100644 --- a/src/main/java/de/ph87/tools/group/GroupMemberService.java +++ b/src/main/java/de/ph87/tools/group/member/GroupMemberService.java @@ -1,5 +1,8 @@ -package de.ph87.tools.group; +package de.ph87.tools.group.member; +import de.ph87.tools.group.Group; +import de.ph87.tools.group.GroupMapper; +import de.ph87.tools.group.GroupService; import de.ph87.tools.group.dto.GroupDto; import de.ph87.tools.group.events.GroupLeftEvent; import de.ph87.tools.group.requests.GroupJoinRequest; @@ -29,7 +32,7 @@ public class GroupMemberService { private final UserService userService; - private final GroupReadService groupReadService; + private final GroupService groupService; private final UserPushService userPushService; @@ -40,7 +43,7 @@ public class GroupMemberService { @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); + final Group group = groupService.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); @@ -54,7 +57,7 @@ public class GroupMemberService { public void leave(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) { final User user = userAccessService.access(privateUuid); - final Group group = groupReadService.getGroupByGroupUuid(groupUuid); + final Group group = groupService.getGroupByGroupUuid(groupUuid); if (group.isOwnedBy(user)) { // owner cannot remove itself from group throw new ResponseStatusException(HttpStatus.BAD_REQUEST); diff --git a/src/main/java/de/ph87/tools/group/GroupOwnerController.java b/src/main/java/de/ph87/tools/group/owner/GroupOwnerController.java similarity index 98% rename from src/main/java/de/ph87/tools/group/GroupOwnerController.java rename to src/main/java/de/ph87/tools/group/owner/GroupOwnerController.java index e2815df..3ad403f 100644 --- a/src/main/java/de/ph87/tools/group/GroupOwnerController.java +++ b/src/main/java/de/ph87/tools/group/owner/GroupOwnerController.java @@ -1,4 +1,4 @@ -package de.ph87.tools.group; +package de.ph87.tools.group.owner; import de.ph87.tools.group.dto.GroupDto; import de.ph87.tools.group.requests.GroupChangePasswordRequest; diff --git a/src/main/java/de/ph87/tools/group/GroupOwnerService.java b/src/main/java/de/ph87/tools/group/owner/GroupOwnerService.java similarity index 93% rename from src/main/java/de/ph87/tools/group/GroupOwnerService.java rename to src/main/java/de/ph87/tools/group/owner/GroupOwnerService.java index bf6dd55..88e0c84 100644 --- a/src/main/java/de/ph87/tools/group/GroupOwnerService.java +++ b/src/main/java/de/ph87/tools/group/owner/GroupOwnerService.java @@ -1,7 +1,13 @@ -package de.ph87.tools.group; +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; @@ -84,7 +90,7 @@ public class GroupOwnerService { @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)) { + if (!ug.group.isOwnedBy(ug.principal)) { throw new ResponseStatusException(HttpStatus.FORBIDDEN); } ug.group.setTitle(request.title); @@ -111,7 +117,7 @@ public class GroupOwnerService { 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.user)) { + if (user.equals(access.principal)) { // owner cannot kick itself from group throw new ResponseStatusException(HttpStatus.BAD_REQUEST); } diff --git a/src/main/java/de/ph87/tools/tools/numbers/Numbers.java b/src/main/java/de/ph87/tools/tools/numbers/Numbers.java index 14233ac..59a48ac 100644 --- a/src/main/java/de/ph87/tools/tools/numbers/Numbers.java +++ b/src/main/java/de/ph87/tools/tools/numbers/Numbers.java @@ -1,16 +1,15 @@ package de.ph87.tools.tools.numbers; import de.ph87.tools.group.Group; +import de.ph87.tools.tools.numbers.lot.NumberLot; import de.ph87.tools.tools.numbers.uuid.NumbersAbstract; import de.ph87.tools.tools.numbers.uuid.NumbersUuid; import de.ph87.tools.user.User; -import jakarta.annotation.Nullable; import jakarta.persistence.*; import lombok.*; import java.time.ZonedDateTime; -import java.util.List; -import java.util.UUID; +import java.util.*; @Entity @Getter @@ -44,40 +43,22 @@ public class Numbers extends NumbersAbstract { @Column(nullable = false) private ZonedDateTime date = ZonedDateTime.now(); - @Column - @Nullable - private ZonedDateTime read = null; - @NonNull - @ManyToMany - @OrderColumn - private List users; + @ElementCollection + private List lots = new ArrayList<>(); - public Numbers(@NonNull final Group group, @NonNull final List users) { + public Numbers(@NonNull final Group group) { this.group = group; - this.users = users; + createRandomLots(group.getUsers()); } - public void setRead(@NonNull final ZonedDateTime date) { - if (this.read != null) { - throw new RuntimeException(); + private void createRandomLots(@NonNull final Set users) { + lots.clear(); + final List shuffledUsers = new ArrayList<>(users); + Collections.shuffle(shuffledUsers); + for (int index = 0; index < shuffledUsers.size(); index++) { + lots.add(new NumberLot(shuffledUsers.get(index), index + 1)); } - this.read = date; - } - - @Nullable - public Integer getNumberForUser(@NonNull final User user) { - for (int index = 0; index < users.size(); index++) { - final User userAtIndex = users.get(index); - if (user.equals(userAtIndex)) { - return index + 1; - } - } - return null; - } - - public boolean containsUser(@NonNull final User user) { - return users.stream().anyMatch(user::equals); } } diff --git a/src/main/java/de/ph87/tools/tools/numbers/NumbersAccess.java b/src/main/java/de/ph87/tools/tools/numbers/NumbersAccess.java index a11e424..ced282d 100644 --- a/src/main/java/de/ph87/tools/tools/numbers/NumbersAccess.java +++ b/src/main/java/de/ph87/tools/tools/numbers/NumbersAccess.java @@ -2,19 +2,22 @@ package de.ph87.tools.tools.numbers; import de.ph87.tools.user.User; import lombok.Getter; +import lombok.NonNull; import lombok.ToString; @Getter @ToString -class NumbersAccess { +public class NumbersAccess { + @NonNull public final Numbers numbers; - public final User user; + @NonNull + public final User principal; - public NumbersAccess(final Numbers numbers, final User user) { + public NumbersAccess(@NonNull final User principal, @NonNull final Numbers numbers) { this.numbers = numbers; - this.user = user; + this.principal = principal; } } diff --git a/src/main/java/de/ph87/tools/tools/numbers/NumbersController.java b/src/main/java/de/ph87/tools/tools/numbers/NumbersController.java index 748752a..d1cebdd 100644 --- a/src/main/java/de/ph87/tools/tools/numbers/NumbersController.java +++ b/src/main/java/de/ph87/tools/tools/numbers/NumbersController.java @@ -41,9 +41,9 @@ public class NumbersController { } @NonNull - @PostMapping("fetchAndMarkAsRead") - public NumbersDto fetchAndMarkAsRead(@NonNull final UserPrivateUuid privateUuid, final NumbersUuid numbersUuid) { - return numbersService.fetchAndMarkAsRead(privateUuid, numbersUuid); + @PostMapping("byUuid") + public NumbersDto byUuid(@NonNull final UserPrivateUuid privateUuid, final NumbersUuid numbersUuid) { + return numbersService.byUuid(privateUuid, numbersUuid); } } 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 3c73507..debc5d8 100644 --- a/src/main/java/de/ph87/tools/tools/numbers/NumbersDto.java +++ b/src/main/java/de/ph87/tools/tools/numbers/NumbersDto.java @@ -3,14 +3,16 @@ 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.dto.GroupDto; +import de.ph87.tools.tools.numbers.lot.NumberLotDto; import de.ph87.tools.tools.numbers.uuid.NumbersAbstract; import de.ph87.tools.tools.numbers.uuid.NumbersUuid; -import jakarta.annotation.Nullable; +import jakarta.persistence.ElementCollection; import lombok.Getter; import lombok.NonNull; import lombok.ToString; import java.time.ZonedDateTime; +import java.util.List; @Getter @ToString(callSuper = true) @@ -20,24 +22,21 @@ public class NumbersDto extends NumbersAbstract { @JsonSerialize(using = UuidSerializer.class) private final NumbersUuid uuid; - @NonNull - private final GroupDto group; - @NonNull private final ZonedDateTime date; - @Nullable - private final ZonedDateTime read; + @NonNull + @ElementCollection + private final List lots; - @Nullable - private final Integer number; + @NonNull + private final GroupDto group; - public NumbersDto(@NonNull final Numbers numbers, @NonNull final GroupDto group, @Nullable final Integer number) { - this.uuid = numbers.getUuid(); - this.date = numbers.getDate(); - this.read = numbers.getRead(); + public NumbersDto(@NonNull final NumbersAccess lotAccess, @NonNull final GroupDto group) { + this.uuid = lotAccess.numbers.getUuid(); + this.date = lotAccess.numbers.getDate(); + this.lots = lotAccess.numbers.getLots().stream().map(lot -> new NumberLotDto(lot, lotAccess.principal)).toList(); this.group = group; - this.number = number; } } diff --git a/src/main/java/de/ph87/tools/tools/numbers/NumbersRepository.java b/src/main/java/de/ph87/tools/tools/numbers/NumbersRepository.java index fa97e8d..06ec9df 100644 --- a/src/main/java/de/ph87/tools/tools/numbers/NumbersRepository.java +++ b/src/main/java/de/ph87/tools/tools/numbers/NumbersRepository.java @@ -6,8 +6,6 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.repository.ListCrudRepository; -import java.util.List; - public interface NumbersRepository extends ListCrudRepository { @NonNull @@ -15,6 +13,4 @@ public interface NumbersRepository extends ListCrudRepository { void deleteAllByGroup(@NonNull Group group); - List findAllByGroupAndReadNull(@NonNull Group group); - } 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 0ade3cc..88e72ab 100644 --- a/src/main/java/de/ph87/tools/tools/numbers/NumbersService.java +++ b/src/main/java/de/ph87/tools/tools/numbers/NumbersService.java @@ -1,7 +1,7 @@ package de.ph87.tools.tools.numbers; -import de.ph87.tools.group.GroupAccess; -import de.ph87.tools.group.GroupAccessService; +import de.ph87.tools.group.access.GroupAccess; +import de.ph87.tools.group.access.GroupAccessService; import de.ph87.tools.group.GroupMapper; import de.ph87.tools.group.dto.GroupDto; import de.ph87.tools.group.uuid.GroupUuid; @@ -21,10 +21,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.server.ResponseStatusException; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; import java.util.Objects; @Slf4j @@ -45,36 +41,13 @@ public class NumbersService { public void create(@NonNull final UserPrivateUuid userPrivateUuid, @NonNull final GroupUuid groupUuid) { final GroupAccess access = groupAccessService.ownerAccess(userPrivateUuid, groupUuid); - final List users = new ArrayList<>(access.getGroup().getUsers()); - Collections.shuffle(users); - final Numbers numbers = numbersRepository.save(new Numbers(access.getGroup(), users)); - publish(numbers); - } - - private void publish(@NonNull final Numbers numbers) { - numbers.getUsers() - .stream() - .filter(Objects::nonNull) - .forEach(user -> publish(numbers, user)); - } - - private void publish(@NonNull final Numbers numbers, @NonNull final User user) { - final NumbersDto dto = toDto(numbers, user); - log.debug("Sending event: {}", dto); - userPushService.push(user, dto); - } - - @NonNull - public NumbersDto toDto(@NonNull final Numbers numbers, @NonNull final User user) { - final GroupDto group = groupMapper.toDto(numbers.getGroup()); - final Integer number = numbers.getNumberForUser(user); - return new NumbersDto(numbers, group, number); + final Numbers numbers = numbersRepository.save(new Numbers(access.group)); + pushAllLots(numbers); } public boolean canAccess(@NonNull final UserPrivateUuid privateUuid, @NonNull final NumbersUuid numbersUuid) { - final User user = userAccessService.access(privateUuid); - final Numbers numbers = numbersRepository.findById(numbersUuid.uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST)); - return numbers.containsUser(user); + final NumbersAccess access = access(privateUuid, numbersUuid); + return access.numbers.getGroup().getUsers().contains(access.principal); } @NonNull @@ -84,28 +57,44 @@ public class NumbersService { } @NonNull - public NumbersDto fetchAndMarkAsRead(@NonNull final UserPrivateUuid privateUuid, @NonNull final NumbersUuid numbersUuid) { - final NumbersAccess access = access(privateUuid, numbersUuid); - final ZonedDateTime now = ZonedDateTime.now(); - numbersRepository.findAllByGroupAndReadNull(access.numbers.getGroup()).forEach(numbers -> numbers.setRead(now)); - return toDto(access.numbers, access.user); - } - - @NonNull - private NumbersAccess access(@NonNull final UserPrivateUuid privateUuid, @NonNull final NumbersUuid numbersUuid) { - final User user = userAccessService.access(privateUuid); - final Numbers numbers = numbersRepository.findById(numbersUuid.uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST)); - if (!numbers.containsUser(user)) { - throw new ResponseStatusException(HttpStatus.BAD_REQUEST); - } - return new NumbersAccess(numbers, user); + public NumbersDto byUuid(@NonNull final UserPrivateUuid privateUuid, @NonNull final NumbersUuid numbersUuid) { + final NumbersAccess lotAccess = access(privateUuid, numbersUuid); + return toDto(lotAccess); } @NonNull public Page page(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid, final int page, final int pageSize) { - final GroupAccess access = groupAccessService.access(privateUuid, groupUuid); + final GroupAccess groupAccess = groupAccessService.access(privateUuid, groupUuid); final PageRequest pageable = PageRequest.of(page, pageSize, Sort.by(new Sort.Order(Sort.Direction.DESC, "date"))); - return numbersRepository.findAllByGroup(access.group, pageable).map(numbers -> toDto(numbers, access.user)); + return numbersRepository.findAllByGroup(groupAccess.group, pageable).map(numbers -> toDto(new NumbersAccess(groupAccess.principal, numbers))); + } + + /* ACCESS --------------------------------------------------------------------------------------- */ + + @NonNull + private NumbersAccess access(@NonNull final UserPrivateUuid privateUuid, @NonNull final NumbersUuid numbersUuid) { + final User principal = userAccessService.access(privateUuid); + final Numbers numbers = numbersRepository.findById(numbersUuid.uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST)); + if (!numbers.getGroup().getUsers().contains(principal)) { + throw new ResponseStatusException(HttpStatus.FORBIDDEN); + } + return new NumbersAccess(principal, numbers); + } + + /* PUSH, DTO ------------------------------------------------------------------------------------ */ + + private void pushAllLots(@NonNull final Numbers numbers) { + numbers.getLots() + .stream() + .filter(Objects::nonNull) + .map(lot -> new NumbersAccess(lot.getUser(), numbers)) + .forEach(lotAccess -> userPushService.push(lotAccess.principal, toDto(lotAccess))); + } + + @NonNull + private NumbersDto toDto(@NonNull final NumbersAccess lotAccess) { + final GroupDto group = groupMapper.toDto(lotAccess.numbers.getGroup()); + return new NumbersDto(lotAccess, group); } } diff --git a/src/main/java/de/ph87/tools/tools/numbers/lot/NumberLot.java b/src/main/java/de/ph87/tools/tools/numbers/lot/NumberLot.java new file mode 100644 index 0000000..09ce762 --- /dev/null +++ b/src/main/java/de/ph87/tools/tools/numbers/lot/NumberLot.java @@ -0,0 +1,37 @@ +package de.ph87.tools.tools.numbers.lot; + +import de.ph87.tools.user.User; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.persistence.ManyToOne; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.ToString; + +@Getter +@ToString +@Embeddable +@NoArgsConstructor +public class NumberLot { + + @NonNull + @ManyToOne(optional = false) + private User user; + + @Column(nullable = false) + private int number; + + @Column(nullable = false) + private boolean revealed = false; + + public NumberLot(@NonNull final User user, final int number) { + this.user = user; + this.number = number; + } + + public boolean is(@NonNull final User user) { + return this.user.equals(user); + } + +} diff --git a/src/main/java/de/ph87/tools/tools/numbers/lot/NumberLotDto.java b/src/main/java/de/ph87/tools/tools/numbers/lot/NumberLotDto.java new file mode 100644 index 0000000..f3e21d6 --- /dev/null +++ b/src/main/java/de/ph87/tools/tools/numbers/lot/NumberLotDto.java @@ -0,0 +1,25 @@ +package de.ph87.tools.tools.numbers.lot; + +import de.ph87.tools.user.User; +import de.ph87.tools.user.UserPublicDto; +import jakarta.annotation.Nullable; +import lombok.Getter; +import lombok.NonNull; +import lombok.ToString; + +@Getter +@ToString +public class NumberLotDto { + + @NonNull + private final UserPublicDto user; + + @Nullable + private final Integer number; + + public NumberLotDto(@NonNull final NumberLot lot, @NonNull final User principal) { + this.user = new UserPublicDto(lot.getUser()); + this.number = lot.isRevealed() || lot.getUser().equals(principal) ? lot.getNumber() : null; + } + +}