Compare commits
9 Commits
b07fc824af
...
5987330089
| Author | SHA1 | Date | |
|---|---|---|---|
| 5987330089 | |||
| 6eb7165bf1 | |||
| 9636bd222b | |||
| 232d824ceb | |||
| c7b88d415a | |||
| a1e3a4353d | |||
| bff407c446 | |||
| a9e08775d1 | |||
| 8a28acc6dc |
@ -1,5 +1,5 @@
|
|||||||
import {UserPublic} from "../User/UserPublic";
|
import {UserPublic} from "../User/UserPublic";
|
||||||
import {validateBoolean, validateDate, validateList, validateString} from "../common/validators";
|
import {validateDate, validateList, validateString} from "../common/validators";
|
||||||
import {UserPrivate} from "../User/UserPrivate";
|
import {UserPrivate} from "../User/UserPrivate";
|
||||||
import {GroupUuid} from "./GroupUuid";
|
import {GroupUuid} from "./GroupUuid";
|
||||||
|
|
||||||
@ -13,12 +13,11 @@ export class Group extends GroupUuid {
|
|||||||
readonly password: string,
|
readonly password: string,
|
||||||
readonly users: UserPublic[],
|
readonly users: UserPublic[],
|
||||||
readonly banned: UserPublic[],
|
readonly banned: UserPublic[],
|
||||||
readonly initial: boolean,
|
|
||||||
) {
|
) {
|
||||||
super(uuid);
|
super(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
isOwner(user: UserPublic) {
|
isOwner(user: UserPublic): boolean {
|
||||||
return this.owner.publicUuid === user.publicUuid;
|
return this.owner.publicUuid === user.publicUuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,11 +30,10 @@ export class Group extends GroupUuid {
|
|||||||
validateString(json['password']),
|
validateString(json['password']),
|
||||||
validateList(json['users'], UserPublic.fromJson),
|
validateList(json['users'], UserPublic.fromJson),
|
||||||
validateList(json['banned'], UserPublic.fromJson),
|
validateList(json['banned'], UserPublic.fromJson),
|
||||||
validateBoolean(json['initial']),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
usersByNameOwnerFirst() {
|
usersByNameOwnerFirst(): UserPublic[] {
|
||||||
return this.users.sort((a, b) => this.compareOwnerFirstThenName(a, b));
|
return this.users.sort((a, b) => this.compareOwnerFirstThenName(a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,17 +50,21 @@ export class Group extends GroupUuid {
|
|||||||
return a.created.getTime() - b.created.getTime();
|
return a.created.getTime() - b.created.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
isOwnedBy(user: UserPublic | UserPrivate | null) {
|
isOwnedBy(user: UserPublic | UserPrivate | null): boolean {
|
||||||
return user !== null && user.is(this.owner);
|
return user !== null && user.is(this.owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
bannedByName() {
|
bannedByName(): UserPublic[] {
|
||||||
return this.banned.sort(UserPublic.compareName);
|
return this.banned.sort(UserPublic.compareName);
|
||||||
}
|
}
|
||||||
|
|
||||||
hasUser(user: UserPublic) {
|
hasUser(user: UserPublic): boolean {
|
||||||
return this.users.some(u => u.is(user));
|
return this.users.some(u => u.is(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
equals(group: Group | null): boolean {
|
||||||
|
return this.uuid === group?.uuid;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,15 @@
|
|||||||
import {Group} from "../../group/Group";
|
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 {
|
export class Numbers {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly uuid: string,
|
readonly uuid: string,
|
||||||
readonly group: Group,
|
|
||||||
readonly date: Date,
|
readonly date: Date,
|
||||||
readonly read: Date | null,
|
readonly lots: NumbersLot[],
|
||||||
readonly number: number | null,
|
readonly group: Group,
|
||||||
) {
|
) {
|
||||||
// -
|
// -
|
||||||
}
|
}
|
||||||
@ -16,11 +17,18 @@ export class Numbers {
|
|||||||
static fromJson(json: any): Numbers {
|
static fromJson(json: any): Numbers {
|
||||||
return new Numbers(
|
return new Numbers(
|
||||||
validateString(json['uuid']),
|
validateString(json['uuid']),
|
||||||
Group.fromJson(json['group']),
|
|
||||||
validateDate(json['date']),
|
validateDate(json['date']),
|
||||||
validateDateOrNull(json['read']),
|
validateList(json['lots'], NumbersLot.fromJson),
|
||||||
validateNumberOrNull(json['number']),
|
Group.fromJson(json['group']),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getMine(user: UserPrivate | null): NumbersLot | null {
|
||||||
|
return this.lots.filter(u => u.user.is(user))[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
sameGroup(numbers: Numbers): boolean {
|
||||||
|
return this.group.equals(numbers.group);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
20
src/main/angular/src/app/api/tools/Numbers/NumbersLot.ts
Normal file
20
src/main/angular/src/app/api/tools/Numbers/NumbersLot.ts
Normal file
@ -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']),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -28,8 +28,8 @@ export class NumbersService {
|
|||||||
this.api.getPage(['Numbers', 'page', groupUuid, page, pageSize], Numbers.fromJson, next);
|
this.api.getPage(['Numbers', 'page', groupUuid, page, pageSize], Numbers.fromJson, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchAndMarkAsRead(numbersUuid: string, next: Next<Numbers>): void {
|
byUuid(numbersUuid: string, next: Next<Numbers>): void {
|
||||||
this.api.postSingle(['Numbers', 'fetchAndMarkAsRead'], numbersUuid, Numbers.fromJson, next);
|
this.api.postSingle(['Numbers', 'byUuid'], numbersUuid, Numbers.fromJson, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
canAccess(numbersUuid: string, next: Next<boolean>): void {
|
canAccess(numbersUuid: string, next: Next<boolean>): void {
|
||||||
|
|||||||
@ -1,15 +1,6 @@
|
|||||||
<div class="tileContainer">
|
<div class="tileContainer">
|
||||||
|
|
||||||
<div class="tile" *ngIf="group === null && granted === false">
|
<app-password-tile [visible]="group === null && granted === false" (join)="join($event)"></app-password-tile>
|
||||||
<div class="tileInner">
|
|
||||||
<div class="tileTitle">
|
|
||||||
Passwort
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="tileContent">
|
|
||||||
<app-password [visible]="true" (join)="join($event)"></app-password>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ng-container *ngIf="group">
|
<ng-container *ngIf="group">
|
||||||
|
|
||||||
@ -42,7 +33,7 @@
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<div class="button buttonRight buttonDelete" (click)="groupDelete(group)">
|
<div class="button buttonRight buttonDelete" (click)="groupDelete(group)" *ngIf="userService.iOwn(group)">
|
||||||
Gruppe löschen
|
Gruppe löschen
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -57,26 +48,24 @@
|
|||||||
Mitglieder
|
Mitglieder
|
||||||
</div>
|
</div>
|
||||||
<div class="tileContent">
|
<div class="tileContent">
|
||||||
<div class="numbers">
|
<table>
|
||||||
<table>
|
<tr [class.user_owner]="group.isOwner(user)" *ngFor="let user of group.usersByNameOwnerFirst()">
|
||||||
<tr [class.user_owner]="group.isOwner(user)" *ngFor="let user of group.usersByNameOwnerFirst()">
|
<td (click)="userService.goto(user)">
|
||||||
<td (click)="userService.goto(user)">
|
{{ user.name }}
|
||||||
{{ user.name }}
|
</td>
|
||||||
</td>
|
<td>
|
||||||
<td>
|
|
||||||
<span class="owner" *ngIf="group.isOwnedBy(user)">
|
<span class="owner" *ngIf="group.isOwnedBy(user)">
|
||||||
Admin
|
Admin
|
||||||
</span>
|
</span>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<ng-container *ngIf="userService.iOwn(group) && !userService.iAm(user)">
|
<ng-container *ngIf="userService.iOwn(group) && !userService.iAm(user)">
|
||||||
<div class="button buttonRight buttonBan" (click)="groupService.ban(group, user)">Verbannen</div>
|
<div class="button buttonRight buttonBan" (click)="groupService.ban(group, user)">Verbannen</div>
|
||||||
<div class="button buttonRight buttonRemove" (click)="groupService.kick(group, user)">Entfernen</div>
|
<div class="button buttonRight buttonRemove" (click)="groupService.kick(group, user)">Entfernen</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -87,22 +76,20 @@
|
|||||||
Verbannt
|
Verbannt
|
||||||
</div>
|
</div>
|
||||||
<div class="tileContent">
|
<div class="tileContent">
|
||||||
<div class="numbers">
|
<table>
|
||||||
<table>
|
<tr [class.user_owner]="group.isOwner(user)" *ngFor="let user of group.bannedByName()">
|
||||||
<tr [class.user_owner]="group.isOwner(user)" *ngFor="let user of group.bannedByName()">
|
<td (click)="userService.goto(user)">
|
||||||
<td (click)="userService.goto(user)">
|
{{ user.name }}
|
||||||
{{ user.name }}
|
</td>
|
||||||
</td>
|
<td>
|
||||||
<td>
|
<div class="buttons">
|
||||||
<div class="buttons">
|
<ng-container *ngIf="userService.iOwn(group) && !userService.iAm(user)">
|
||||||
<ng-container *ngIf="userService.iOwn(group) && !userService.iAm(user)">
|
<div class="button buttonRight buttonUnban" (click)="groupService.unban(group, user)">Aufheben</div>
|
||||||
<div class="button buttonRight buttonUnban" (click)="groupService.unban(group, user)">Aufheben</div>
|
</ng-container>
|
||||||
</ng-container>
|
</div>
|
||||||
</div>
|
</td>
|
||||||
</td>
|
</tr>
|
||||||
</tr>
|
</table>
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -116,14 +103,18 @@
|
|||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<div class="button buttonRight buttonNext" *ngIf="userService.iOwn(group)" (click)="numbersService.create(group.uuid)">+ Nächste Runde</div>
|
<div class="button buttonRight buttonNext" *ngIf="userService.iOwn(group)" (click)="numbersService.create(group.uuid)">+ Nächste Runde</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="numbers">
|
<table>
|
||||||
<table>
|
<tr
|
||||||
<tr class="number" *ngFor="let numbers of numbersList.content" (click)="numbersService.goto(numbers)" [class.read]="numbers.read !== null">
|
*ngFor="let numbers of numbersList.content"
|
||||||
<td>{{ numbers.date | relative:now }}</td>
|
(click)="numbersService.goto(numbers)"
|
||||||
<td>{{ numbers.number || '-' }}</td>
|
[class.date_fresh]="now.getTime() - numbers.date.getTime() < 60 * 1000"
|
||||||
</tr>
|
[class.date_middle]="now.getTime() - numbers.date.getTime() >= 60 * 1000"
|
||||||
</table>
|
[class.date_old]="now.getTime() - numbers.date.getTime() >= 5 * 60 * 1000"
|
||||||
</div>
|
>
|
||||||
|
<td>{{ numbers.date | relative:now }}</td>
|
||||||
|
<td>{{ numbers.getMine(userService.user)?.number || '-' }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -4,12 +4,24 @@ th {
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.date_fresh {
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date_middle {
|
||||||
|
color: orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date_old {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
.read {
|
.read {
|
||||||
color: gray;
|
color: lightgray;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unread {
|
.unread {
|
||||||
background-color: lightskyblue;
|
background-color: palegreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
.buttonRemove {
|
.buttonRemove {
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import {GroupService} from "../../../api/group/group.service";
|
|||||||
import {UserService} from "../../../api/User/user.service";
|
import {UserService} from "../../../api/User/user.service";
|
||||||
import {Group} from "../../../api/group/Group";
|
import {Group} from "../../../api/group/Group";
|
||||||
import {NumbersService} from "../../../api/tools/Numbers/numbers.service";
|
import {NumbersService} from "../../../api/tools/Numbers/numbers.service";
|
||||||
import {PasswordComponent} from "../../../shared/password/password.component";
|
import {PasswordTileComponent} from "../../../shared/password-tile/password-tile.component";
|
||||||
import {Numbers} from "../../../api/tools/Numbers/Numbers";
|
import {Numbers} from "../../../api/tools/Numbers/Numbers";
|
||||||
import {Page} from "../../../api/common/Page";
|
import {Page} from "../../../api/common/Page";
|
||||||
import {RelativePipe} from "../../../shared/relative.pipe";
|
import {RelativePipe} from "../../../shared/relative.pipe";
|
||||||
@ -26,7 +26,7 @@ import {UserPublic} from "../../../api/User/UserPublic";
|
|||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
TextComponent,
|
TextComponent,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
PasswordComponent,
|
PasswordTileComponent,
|
||||||
RelativePipe
|
RelativePipe
|
||||||
],
|
],
|
||||||
templateUrl: './group.component.html',
|
templateUrl: './group.component.html',
|
||||||
@ -95,10 +95,10 @@ export class GroupComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.subs.forEach(sub => sub.unsubscribe());
|
this.subs.forEach(sub => sub.unsubscribe());
|
||||||
this.subs.length=0;
|
this.subs.length = 0;
|
||||||
|
|
||||||
this.userSubs.forEach(sub => sub.unsubscribe());
|
this.userSubs.forEach(sub => sub.unsubscribe());
|
||||||
this.userSubs.length=0;
|
this.userSubs.length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private setGroup(group: Group) {
|
private setGroup(group: Group) {
|
||||||
@ -107,6 +107,9 @@ export class GroupComponent implements OnInit, OnDestroy {
|
|||||||
this.userSubs.length = 0;
|
this.userSubs.length = 0;
|
||||||
if (this.group !== null) {
|
if (this.group !== null) {
|
||||||
this.group.users.forEach(_ => this.userSubs.push(this.userService.subscribePush(UserPublic, u => this.updateUser(u))));
|
this.group.users.forEach(_ => this.userSubs.push(this.userService.subscribePush(UserPublic, u => this.updateUser(u))));
|
||||||
|
this.updateNumbersList();
|
||||||
|
} else {
|
||||||
|
this.numbersList = Page.EMPTY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,61 +1,37 @@
|
|||||||
<ng-container *ngIf="userService.user !== null">
|
<ng-container *ngIf="userService.user !== null">
|
||||||
<h1>Profil</h1>
|
<div class="tileContainer">
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th>
|
|
||||||
Name:
|
|
||||||
</th>
|
|
||||||
<td>
|
|
||||||
<app-text [initial]="userService.user.name" [editable]="true" (onChange)="userService.changeName($event)" [validator]="nameValidator"></app-text>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="hint" colspan="2">
|
|
||||||
Mindestens {{ USER_NAME_MIN_LENGTH }} Zeichen. Keine Leerzeichen. Buchstaben oder Zahlen müssen enthalten sein.
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
<div class="tile">
|
||||||
<th colspan="2"> </th>
|
<div class="tileInner">
|
||||||
</tr>
|
<div class="tileTitle">
|
||||||
|
Benutzername
|
||||||
|
</div>
|
||||||
|
<div class="tileContent">
|
||||||
|
<app-text [initial]="userService.user.name" [editable]="true" (onChange)="userService.changeName($event)" [validator]="nameValidator"></app-text>
|
||||||
|
<div class="hint">
|
||||||
|
Mindestens {{ USER_NAME_MIN_LENGTH }} Zeichen. Keine Leerzeichen. Buchstaben oder Zahlen müssen enthalten sein.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<tr>
|
<div class="tile">
|
||||||
<th>
|
<div class="tileInner">
|
||||||
Passwort:
|
<div class="tileTitle">
|
||||||
</th>
|
Passwort
|
||||||
<td>
|
<span *ngIf="!userService.user.password" class="passwordNotSet">(nicht gesetzt))</span>
|
||||||
<div *ngIf="!userService.user.password" class="passwordNotSet">Nicht gesetzt</div>
|
<span *ngIf="userService.user.password" class="passwordSet">(gesetzt)</span>
|
||||||
<div *ngIf="userService.user.password" class="passwordSet">Gesetzt</div>
|
</div>
|
||||||
</td>
|
<div class="tileContent">
|
||||||
</tr>
|
<input #p0 type="text" [(ngModel)]="password0" [class.passwordInvalid]="p0Invalid()" [class.passwordValid]="p0Valid()" (keydown.enter)="p0Enter()">
|
||||||
<tr>
|
<input #p1 type="text" [(ngModel)]="password1" [class.passwordInvalid]="p1Invalid()" [class.passwordValid]="p1Valid()" (keydown.enter)="p1Enter()">
|
||||||
<th>
|
<div class="hint">
|
||||||
Neues Passwort:
|
Mindestens {{ USER_PASSWORD_MIN_LENGTH }} Zeichen. Nicht nur Zahlen. Nicht nur Buchstaben.
|
||||||
</th>
|
</div>
|
||||||
<td>
|
</div>
|
||||||
<input #p0 type="text" [(ngModel)]="password0" [class.passwordInvalid]="p0Invalid()" [class.passwordValid]="p0Valid()" (keydown.enter)="p0Enter()">
|
</div>
|
||||||
</td>
|
</div>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>
|
|
||||||
Wiederholung:
|
|
||||||
</th>
|
|
||||||
<td>
|
|
||||||
<input #p1 type="text" [(ngModel)]="password1" [class.passwordInvalid]="p1Invalid()" [class.passwordValid]="p1Valid()" (keydown.enter)="p1Enter()">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="hint" colspan="2">
|
|
||||||
Mindestens {{ USER_PASSWORD_MIN_LENGTH }} Zeichen. Nicht nur Zahlen. Nicht nur Buchstaben.
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
</div>
|
||||||
<th colspan="2"> </th>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<app-group-list [groups]="groups"></app-group-list>
|
|
||||||
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|||||||
@ -51,8 +51,9 @@ export class ProfileComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
this.updateGroupList();
|
||||||
this.subs.push(this.userService.subscribePush(UserPrivate, _ => {
|
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;
|
this.subs.length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private updateGroupList() {
|
||||||
|
this.groupService.findAllJoined(groups => this.groups = groups);
|
||||||
|
}
|
||||||
|
|
||||||
protected nameValidator(name: string): boolean {
|
protected nameValidator(name: string): boolean {
|
||||||
return name.length >= USER_NAME_MIN_LENGTH && !/\s+|^[^a-zA-Z0-9]+$/.test(name);
|
return name.length >= USER_NAME_MIN_LENGTH && !/\s+|^[^a-zA-Z0-9]+$/.test(name);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<div
|
<div
|
||||||
*ngIf="numbers"
|
*ngIf="numbers"
|
||||||
class="numbers"
|
[class.date_fresh]="now.getTime() - numbers.date.getTime() < 60 * 1000"
|
||||||
[class.date_middle]="now.getTime() - numbers.date.getTime() >= 30 * 1000"
|
[class.date_middle]="now.getTime() - numbers.date.getTime() >= 60 * 1000"
|
||||||
[class.date_old]="now.getTime() - numbers.date.getTime() >= 5 * 60 * 1000"
|
[class.date_old]="now.getTime() - numbers.date.getTime() >= 5 * 60 * 1000"
|
||||||
>
|
>
|
||||||
|
|
||||||
@ -10,7 +10,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="huge" (click)="gotoGroup()">
|
<div class="huge" (click)="gotoGroup()">
|
||||||
{{ numbers.number || '-' }}
|
{{ numbers.getMine(userService.user)?.number || '-' }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.numbers {
|
.date_fresh {
|
||||||
color: green;
|
color: green;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import {ActivatedRoute} from "@angular/router";
|
|||||||
import {NumbersService} from "../../../api/tools/Numbers/numbers.service";
|
import {NumbersService} from "../../../api/tools/Numbers/numbers.service";
|
||||||
import {NgIf} from "@angular/common";
|
import {NgIf} from "@angular/common";
|
||||||
import {FormsModule} from "@angular/forms";
|
import {FormsModule} from "@angular/forms";
|
||||||
import {PasswordComponent} from "../../../shared/password/password.component";
|
import {PasswordTileComponent} from "../../../shared/password-tile/password-tile.component";
|
||||||
import {GroupService} from "../../../api/group/group.service";
|
import {GroupService} from "../../../api/group/group.service";
|
||||||
import {UserService} from "../../../api/User/user.service";
|
import {UserService} from "../../../api/User/user.service";
|
||||||
import {RelativePipe} from "../../../shared/relative.pipe";
|
import {RelativePipe} from "../../../shared/relative.pipe";
|
||||||
@ -16,7 +16,7 @@ import {Subscription, timer} from "rxjs";
|
|||||||
imports: [
|
imports: [
|
||||||
NgIf,
|
NgIf,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
PasswordComponent,
|
PasswordTileComponent,
|
||||||
RelativePipe
|
RelativePipe
|
||||||
],
|
],
|
||||||
templateUrl: './numbers.component.html',
|
templateUrl: './numbers.component.html',
|
||||||
@ -24,12 +24,12 @@ import {Subscription, timer} from "rxjs";
|
|||||||
})
|
})
|
||||||
export class NumbersComponent implements OnInit, OnDestroy {
|
export class NumbersComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
|
private readonly subs: Subscription[] = [];
|
||||||
|
|
||||||
protected numbers: Numbers | null = null;
|
protected numbers: Numbers | null = null;
|
||||||
|
|
||||||
protected now: Date = new Date();
|
protected now: Date = new Date();
|
||||||
|
|
||||||
private timer?: Subscription;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected readonly activatedRoute: ActivatedRoute,
|
protected readonly activatedRoute: ActivatedRoute,
|
||||||
protected readonly numbersService: NumbersService,
|
protected readonly numbersService: NumbersService,
|
||||||
@ -40,13 +40,13 @@ export class NumbersComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.timer = timer(1000, 1000).subscribe(() => this.now = new Date());
|
this.subs.push(timer(1000, 1000).subscribe(() => this.now = new Date()));
|
||||||
this.activatedRoute.params.subscribe(params => {
|
this.subs.push(this.activatedRoute.params.subscribe(params => {
|
||||||
const uuid = params['uuid'];
|
const uuid = params['uuid'];
|
||||||
if (uuid) {
|
if (uuid) {
|
||||||
this.numbersService.canAccess(uuid, granted => {
|
this.numbersService.canAccess(uuid, granted => {
|
||||||
if (granted) {
|
if (granted) {
|
||||||
this.numbersService.fetchAndMarkAsRead(uuid, numbers => this.numbers = numbers);
|
this.numbersService.byUuid(uuid, numbers => this.numbers = numbers);
|
||||||
} else {
|
} else {
|
||||||
this.numbersService.getGroupUuid(uuid, groupUuid => this.groupService.goto(groupUuid));
|
this.numbersService.getGroupUuid(uuid, groupUuid => this.groupService.goto(groupUuid));
|
||||||
}
|
}
|
||||||
@ -54,14 +54,17 @@ export class NumbersComponent implements OnInit, OnDestroy {
|
|||||||
} else {
|
} else {
|
||||||
this.numbers = null;
|
this.numbers = null;
|
||||||
}
|
}
|
||||||
|
}));
|
||||||
|
this.userService.subscribePush(Numbers, numbers => {
|
||||||
|
if (this.numbers?.sameGroup(numbers)) {
|
||||||
|
this.numbers = numbers;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (this.timer) {
|
this.subs.forEach(sub => sub.unsubscribe());
|
||||||
this.timer.unsubscribe();
|
this.subs.length = 0;
|
||||||
this.timer = undefined;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@HostListener('window:keydown.escape')
|
@HostListener('window:keydown.escape')
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
import {Component, Inject, LOCALE_ID, OnInit} from '@angular/core';
|
import {Component, Inject, LOCALE_ID, OnDestroy, OnInit} from '@angular/core';
|
||||||
import {BODIES, BODIES_PRINT, EARTH, EARTH_MOON, JUPITER, JUPITER_SCALED_DIAMETER, SUN} from "../SOLAR_SYSTEM";
|
import {BODIES, BODIES_PRINT, EARTH, EARTH_MOON, JUPITER, JUPITER_SCALED_DIAMETER, SUN} from "../SOLAR_SYSTEM";
|
||||||
import {ActivatedRoute, Params} from "@angular/router";
|
import {ActivatedRoute, Params} from "@angular/router";
|
||||||
import {DecimalPipe, NgForOf, NgIf} from "@angular/common";
|
import {DecimalPipe, NgForOf, NgIf} from "@angular/common";
|
||||||
import {MIO_KILO, SolarSystemBody} from "../SolarSystemBody";
|
import {MIO_KILO, SolarSystemBody} from "../SolarSystemBody";
|
||||||
import {Unit} from "../../../../Unit";
|
import {Unit} from "../../../../Unit";
|
||||||
|
import {Subscription} from "rxjs";
|
||||||
|
|
||||||
function getScale(params: Params) {
|
function getScale(params: Params) {
|
||||||
if ('scale' in params) {
|
if ('scale' in params) {
|
||||||
@ -37,10 +38,12 @@ export function makePaler(hexColor: string, factor: number): string {
|
|||||||
templateUrl: './solar-system-printout.component.html',
|
templateUrl: './solar-system-printout.component.html',
|
||||||
styleUrl: './solar-system-printout.component.less'
|
styleUrl: './solar-system-printout.component.less'
|
||||||
})
|
})
|
||||||
export class SolarSystemPrintoutComponent implements OnInit {
|
export class SolarSystemPrintoutComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
public readonly PRINTABLE_ONLY: boolean = true;
|
public readonly PRINTABLE_ONLY: boolean = true;
|
||||||
|
|
||||||
|
private readonly subs: Subscription[] = [];
|
||||||
|
|
||||||
protected readonly makePaler = makePaler;
|
protected readonly makePaler = makePaler;
|
||||||
|
|
||||||
protected readonly BODIES_PRINT = BODIES_PRINT;
|
protected readonly BODIES_PRINT = BODIES_PRINT;
|
||||||
@ -64,10 +67,15 @@ export class SolarSystemPrintoutComponent implements OnInit {
|
|||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
JUPITER.scaledDiameter = JUPITER_SCALED_DIAMETER;
|
JUPITER.scaledDiameter = JUPITER_SCALED_DIAMETER;
|
||||||
this.activatedRoute.params.subscribe(params => {
|
this.subs.push(this.activatedRoute.params.subscribe(params => {
|
||||||
const scale = getScale(params);
|
const scale = getScale(params);
|
||||||
BODIES.forEach(b => b.scale(scale));
|
BODIES.forEach(b => b.scale(scale));
|
||||||
});
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.subs.forEach(sub => sub.unsubscribe());
|
||||||
|
this.subs.length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fontSize(body: SolarSystemBody): string {
|
fontSize(body: SolarSystemBody): string {
|
||||||
|
|||||||
@ -1,6 +1,29 @@
|
|||||||
<ng-container *ngIf="user !== null">
|
<ng-container *ngIf="user !== null">
|
||||||
<h2>Benutzer: {{ user.name }}</h2>
|
|
||||||
|
|
||||||
<h3>Gemeinsame Gruppen</h3>
|
<div class="tileContainer">
|
||||||
<app-group-list [groups]="commonGroups"></app-group-list>
|
|
||||||
|
<div class="tile">
|
||||||
|
<div class="tileInner">
|
||||||
|
<div class="tileTitle">
|
||||||
|
Benutzer
|
||||||
|
</div>
|
||||||
|
<div class="tileContent">
|
||||||
|
{{ user.name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tile">
|
||||||
|
<div class="tileInner">
|
||||||
|
<div class="tileTitle">
|
||||||
|
Gemeinsame Gruppen
|
||||||
|
</div>
|
||||||
|
<div class="tileContent">
|
||||||
|
<app-group-list [groups]="commonGroups"></app-group-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||||
import {NgForOf, NgIf} from "@angular/common";
|
import {NgForOf, NgIf} from "@angular/common";
|
||||||
import {ActivatedRoute} from "@angular/router";
|
import {ActivatedRoute} from "@angular/router";
|
||||||
import {GroupListComponent} from "../group/shared/group-list/group-list.component";
|
import {GroupListComponent} from "../group/shared/group-list/group-list.component";
|
||||||
@ -6,6 +6,9 @@ import {GroupService} from "../../api/group/group.service";
|
|||||||
import {UserService} from "../../api/User/user.service";
|
import {UserService} from "../../api/User/user.service";
|
||||||
import {Group} from "../../api/group/Group";
|
import {Group} from "../../api/group/Group";
|
||||||
import {UserPublic} from "../../api/User/UserPublic";
|
import {UserPublic} from "../../api/User/UserPublic";
|
||||||
|
import {ReactiveFormsModule} from "@angular/forms";
|
||||||
|
import {TextComponent} from "../../shared/text/text.component";
|
||||||
|
import {Subscription} from "rxjs";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-user',
|
selector: 'app-user',
|
||||||
@ -13,12 +16,16 @@ import {UserPublic} from "../../api/User/UserPublic";
|
|||||||
imports: [
|
imports: [
|
||||||
NgForOf,
|
NgForOf,
|
||||||
NgIf,
|
NgIf,
|
||||||
GroupListComponent
|
GroupListComponent,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
TextComponent
|
||||||
],
|
],
|
||||||
templateUrl: './user.component.html',
|
templateUrl: './user.component.html',
|
||||||
styleUrl: './user.component.less'
|
styleUrl: './user.component.less'
|
||||||
})
|
})
|
||||||
export class UserComponent implements OnInit {
|
export class UserComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
|
private readonly subs: Subscription[] = [];
|
||||||
|
|
||||||
protected user: UserPublic | null = null;
|
protected user: UserPublic | null = null;
|
||||||
|
|
||||||
@ -33,13 +40,18 @@ export class UserComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.activatedRoute.params.subscribe(params => {
|
this.subs.push(this.activatedRoute.params.subscribe(params => {
|
||||||
const publicUuid = params['publicUuid'];
|
const publicUuid = params['publicUuid'];
|
||||||
if (publicUuid) {
|
if (publicUuid) {
|
||||||
this.userService.getByPublicUuid(publicUuid, user => this.user = user);
|
this.userService.getByPublicUuid(publicUuid, user => this.user = user);
|
||||||
this.groupService.findAllCommon(publicUuid, commonGroups => this.commonGroups = commonGroups);
|
this.groupService.findAllCommon(publicUuid, commonGroups => this.commonGroups = commonGroups);
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.subs.forEach(sub => sub.unsubscribe());
|
||||||
|
this.subs.length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,13 @@
|
|||||||
|
<div class="tile" *ngIf="visible">
|
||||||
|
<div class="tileInner" *ngIf="visible">
|
||||||
|
<div class="tileTitle">
|
||||||
|
Gruppenpasswort
|
||||||
|
</div>
|
||||||
|
<div class="tileContent">
|
||||||
|
<input type="text" [(ngModel)]="password" (keydown.enter)="join.emit(password)">
|
||||||
|
<div class="buttons">
|
||||||
|
<div class="button buttonRight buttonJoin" (click)="join.emit(password)">Beitreten</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@ -0,0 +1 @@
|
|||||||
|
@import "../../../common";
|
||||||
@ -3,16 +3,16 @@ import {FormsModule} from "@angular/forms";
|
|||||||
import {NgIf} from "@angular/common";
|
import {NgIf} from "@angular/common";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-password',
|
selector: 'app-password-tile',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [
|
imports: [
|
||||||
FormsModule,
|
FormsModule,
|
||||||
NgIf
|
NgIf
|
||||||
],
|
],
|
||||||
templateUrl: './password.component.html',
|
templateUrl: './password-tile.component.html',
|
||||||
styleUrl: './password.component.less'
|
styleUrl: './password-tile.component.less'
|
||||||
})
|
})
|
||||||
export class PasswordComponent implements OnInit {
|
export class PasswordTileComponent implements OnInit {
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
visible: boolean = false;
|
visible: boolean = false;
|
||||||
@ -1,7 +0,0 @@
|
|||||||
<ng-container *ngIf="visible">
|
|
||||||
<h1>Passwort</h1>
|
|
||||||
<input type="text" [(ngModel)]="password" (keydown.enter)="join.emit(password)">
|
|
||||||
<div class="buttons">
|
|
||||||
<div class="button buttonRight buttonJoin" (click)="join.emit(password)">Beitreten</div>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
||||||
@ -1,4 +1,3 @@
|
|||||||
@import "./tile.less";
|
|
||||||
@import "./user.less";
|
@import "./user.less";
|
||||||
|
|
||||||
.buttons {
|
.buttons {
|
||||||
|
|||||||
@ -29,10 +29,61 @@ table {
|
|||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tileContainer {
|
||||||
|
padding: @halfSpace;
|
||||||
|
|
||||||
|
.tile {
|
||||||
|
width: 100%;
|
||||||
|
padding: @halfSpace;
|
||||||
|
|
||||||
|
.tileInner {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: @space;
|
||||||
|
background-color: #fbfbfb;
|
||||||
|
|
||||||
|
.tileTitle {
|
||||||
|
font-weight: bold;
|
||||||
|
padding: @halfSpace @space;
|
||||||
|
background-color: lightskyblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tileContent {
|
||||||
|
padding: @halfSpace;
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
white-space: nowrap;
|
||||||
|
border: 0.2em solid white;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.tileFooter {
|
||||||
|
padding: @halfSpace @space;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@media (min-width: 1000px) {
|
@media (min-width: 1000px) {
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tileContainer {
|
||||||
|
|
||||||
|
.tile {
|
||||||
|
float: left;
|
||||||
|
width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,56 +0,0 @@
|
|||||||
@import "./config.less";
|
|
||||||
|
|
||||||
.tileContainer {
|
|
||||||
padding: @halfSpace;
|
|
||||||
|
|
||||||
.tile {
|
|
||||||
width: 100%;
|
|
||||||
padding: @halfSpace;
|
|
||||||
|
|
||||||
.tileInner {
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: @space;
|
|
||||||
background-color: #fbfbfb;
|
|
||||||
|
|
||||||
.tileTitle {
|
|
||||||
font-weight: bold;
|
|
||||||
padding: @halfSpace @space;
|
|
||||||
background-color: lightskyblue;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tileContent {
|
|
||||||
padding: @halfSpace;
|
|
||||||
|
|
||||||
table {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
td {
|
|
||||||
white-space: nowrap;
|
|
||||||
border: 0.2em solid white;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.tileFooter {
|
|
||||||
padding: @halfSpace @space;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 1000px) {
|
|
||||||
|
|
||||||
.tileContainer {
|
|
||||||
|
|
||||||
.tile {
|
|
||||||
float: left;
|
|
||||||
width: 500px;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -75,15 +75,11 @@ public class Group extends GroupAbstract implements IWebSocketMessage {
|
|||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
private String password = UUID.randomUUID().toString().substring(0, 4);
|
private String password = UUID.randomUUID().toString().substring(0, 4);
|
||||||
|
|
||||||
@Setter
|
|
||||||
@Column(nullable = false)
|
|
||||||
private boolean initial = true;
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
private ZonedDateTime lastAccess = created;
|
private ZonedDateTime lastAccess = created;
|
||||||
|
|
||||||
protected Group(@NonNull final User owner) {
|
public Group(@NonNull final User owner) {
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,25 +14,25 @@ import java.util.Set;
|
|||||||
@RestController
|
@RestController
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@RequestMapping("Group")
|
@RequestMapping("Group")
|
||||||
public class GroupReadController {
|
public class GroupController {
|
||||||
|
|
||||||
private final GroupReadService groupReadService;
|
private final GroupService groupService;
|
||||||
|
|
||||||
@PostMapping("get")
|
@PostMapping("get")
|
||||||
public GroupDto get(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) {
|
public GroupDto get(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) {
|
||||||
return groupReadService.get(privateUuid, groupUuid);
|
return groupService.get(privateUuid, groupUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@GetMapping("findAllJoined")
|
@GetMapping("findAllJoined")
|
||||||
public Set<GroupDto> findAllJoined(@NonNull final UserPrivateUuid userUuid) {
|
public Set<GroupDto> findAllJoined(@NonNull final UserPrivateUuid userUuid) {
|
||||||
return groupReadService.findAllJoined(userUuid);
|
return groupService.findAllJoined(userUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@PostMapping("findAllCommon")
|
@PostMapping("findAllCommon")
|
||||||
public Set<GroupDto> findAllCommon(@NonNull final UserPrivateUuid userUuid, @NonNull final UserPublicUuid targetUuid) {
|
public Set<GroupDto> findAllCommon(@NonNull final UserPrivateUuid userUuid, @NonNull final UserPublicUuid targetUuid) {
|
||||||
return groupReadService.findAllCommon(userUuid, targetUuid);
|
return groupService.findAllCommon(userUuid, targetUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
package de.ph87.tools.group;
|
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.dto.GroupDto;
|
||||||
import de.ph87.tools.group.uuid.GroupUuid;
|
import de.ph87.tools.group.uuid.GroupUuid;
|
||||||
import de.ph87.tools.user.User;
|
import de.ph87.tools.user.User;
|
||||||
@ -22,7 +24,7 @@ import java.util.stream.Collectors;
|
|||||||
@Service
|
@Service
|
||||||
@Transactional
|
@Transactional
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class GroupReadService {
|
public class GroupService {
|
||||||
|
|
||||||
private final GroupAccessService groupAccessService;
|
private final GroupAccessService groupAccessService;
|
||||||
|
|
||||||
@ -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 de.ph87.tools.user.User;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class GroupAccess {
|
public class GroupAccess {
|
||||||
|
|
||||||
public final User user;
|
public final User principal;
|
||||||
|
|
||||||
public final Group group;
|
public final Group group;
|
||||||
|
|
||||||
@ -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.group.uuid.GroupUuid;
|
||||||
import de.ph87.tools.user.uuid.UserPrivateUuid;
|
import de.ph87.tools.user.uuid.UserPrivateUuid;
|
||||||
@ -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.group.uuid.GroupUuid;
|
||||||
import de.ph87.tools.user.User;
|
import de.ph87.tools.user.User;
|
||||||
import de.ph87.tools.user.UserAccessService;
|
import de.ph87.tools.user.UserAccessService;
|
||||||
@ -42,7 +44,7 @@ public class GroupAccessService {
|
|||||||
@NonNull
|
@NonNull
|
||||||
public GroupAccess ownerAccess(@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);
|
final GroupAccess groupAccess = access(userPrivateUuid, groupUuid);
|
||||||
if (!groupAccess.group.isOwnedBy(groupAccess.user)) {
|
if (!groupAccess.group.isOwnedBy(groupAccess.principal)) {
|
||||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
|
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
return groupAccess;
|
return groupAccess;
|
||||||
@ -62,8 +62,6 @@ public class GroupDto {
|
|||||||
return banned.size();
|
return banned.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean initial;
|
|
||||||
|
|
||||||
public GroupDto(@NonNull final Group group, @NonNull final UserPublicDto owner, @NonNull final Set<UserPublicDto> users, @NonNull final Set<UserPublicDto> banned) {
|
public GroupDto(@NonNull final Group group, @NonNull final UserPublicDto owner, @NonNull final Set<UserPublicDto> users, @NonNull final Set<UserPublicDto> banned) {
|
||||||
this.uuid = group.getUuid();
|
this.uuid = group.getUuid();
|
||||||
this.title = group.getTitle();
|
this.title = group.getTitle();
|
||||||
@ -72,7 +70,6 @@ public class GroupDto {
|
|||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
this.users = users;
|
this.users = users;
|
||||||
this.banned = banned;
|
this.banned = banned;
|
||||||
this.initial = group.isInitial();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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.dto.GroupDto;
|
||||||
import de.ph87.tools.group.requests.GroupJoinRequest;
|
import de.ph87.tools.group.requests.GroupJoinRequest;
|
||||||
@ -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.dto.GroupDto;
|
||||||
import de.ph87.tools.group.events.GroupLeftEvent;
|
import de.ph87.tools.group.events.GroupLeftEvent;
|
||||||
import de.ph87.tools.group.requests.GroupJoinRequest;
|
import de.ph87.tools.group.requests.GroupJoinRequest;
|
||||||
@ -29,7 +32,7 @@ public class GroupMemberService {
|
|||||||
|
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
|
|
||||||
private final GroupReadService groupReadService;
|
private final GroupService groupService;
|
||||||
|
|
||||||
private final UserPushService userPushService;
|
private final UserPushService userPushService;
|
||||||
|
|
||||||
@ -40,7 +43,7 @@ public class GroupMemberService {
|
|||||||
@NonNull
|
@NonNull
|
||||||
public GroupDto join(@Nullable final UserPrivateUuid privateUuid, @NonNull final GroupJoinRequest request, @NonNull final HttpServletResponse response) {
|
public GroupDto join(@Nullable final UserPrivateUuid privateUuid, @NonNull final GroupJoinRequest request, @NonNull final HttpServletResponse response) {
|
||||||
final User user = userService.getUserByPrivateUuidOrElseCreate(privateUuid, 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)) {
|
if (group.isBanned(user)) {
|
||||||
log.error("User is banned from Group and cannot join it: user={}, group={}", user, group);
|
log.error("User is banned from Group and cannot join it: user={}, group={}", user, group);
|
||||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
|
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
|
||||||
@ -54,7 +57,7 @@ public class GroupMemberService {
|
|||||||
|
|
||||||
public void leave(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) {
|
public void leave(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) {
|
||||||
final User user = userAccessService.access(privateUuid);
|
final User user = userAccessService.access(privateUuid);
|
||||||
final Group group = groupReadService.getGroupByGroupUuid(groupUuid);
|
final Group group = groupService.getGroupByGroupUuid(groupUuid);
|
||||||
if (group.isOwnedBy(user)) {
|
if (group.isOwnedBy(user)) {
|
||||||
// owner cannot remove itself from group
|
// owner cannot remove itself from group
|
||||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
|
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
|
||||||
@ -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.dto.GroupDto;
|
||||||
import de.ph87.tools.group.requests.GroupChangePasswordRequest;
|
import de.ph87.tools.group.requests.GroupChangePasswordRequest;
|
||||||
@ -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.dto.GroupDto;
|
||||||
import de.ph87.tools.group.events.GroupDeletedEvent;
|
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.GroupChangePasswordRequest;
|
||||||
import de.ph87.tools.group.requests.GroupChangeTitleRequest;
|
import de.ph87.tools.group.requests.GroupChangeTitleRequest;
|
||||||
import de.ph87.tools.group.requests.GroupUserRequest;
|
import de.ph87.tools.group.requests.GroupUserRequest;
|
||||||
@ -84,7 +90,7 @@ public class GroupOwnerService {
|
|||||||
@NonNull
|
@NonNull
|
||||||
public GroupDto changeTitle(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupChangeTitleRequest request) {
|
public GroupDto changeTitle(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupChangeTitleRequest request) {
|
||||||
final GroupAccess ug = groupAccessService.access(privateUuid, request.groupUuid);
|
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);
|
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
|
||||||
}
|
}
|
||||||
ug.group.setTitle(request.title);
|
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<Group, User> beforePush) {
|
private OwnerRemoveResult _removeUser(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUserRequest request, @NonNull final BiConsumer<Group, User> beforePush) {
|
||||||
final GroupAccess access = groupAccessService.ownerAccess(privateUuid, request.groupUuid);
|
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));
|
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
|
// owner cannot kick itself from group
|
||||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
|
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
@ -1,17 +1,15 @@
|
|||||||
package de.ph87.tools.tools.numbers;
|
package de.ph87.tools.tools.numbers;
|
||||||
|
|
||||||
import de.ph87.tools.group.Group;
|
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.NumbersAbstract;
|
||||||
import de.ph87.tools.tools.numbers.uuid.NumbersUuid;
|
import de.ph87.tools.tools.numbers.uuid.NumbersUuid;
|
||||||
import de.ph87.tools.user.User;
|
import de.ph87.tools.user.User;
|
||||||
import de.ph87.tools.user.reference.UserReference;
|
|
||||||
import jakarta.annotation.Nullable;
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Getter
|
@Getter
|
||||||
@ -45,40 +43,22 @@ public class Numbers extends NumbersAbstract {
|
|||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
private ZonedDateTime date = ZonedDateTime.now();
|
private ZonedDateTime date = ZonedDateTime.now();
|
||||||
|
|
||||||
@Column
|
|
||||||
@Nullable
|
|
||||||
private ZonedDateTime read = null;
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@OrderColumn
|
@ElementCollection
|
||||||
@OneToMany(orphanRemoval = true)
|
private List<NumberLot> lots = new ArrayList<>();
|
||||||
private List<UserReference> users;
|
|
||||||
|
|
||||||
public Numbers(@NonNull final Group group, @NonNull final List<UserReference> users) {
|
public Numbers(@NonNull final Group group) {
|
||||||
this.group = group;
|
this.group = group;
|
||||||
this.users = users;
|
createRandomLots(group.getUsers());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRead(@NonNull final ZonedDateTime date) {
|
private void createRandomLots(@NonNull final Set<User> users) {
|
||||||
if (this.read != null) {
|
lots.clear();
|
||||||
throw new RuntimeException();
|
final List<User> 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 userReferenceIndex = 0; userReferenceIndex < users.size(); userReferenceIndex++) {
|
|
||||||
final UserReference userReference = users.get(userReferenceIndex);
|
|
||||||
if (userReference.getUser() != null && userReference.getUser().equals(user)) {
|
|
||||||
return userReferenceIndex + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean containsUser(@NonNull final User user) {
|
|
||||||
return users.stream().anyMatch(u -> user.equals(u.getUser()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,19 +2,22 @@ package de.ph87.tools.tools.numbers;
|
|||||||
|
|
||||||
import de.ph87.tools.user.User;
|
import de.ph87.tools.user.User;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ToString
|
@ToString
|
||||||
class NumbersAccess {
|
public class NumbersAccess {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
public final Numbers numbers;
|
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.numbers = numbers;
|
||||||
this.user = user;
|
this.principal = principal;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,9 +41,9 @@ public class NumbersController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@PostMapping("fetchAndMarkAsRead")
|
@PostMapping("byUuid")
|
||||||
public NumbersDto fetchAndMarkAsRead(@NonNull final UserPrivateUuid privateUuid, final NumbersUuid numbersUuid) {
|
public NumbersDto byUuid(@NonNull final UserPrivateUuid privateUuid, final NumbersUuid numbersUuid) {
|
||||||
return numbersService.fetchAndMarkAsRead(privateUuid, numbersUuid);
|
return numbersService.byUuid(privateUuid, numbersUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,14 +3,16 @@ package de.ph87.tools.tools.numbers;
|
|||||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
import de.ph87.tools.common.uuid.UuidSerializer;
|
import de.ph87.tools.common.uuid.UuidSerializer;
|
||||||
import de.ph87.tools.group.dto.GroupDto;
|
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.NumbersAbstract;
|
||||||
import de.ph87.tools.tools.numbers.uuid.NumbersUuid;
|
import de.ph87.tools.tools.numbers.uuid.NumbersUuid;
|
||||||
import jakarta.annotation.Nullable;
|
import jakarta.persistence.ElementCollection;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@ -20,24 +22,21 @@ public class NumbersDto extends NumbersAbstract {
|
|||||||
@JsonSerialize(using = UuidSerializer.class)
|
@JsonSerialize(using = UuidSerializer.class)
|
||||||
private final NumbersUuid uuid;
|
private final NumbersUuid uuid;
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final GroupDto group;
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final ZonedDateTime date;
|
private final ZonedDateTime date;
|
||||||
|
|
||||||
@Nullable
|
@NonNull
|
||||||
private final ZonedDateTime read;
|
@ElementCollection
|
||||||
|
private final List<NumberLotDto> lots;
|
||||||
|
|
||||||
@Nullable
|
@NonNull
|
||||||
private final Integer number;
|
private final GroupDto group;
|
||||||
|
|
||||||
public NumbersDto(@NonNull final Numbers numbers, @NonNull final GroupDto group, @Nullable final Integer number) {
|
public NumbersDto(@NonNull final NumbersAccess lotAccess, @NonNull final GroupDto group) {
|
||||||
this.uuid = numbers.getUuid();
|
this.uuid = lotAccess.numbers.getUuid();
|
||||||
this.date = numbers.getDate();
|
this.date = lotAccess.numbers.getDate();
|
||||||
this.read = numbers.getRead();
|
this.lots = lotAccess.numbers.getLots().stream().map(lot -> new NumberLotDto(lot, lotAccess.principal)).toList();
|
||||||
this.group = group;
|
this.group = group;
|
||||||
this.number = number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,8 +6,6 @@ import org.springframework.data.domain.Page;
|
|||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.repository.ListCrudRepository;
|
import org.springframework.data.repository.ListCrudRepository;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public interface NumbersRepository extends ListCrudRepository<Numbers, String> {
|
public interface NumbersRepository extends ListCrudRepository<Numbers, String> {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@ -15,6 +13,4 @@ public interface NumbersRepository extends ListCrudRepository<Numbers, String> {
|
|||||||
|
|
||||||
void deleteAllByGroup(@NonNull Group group);
|
void deleteAllByGroup(@NonNull Group group);
|
||||||
|
|
||||||
List<Numbers> findAllByGroupAndReadNull(@NonNull Group group);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package de.ph87.tools.tools.numbers;
|
package de.ph87.tools.tools.numbers;
|
||||||
|
|
||||||
import de.ph87.tools.group.GroupAccess;
|
import de.ph87.tools.group.access.GroupAccess;
|
||||||
import de.ph87.tools.group.GroupAccessService;
|
import de.ph87.tools.group.access.GroupAccessService;
|
||||||
import de.ph87.tools.group.GroupMapper;
|
import de.ph87.tools.group.GroupMapper;
|
||||||
import de.ph87.tools.group.dto.GroupDto;
|
import de.ph87.tools.group.dto.GroupDto;
|
||||||
import de.ph87.tools.group.uuid.GroupUuid;
|
import de.ph87.tools.group.uuid.GroupUuid;
|
||||||
@ -9,8 +9,6 @@ import de.ph87.tools.tools.numbers.uuid.NumbersUuid;
|
|||||||
import de.ph87.tools.user.User;
|
import de.ph87.tools.user.User;
|
||||||
import de.ph87.tools.user.UserAccessService;
|
import de.ph87.tools.user.UserAccessService;
|
||||||
import de.ph87.tools.user.push.UserPushService;
|
import de.ph87.tools.user.push.UserPushService;
|
||||||
import de.ph87.tools.user.reference.UserReference;
|
|
||||||
import de.ph87.tools.user.reference.UserReferenceService;
|
|
||||||
import de.ph87.tools.user.uuid.UserPrivateUuid;
|
import de.ph87.tools.user.uuid.UserPrivateUuid;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -23,11 +21,7 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.server.ResponseStatusException;
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@ -39,8 +33,6 @@ public class NumbersService {
|
|||||||
|
|
||||||
private final GroupAccessService groupAccessService;
|
private final GroupAccessService groupAccessService;
|
||||||
|
|
||||||
private final UserReferenceService userReferenceService;
|
|
||||||
|
|
||||||
private final UserPushService userPushService;
|
private final UserPushService userPushService;
|
||||||
|
|
||||||
private final UserAccessService userAccessService;
|
private final UserAccessService userAccessService;
|
||||||
@ -49,37 +41,13 @@ public class NumbersService {
|
|||||||
|
|
||||||
public void create(@NonNull final UserPrivateUuid userPrivateUuid, @NonNull final GroupUuid groupUuid) {
|
public void create(@NonNull final UserPrivateUuid userPrivateUuid, @NonNull final GroupUuid groupUuid) {
|
||||||
final GroupAccess access = groupAccessService.ownerAccess(userPrivateUuid, groupUuid);
|
final GroupAccess access = groupAccessService.ownerAccess(userPrivateUuid, groupUuid);
|
||||||
final List<UserReference> users = access.getGroup().getUsers().stream().map(userReferenceService::create).collect(Collectors.toList());
|
final Numbers numbers = numbersRepository.save(new Numbers(access.group));
|
||||||
Collections.shuffle(users);
|
pushAllLots(numbers);
|
||||||
final Numbers numbers = numbersRepository.save(new Numbers(access.getGroup(), users));
|
|
||||||
publish(numbers);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void publish(@NonNull final Numbers numbers) {
|
|
||||||
numbers.getUsers()
|
|
||||||
.stream()
|
|
||||||
.map(UserReference::getUser)
|
|
||||||
.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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canAccess(@NonNull final UserPrivateUuid privateUuid, @NonNull final NumbersUuid numbersUuid) {
|
public boolean canAccess(@NonNull final UserPrivateUuid privateUuid, @NonNull final NumbersUuid numbersUuid) {
|
||||||
final User user = userAccessService.access(privateUuid);
|
final NumbersAccess access = access(privateUuid, numbersUuid);
|
||||||
final Numbers numbers = numbersRepository.findById(numbersUuid.uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
return access.numbers.getGroup().getUsers().contains(access.principal);
|
||||||
return numbers.containsUser(user);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@ -89,28 +57,44 @@ public class NumbersService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public NumbersDto fetchAndMarkAsRead(@NonNull final UserPrivateUuid privateUuid, @NonNull final NumbersUuid numbersUuid) {
|
public NumbersDto byUuid(@NonNull final UserPrivateUuid privateUuid, @NonNull final NumbersUuid numbersUuid) {
|
||||||
final NumbersAccess access = access(privateUuid, numbersUuid);
|
final NumbersAccess lotAccess = access(privateUuid, numbersUuid);
|
||||||
final ZonedDateTime now = ZonedDateTime.now();
|
return toDto(lotAccess);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public Page<NumbersDto> page(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid, final int page, final int pageSize) {
|
public Page<NumbersDto> 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")));
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
37
src/main/java/de/ph87/tools/tools/numbers/lot/NumberLot.java
Normal file
37
src/main/java/de/ph87/tools/tools/numbers/lot/NumberLot.java
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,35 +0,0 @@
|
|||||||
package de.ph87.tools.user.reference;
|
|
||||||
|
|
||||||
import de.ph87.tools.user.User;
|
|
||||||
import jakarta.annotation.Nullable;
|
|
||||||
import jakarta.persistence.*;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.ToString;
|
|
||||||
|
|
||||||
@Entity
|
|
||||||
@Getter
|
|
||||||
@ToString
|
|
||||||
@NoArgsConstructor
|
|
||||||
@Table(name = "`user_reference`")
|
|
||||||
public class UserReference {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@GeneratedValue
|
|
||||||
private long id;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@ManyToOne
|
|
||||||
private User user;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Column(nullable = false)
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
public UserReference(@NonNull final User user) {
|
|
||||||
this.user = user;
|
|
||||||
this.name = user.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
package de.ph87.tools.user.reference;
|
|
||||||
|
|
||||||
import org.springframework.data.repository.ListCrudRepository;
|
|
||||||
|
|
||||||
public interface UserReferenceRepository extends ListCrudRepository<UserReference, Long> {
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
package de.ph87.tools.user.reference;
|
|
||||||
|
|
||||||
import de.ph87.tools.user.User;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
@Transactional
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class UserReferenceService {
|
|
||||||
|
|
||||||
private final UserReferenceRepository userReferenceRepository;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public UserReference create(@NonNull final User user) {
|
|
||||||
return userReferenceRepository.save(new UserReference(user));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user