Compare commits
No commits in common. "e7dba8139b77042862fa331f16317a6d594a6cd6" and "3881f9b15fa30371d8ab51117f4670c016ef06a4" have entirely different histories.
e7dba8139b
...
3881f9b15f
50
src/main/angular/src/app/api/Subscribed.ts
Normal file
50
src/main/angular/src/app/api/Subscribed.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import {Subscription} from "rxjs";
|
||||||
|
import {Next} from "./common/types";
|
||||||
|
|
||||||
|
export class Subscribed<T> {
|
||||||
|
|
||||||
|
private subscription: Subscription | null = null;
|
||||||
|
|
||||||
|
private _value: T | null = null;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly same: (a: T, b: T) => boolean,
|
||||||
|
private readonly subscribe: (value: T, next: Next<T>) => Subscription,
|
||||||
|
) {
|
||||||
|
// -
|
||||||
|
}
|
||||||
|
|
||||||
|
get value(): T | null {
|
||||||
|
return this._value;
|
||||||
|
}
|
||||||
|
|
||||||
|
set value(value: T | null) {
|
||||||
|
if (!this.isSame(value)) {
|
||||||
|
this.unsubscribe();
|
||||||
|
if (value) {
|
||||||
|
this.subscription = this.subscribe(value, next => this.value = next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsubscribe() {
|
||||||
|
if (this.subscription) {
|
||||||
|
this.subscription.unsubscribe();
|
||||||
|
this.subscription = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private isSame(value: T | null) {
|
||||||
|
if (this._value === null) {
|
||||||
|
return value === null;
|
||||||
|
} else {
|
||||||
|
if (value === null) {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
return this.same(this._value, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,27 +1,24 @@
|
|||||||
import {validateBoolean, validateDate, validateString} from "../common/validators";
|
import {validateBoolean, validateDate, validateString} from "../common/validators";
|
||||||
import {UserPublic} from "./UserPublic";
|
|
||||||
|
|
||||||
export class UserPrivate extends UserPublic {
|
export class UserPrivate {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly privateUuid: string,
|
readonly privateUuid: string,
|
||||||
publicUuid: string,
|
readonly publicUuid: string,
|
||||||
readonly created: Date,
|
readonly created: Date,
|
||||||
name: string,
|
readonly name: string,
|
||||||
readonly password: boolean,
|
readonly password: boolean,
|
||||||
admin: boolean,
|
|
||||||
) {
|
) {
|
||||||
super(publicUuid, name, admin);
|
// -
|
||||||
}
|
}
|
||||||
|
|
||||||
static override fromJson(json: any): UserPrivate {
|
static fromJson(json: any): UserPrivate {
|
||||||
return new UserPrivate(
|
return new UserPrivate(
|
||||||
validateString(json['privateUuid']),
|
validateString(json['privateUuid']),
|
||||||
validateString(json['publicUuid']),
|
validateString(json['publicUuid']),
|
||||||
validateDate(json['created']),
|
validateDate(json['created']),
|
||||||
validateString(json['name']),
|
validateString(json['name']),
|
||||||
validateBoolean(json['password']),
|
validateBoolean(json['password']),
|
||||||
validateBoolean(json['admin']),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,4 +29,8 @@ export class UserPrivate extends UserPublic {
|
|||||||
return UserPrivate.fromJson(json);
|
return UserPrivate.fromJson(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static samePrivateUuid(a: UserPrivate, b: UserPrivate): boolean {
|
||||||
|
return a.privateUuid === b.privateUuid;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,10 @@
|
|||||||
import {validateBoolean, validateString} from "../common/validators";
|
import {validateString} from "../common/validators";
|
||||||
import {UserPrivate} from "./UserPrivate";
|
|
||||||
|
|
||||||
export class UserPublic {
|
export class UserPublic {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly publicUuid: string,
|
readonly publicUuid: string,
|
||||||
readonly name: string,
|
readonly name: string,
|
||||||
readonly admin: boolean,
|
|
||||||
) {
|
) {
|
||||||
// -
|
// -
|
||||||
}
|
}
|
||||||
@ -15,7 +13,6 @@ export class UserPublic {
|
|||||||
return new UserPublic(
|
return new UserPublic(
|
||||||
validateString(json['publicUuid']),
|
validateString(json['publicUuid']),
|
||||||
validateString(json['name']),
|
validateString(json['name']),
|
||||||
validateBoolean(json['admin']),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,8 +20,4 @@ export class UserPublic {
|
|||||||
return a.name.localeCompare(b.name);
|
return a.name.localeCompare(b.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
equals(user: UserPublic | UserPrivate | null) {
|
|
||||||
return user !== null && this.publicUuid === user.publicUuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +1,13 @@
|
|||||||
import {Injectable, Type} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {ApiService} from "../common/api.service";
|
import {ApiService} from "../common/api.service";
|
||||||
import {UserPrivate} from "./UserPrivate";
|
import {UserPrivate} from "./UserPrivate";
|
||||||
import {Next} from "../common/types";
|
import {Next} from "../common/types";
|
||||||
import {UserPublic} from "./UserPublic";
|
import {UserPublic} from "./UserPublic";
|
||||||
import {EventType, Router} from "@angular/router";
|
import {EventType, Router} from "@angular/router";
|
||||||
import {BehaviorSubject, filter, map, Subject, Subscription} from "rxjs";
|
import {BehaviorSubject, filter, Subject, Subscription} from "rxjs";
|
||||||
import {Group} from "../group/Group";
|
import {Group} from "../group/Group";
|
||||||
import {StompService} from "@stomp/ng2-stompjs";
|
import {StompService} from "@stomp/ng2-stompjs";
|
||||||
import {Numbers} from "../tools/Numbers/Numbers";
|
import {Numbers} from "../tools/Numbers/Numbers";
|
||||||
import {GroupDeletedEvent} from "../group/events/GroupDeletedEvent";
|
|
||||||
import {GroupLeftEvent} from "../group/events/GroupLeftEvent";
|
|
||||||
|
|
||||||
function userPushMessageFromJson(json: any): object {
|
function userPushMessageFromJson(json: any): object {
|
||||||
const type = json['_type_'];
|
const type = json['_type_'];
|
||||||
@ -20,10 +18,6 @@ function userPushMessageFromJson(json: any): object {
|
|||||||
return UserPrivate.fromJson(json['payload']);
|
return UserPrivate.fromJson(json['payload']);
|
||||||
case 'GroupDto':
|
case 'GroupDto':
|
||||||
return Group.fromJson(json['payload']);
|
return Group.fromJson(json['payload']);
|
||||||
case 'GroupDeletedEvent':
|
|
||||||
return GroupDeletedEvent.fromJson(json['payload']);
|
|
||||||
case 'GroupLeftEvent':
|
|
||||||
return GroupLeftEvent.fromJson(json['payload']);
|
|
||||||
}
|
}
|
||||||
throw new Error("Not implemented UserPushMessage._type_ = " + type);
|
throw new Error("Not implemented UserPushMessage._type_ = " + type);
|
||||||
}
|
}
|
||||||
@ -84,8 +78,14 @@ export class UserService {
|
|||||||
return this.subject.subscribe(next);
|
return this.subject.subscribe(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
subscribePush<T>(predicate: (m: any) => boolean, next: Next<T>): Subscription {
|
||||||
|
return this.pushSubject
|
||||||
|
.pipe(filter(predicate))
|
||||||
|
.subscribe(next);
|
||||||
|
}
|
||||||
|
|
||||||
iOwn(group: Group): boolean {
|
iOwn(group: Group): boolean {
|
||||||
return group.owner.equals(this.user);
|
return this.user?.publicUuid === group.owner.publicUuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
private setUser(user: UserPrivate | null) {
|
private setUser(user: UserPrivate | null) {
|
||||||
@ -99,17 +99,4 @@ export class UserService {
|
|||||||
this.subject.next(user);
|
this.subject.next(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
iAm(user: UserPublic | UserPrivate | null) {
|
|
||||||
return this.user !== null && this.user.equals(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
subscribePush<T>(TYPE: Type<T>, next: Next<T>): Subscription {
|
|
||||||
return this.pushSubject
|
|
||||||
.pipe(
|
|
||||||
filter(m => m instanceof TYPE),
|
|
||||||
map(m => m as T),
|
|
||||||
)
|
|
||||||
.subscribe(next);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,21 +1,18 @@
|
|||||||
import {UserPublic} from "../User/UserPublic";
|
import {UserPublic} from "../User/UserPublic";
|
||||||
import {validateBoolean, validateDate, validateList, validateString} from "../common/validators";
|
import {validateBoolean, validateDate, validateList, validateString} from "../common/validators";
|
||||||
import {UserPrivate} from "../User/UserPrivate";
|
|
||||||
import {GroupUuid} from "./GroupUuid";
|
|
||||||
|
|
||||||
export class Group extends GroupUuid {
|
export class Group {
|
||||||
|
|
||||||
constructor(
|
protected constructor(
|
||||||
uuid: string,
|
readonly uuid: string,
|
||||||
readonly owner: UserPublic,
|
readonly owner: UserPublic,
|
||||||
readonly created: Date,
|
readonly created: Date,
|
||||||
readonly title: string,
|
readonly title: string,
|
||||||
readonly password: string,
|
readonly password: string,
|
||||||
readonly users: UserPublic[],
|
readonly users: UserPublic[],
|
||||||
readonly banned: UserPublic[],
|
|
||||||
readonly initial: boolean,
|
readonly initial: boolean,
|
||||||
) {
|
) {
|
||||||
super(uuid);
|
// -
|
||||||
}
|
}
|
||||||
|
|
||||||
isOwner(user: UserPublic) {
|
isOwner(user: UserPublic) {
|
||||||
@ -30,7 +27,6 @@ export class Group extends GroupUuid {
|
|||||||
validateString(json['title']),
|
validateString(json['title']),
|
||||||
validateString(json['password']),
|
validateString(json['password']),
|
||||||
validateList(json['users'], UserPublic.fromJson),
|
validateList(json['users'], UserPublic.fromJson),
|
||||||
validateList(json['banned'], UserPublic.fromJson),
|
|
||||||
validateBoolean(json['initial']),
|
validateBoolean(json['initial']),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -48,17 +44,13 @@ export class Group extends GroupUuid {
|
|||||||
return UserPublic.compareName(a, b);
|
return UserPublic.compareName(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static sameUuid(a: Group, b: Group): boolean {
|
||||||
|
return a.uuid === b.uuid;
|
||||||
|
}
|
||||||
|
|
||||||
static compareCreated(a: Group, b: Group): number {
|
static compareCreated(a: Group, b: Group): number {
|
||||||
return a.created.getTime() - b.created.getTime();
|
return a.created.getTime() - b.created.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
isOwnedBy(user: UserPublic | UserPrivate | null) {
|
|
||||||
return user !== null && user.equals(this.owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
bannedByName() {
|
|
||||||
return this.banned.sort(UserPublic.compareName);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +0,0 @@
|
|||||||
export class GroupUuid {
|
|
||||||
|
|
||||||
protected constructor(
|
|
||||||
readonly uuid: string,
|
|
||||||
) {
|
|
||||||
// -
|
|
||||||
}
|
|
||||||
|
|
||||||
is(other: GroupUuid | null) {
|
|
||||||
return other !== null && this.uuid === other.uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
import {validateString} from "../../common/validators";
|
|
||||||
|
|
||||||
import {GroupUuid} from "../GroupUuid";
|
|
||||||
|
|
||||||
export class GroupDeletedEvent extends GroupUuid {
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
uuid: string,
|
|
||||||
) {
|
|
||||||
super(uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
static fromJson(json: any): GroupDeletedEvent {
|
|
||||||
return new GroupDeletedEvent(
|
|
||||||
validateString(json['uuid']),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
import {GroupUuid} from "../GroupUuid";
|
|
||||||
import {validateString} from "../../common/validators";
|
|
||||||
import {GroupDeletedEvent} from "./GroupDeletedEvent";
|
|
||||||
|
|
||||||
export class GroupLeftEvent extends GroupUuid {
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
uuid: string,
|
|
||||||
) {
|
|
||||||
super(uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
static fromJson(json: any): GroupDeletedEvent {
|
|
||||||
return new GroupDeletedEvent(
|
|
||||||
validateString(json['uuid']),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -5,11 +5,7 @@ import {Router} from "@angular/router";
|
|||||||
import {UserService} from "../User/user.service";
|
import {UserService} from "../User/user.service";
|
||||||
import {validateBoolean} from "../common/validators";
|
import {validateBoolean} from "../common/validators";
|
||||||
import {Injectable} from "@angular/core";
|
import {Injectable} from "@angular/core";
|
||||||
import {UserPublic} from "../User/UserPublic";
|
import {Subscribed} from "../Subscribed";
|
||||||
import {GroupUserRequest} from "./requests/GroupUserRequest";
|
|
||||||
import {GroupChangeTitleRequest} from "./requests/GroupChangeTitleRequest";
|
|
||||||
import {GroupChangePasswordRequest} from "./requests/GroupChangePasswordRequest";
|
|
||||||
import {GroupJoinRequest} from "./requests/GroupJoinRequest";
|
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@ -45,17 +41,26 @@ export class GroupService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
changeTitle(group: Group, title: string, next?: Next<Group>): void {
|
changeTitle(group: Group, title: string, next?: Next<Group>): void {
|
||||||
const data = new GroupChangeTitleRequest(group, title);
|
const data = {
|
||||||
|
uuid: group.uuid,
|
||||||
|
title: title,
|
||||||
|
};
|
||||||
this.api.postSingle(['Group', 'changeTitle'], data, Group.fromJson, next);
|
this.api.postSingle(['Group', 'changeTitle'], data, Group.fromJson, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
changePassword(group: Group, password: string, next?: Next<Group>): void {
|
changePassword(group: Group, password: string, next?: Next<Group>): void {
|
||||||
const data = new GroupChangePasswordRequest(group, password);
|
const data = {
|
||||||
|
uuid: group.uuid,
|
||||||
|
password: password,
|
||||||
|
};
|
||||||
this.api.postSingle(['Group', 'changePassword'], data, Group.fromJson, next);
|
this.api.postSingle(['Group', 'changePassword'], data, Group.fromJson, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
join(groupUuid: string, password: string, next: Next<Group>): void {
|
join(uuid: string, password: string, next: Next<Group>): void {
|
||||||
const data = new GroupJoinRequest(groupUuid, password);
|
const data = {
|
||||||
|
uuid: uuid,
|
||||||
|
password: password,
|
||||||
|
};
|
||||||
this.api.postSingle(['Group', 'join'], data, Group.fromJson, next);
|
this.api.postSingle(['Group', 'join'], data, Group.fromJson, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,6 +72,10 @@ export class GroupService {
|
|||||||
this.router.navigate(['Group', uuid]);
|
this.router.navigate(['Group', uuid]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newSubscriber(): Subscribed<Group> {
|
||||||
|
return new Subscribed<Group>(Group.sameUuid, (group, next) => this.api.subscribe(['Group', group.uuid], Group.fromJson, next));
|
||||||
|
}
|
||||||
|
|
||||||
gotoGroups(): void {
|
gotoGroups(): void {
|
||||||
this.router.navigate(['Groups']);
|
this.router.navigate(['Groups']);
|
||||||
}
|
}
|
||||||
@ -75,17 +84,5 @@ export class GroupService {
|
|||||||
this.api.postNone(['Group', 'delete'], group.uuid, next);
|
this.api.postNone(['Group', 'delete'], group.uuid, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
kick(group: Group, user: UserPublic, next?: Next<void>): void {
|
|
||||||
this.api.postNone(['Group', 'kick'], new GroupUserRequest(group, user), next);
|
|
||||||
}
|
|
||||||
|
|
||||||
ban(group: Group, user: UserPublic, next?: Next<void>): void {
|
|
||||||
this.api.postNone(['Group', 'ban'], new GroupUserRequest(group, user), next);
|
|
||||||
}
|
|
||||||
|
|
||||||
unban(group: Group, user: UserPublic, next?: Next<void>): void {
|
|
||||||
this.api.postNone(['Group', 'unban'], new GroupUserRequest(group, user), next);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +0,0 @@
|
|||||||
import {Group} from "../Group";
|
|
||||||
|
|
||||||
export class GroupChangePasswordRequest {
|
|
||||||
|
|
||||||
readonly groupUuid: string;
|
|
||||||
|
|
||||||
readonly password: string;
|
|
||||||
|
|
||||||
constructor(group: Group, password: string) {
|
|
||||||
this.groupUuid = group.uuid;
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
import {Group} from "../Group";
|
|
||||||
|
|
||||||
export class GroupChangeTitleRequest {
|
|
||||||
|
|
||||||
readonly groupUuid: string;
|
|
||||||
|
|
||||||
readonly title: string;
|
|
||||||
|
|
||||||
constructor(group: Group, title: string) {
|
|
||||||
this.groupUuid = group.uuid;
|
|
||||||
this.title = title;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
export class GroupJoinRequest {
|
|
||||||
|
|
||||||
readonly groupUuid: string;
|
|
||||||
|
|
||||||
readonly password: string;
|
|
||||||
|
|
||||||
constructor(groupUuid: string, password: string) {
|
|
||||||
this.groupUuid = groupUuid;
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
import {Group} from "../Group";
|
|
||||||
import {UserPublic} from "../../User/UserPublic";
|
|
||||||
|
|
||||||
export class GroupUserRequest {
|
|
||||||
|
|
||||||
readonly groupUuid: string;
|
|
||||||
|
|
||||||
readonly userPublicUuid: string;
|
|
||||||
|
|
||||||
constructor(group: Group, user: UserPublic) {
|
|
||||||
this.groupUuid = group.uuid;
|
|
||||||
this.userPublicUuid = user.publicUuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import {Group} from "../../group/Group";
|
import {Group} from "../../group/Group";
|
||||||
import {validateDate, validateDateOrNull, validateNumberOrNull, validateString} from "../../common/validators";
|
import {validateDate, validateNumber, validateString} from "../../common/validators";
|
||||||
|
|
||||||
export class Numbers {
|
export class Numbers {
|
||||||
|
|
||||||
@ -7,8 +7,7 @@ export class Numbers {
|
|||||||
readonly uuid: string,
|
readonly uuid: string,
|
||||||
readonly group: Group,
|
readonly group: Group,
|
||||||
readonly date: Date,
|
readonly date: Date,
|
||||||
readonly read: Date | null,
|
readonly number: number,
|
||||||
readonly number: number | null,
|
|
||||||
) {
|
) {
|
||||||
// -
|
// -
|
||||||
}
|
}
|
||||||
@ -18,8 +17,7 @@ export class Numbers {
|
|||||||
validateString(json['uuid']),
|
validateString(json['uuid']),
|
||||||
Group.fromJson(json['group']),
|
Group.fromJson(json['group']),
|
||||||
validateDate(json['date']),
|
validateDate(json['date']),
|
||||||
validateDateOrNull(json['read']),
|
validateNumber(json['number']),
|
||||||
validateNumberOrNull(json['number']),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,9 @@ export class NumbersService {
|
|||||||
protected readonly router: Router,
|
protected readonly router: Router,
|
||||||
protected readonly userService: UserService
|
protected readonly userService: UserService
|
||||||
) {
|
) {
|
||||||
// -
|
this.userService.subscribePush<Numbers>(m => m instanceof Numbers, message => {
|
||||||
|
this.router.navigate(['Numbers', message.uuid])
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
create(groupUuid: string): void {
|
create(groupUuid: string): void {
|
||||||
@ -28,8 +30,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 {
|
||||||
@ -40,8 +42,4 @@ export class NumbersService {
|
|||||||
this.api.postSingle(['Numbers', 'getGroupUuid'], numbersUuid, validateString, next);
|
this.api.postSingle(['Numbers', 'getGroupUuid'], numbersUuid, validateString, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
goto(numbers: Numbers) {
|
|
||||||
this.router.navigate(['Numbers', numbers.uuid]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<div class="tileContainer">
|
<div class="tileContainer">
|
||||||
|
|
||||||
<div class="tile" *ngIf="group === null && granted === false">
|
<div class="tile" *ngIf="granted === false">
|
||||||
<div class="tileInner">
|
<div class="tileInner">
|
||||||
<div class="tileTitle">
|
<div class="tileTitle">
|
||||||
Passwort
|
Passwort
|
||||||
@ -11,7 +11,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ng-container *ngIf="group">
|
<ng-container *ngIf="group.value">
|
||||||
|
|
||||||
<div class="tile">
|
<div class="tile">
|
||||||
<div class="tileInner">
|
<div class="tileInner">
|
||||||
@ -19,89 +19,35 @@
|
|||||||
Gruppe
|
Gruppe
|
||||||
</div>
|
</div>
|
||||||
<div class="tileContent">
|
<div class="tileContent">
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Erstellt</th>
|
<th>Erstellt</th>
|
||||||
<td>{{ group.created | date:'yyyy-MM-dd HH:mm' }}</td>
|
<td>{{ group.value.created | date:'yyyy-MM-dd HH:mm' }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Titel</th>
|
<th>Titel</th>
|
||||||
<td>
|
<td>
|
||||||
<app-text [initial]="group.title" [editable]="userService.iOwn(group)" (onChange)="changeTitle(group, $event)"></app-text>
|
<app-text [initial]="group.value.title" [editable]="userService.iOwn(group.value)" (onChange)="changeTitle(group.value, $event)"></app-text>
|
||||||
<ng-container *ngIf="!userService.iOwn(group)"></ng-container>
|
<ng-container *ngIf="!userService.iOwn(group.value)"></ng-container>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Passwort</th>
|
<th>Passwort</th>
|
||||||
<td>
|
<td>
|
||||||
<app-text [initial]="group.password" [editable]="userService.iOwn(group)" (onChange)="changePassword(group, $event)"></app-text>
|
<app-text [initial]="group.value.password" [editable]="userService.iOwn(group.value)" (onChange)="changePassword(group.value, $event)"></app-text>
|
||||||
<ng-container *ngIf="!userService.iOwn(group)"></ng-container>
|
<ng-container *ngIf="!userService.iOwn(group.value)"></ng-container>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
<tr>
|
||||||
|
<th>Teilnehmer</th>
|
||||||
<div class="buttons">
|
|
||||||
<div class="button buttonRight buttonDelete" (click)="groupDelete(group)">
|
|
||||||
Gruppe löschen
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="tile">
|
|
||||||
<div class="tileInner">
|
|
||||||
<div class="tileTitle">
|
|
||||||
Mitglieder
|
|
||||||
</div>
|
|
||||||
<div class="tileContent">
|
|
||||||
<div class="numbers">
|
|
||||||
<table>
|
|
||||||
<tr [class.user_owner]="group.isOwner(user)" *ngFor="let user of group.usersByNameOwnerFirst()">
|
|
||||||
<td (click)="userService.goto(user)">{{ user.name }}</td>
|
|
||||||
<td>
|
<td>
|
||||||
<span class="owner" *ngIf="group.isOwnedBy(user)">
|
<div class="user" [class.user_owner]="group.value.isOwner(user)" *ngFor="let user of group.value.usersByNameOwnerFirst()" (click)="userService.goto(user)">{{ user.name }}</div>
|
||||||
Admin
|
|
||||||
</span>
|
|
||||||
<div class="buttons">
|
|
||||||
<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 buttonRemove" (click)="groupService.kick(group, user)">Entfernen</div>
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="tile" *ngIf="group.banned.length > 0">
|
|
||||||
<div class="tileInner">
|
|
||||||
<div class="tileTitle">
|
|
||||||
Verbannt
|
|
||||||
</div>
|
|
||||||
<div class="tileContent">
|
|
||||||
<div class="numbers">
|
|
||||||
<table>
|
|
||||||
<tr [class.user_owner]="group.isOwner(user)" *ngFor="let user of group.bannedByName()" (click)="userService.goto(user)">
|
|
||||||
<td>{{ user.name }}</td>
|
|
||||||
<td>
|
|
||||||
<div class="buttons">
|
|
||||||
<ng-container *ngIf="userService.iOwn(group) && !userService.iAm(user)">
|
|
||||||
<div class="button buttonRight buttonUnban" (click)="groupService.unban(group, user)">Aufheben</div>
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="tile">
|
<div class="tile">
|
||||||
<div class="tileInner">
|
<div class="tileInner">
|
||||||
@ -109,17 +55,28 @@
|
|||||||
Nummern
|
Nummern
|
||||||
</div>
|
</div>
|
||||||
<div class="tileContent">
|
<div class="tileContent">
|
||||||
<div class="buttons">
|
|
||||||
<div class="button buttonRight buttonNext" *ngIf="userService.iOwn(group)" (click)="numbersService.create(group.uuid)">+ Nächste Runde</div>
|
|
||||||
</div>
|
|
||||||
<div class="numbers">
|
<div class="numbers">
|
||||||
<table>
|
<table>
|
||||||
<tr class="number" *ngFor="let numbers of numbersList.content" (click)="numbersService.goto(numbers)" [class.read]="numbers.read !== null">
|
<tr class="number" *ngFor="let numbers of numbersList.content">
|
||||||
<td>{{ numbers.date | relative:now }}</td>
|
<td>{{ numbers.date | relative:now }}</td>
|
||||||
<td>{{ numbers.number || '-' }}</td>
|
<td>{{ numbers.number }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<button *ngIf="userService.iOwn(group.value)" (click)="numbersService.create(group.value.uuid)">Numbers</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tile" *ngIf="userService.iOwn(group.value)">
|
||||||
|
<div class="tileInner">
|
||||||
|
<div class="tileTitle">
|
||||||
|
Löschen
|
||||||
|
</div>
|
||||||
|
<div class="tileContent">
|
||||||
|
<button (click)="delete(group.value)">
|
||||||
|
Löschen
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -3,23 +3,3 @@
|
|||||||
th {
|
th {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.read {
|
|
||||||
color: gray;
|
|
||||||
}
|
|
||||||
|
|
||||||
.unread {
|
|
||||||
background-color: lightskyblue;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonRemove {
|
|
||||||
color: orange;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonBan {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonUnban {
|
|
||||||
color: green;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -6,14 +6,13 @@ import {ActivatedRoute, Router} from "@angular/router";
|
|||||||
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 {Group} from "../../../api/group/Group";
|
import {Group} from "../../../api/group/Group";
|
||||||
|
import {Subscribed} from "../../../api/Subscribed";
|
||||||
import {NumbersService} from "../../../api/tools/Numbers/numbers.service";
|
import {NumbersService} from "../../../api/tools/Numbers/numbers.service";
|
||||||
import {PasswordComponent} from "../../../shared/password/password.component";
|
import {PasswordComponent} from "../../../shared/password/password.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";
|
||||||
import {Subscription, timer} from "rxjs";
|
import {Subscription, timer} from "rxjs";
|
||||||
import {GroupDeletedEvent} from "../../../api/group/events/GroupDeletedEvent";
|
|
||||||
import {GroupLeftEvent} from "../../../api/group/events/GroupLeftEvent";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-group',
|
selector: 'app-group',
|
||||||
@ -33,9 +32,7 @@ import {GroupLeftEvent} from "../../../api/group/events/GroupLeftEvent";
|
|||||||
})
|
})
|
||||||
export class GroupComponent implements OnInit, OnDestroy {
|
export class GroupComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
protected readonly subs: Subscription[] = [];
|
protected readonly group: Subscribed<Group>;
|
||||||
|
|
||||||
protected group: Group | null = null;
|
|
||||||
|
|
||||||
protected numbersList: Page<Numbers> = Page.EMPTY;
|
protected numbersList: Page<Numbers> = Page.EMPTY;
|
||||||
|
|
||||||
@ -45,6 +42,8 @@ export class GroupComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
protected now: Date = new Date();
|
protected now: Date = new Date();
|
||||||
|
|
||||||
|
private timer?: Subscription;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected readonly router: Router,
|
protected readonly router: Router,
|
||||||
protected readonly activatedRoute: ActivatedRoute,
|
protected readonly activatedRoute: ActivatedRoute,
|
||||||
@ -52,30 +51,12 @@ export class GroupComponent implements OnInit, OnDestroy {
|
|||||||
protected readonly userService: UserService,
|
protected readonly userService: UserService,
|
||||||
protected readonly numbersService: NumbersService,
|
protected readonly numbersService: NumbersService,
|
||||||
) {
|
) {
|
||||||
// -
|
this.group = this.groupService.newSubscriber();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.subs.push(timer(1000, 1000).subscribe(() => this.now = new Date()));
|
this.timer = timer(1000, 1000).subscribe(() => this.now = new Date());
|
||||||
this.subs.push(this.userService.subscribePush(Numbers, _ => {
|
this.activatedRoute.params.subscribe(params => {
|
||||||
this.updateNumbersList();
|
|
||||||
}));
|
|
||||||
this.subs.push(this.userService.subscribePush(Group, group => {
|
|
||||||
if (group.is(this.group)) {
|
|
||||||
this.group = group;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
this.subs.push(this.userService.subscribePush(GroupDeletedEvent, event => {
|
|
||||||
if (event.is(this.group)) {
|
|
||||||
this.groupService.gotoGroups();
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
this.subs.push(this.userService.subscribePush(GroupLeftEvent, event => {
|
|
||||||
if (event.is(this.group)) {
|
|
||||||
this.groupService.gotoGroups();
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
this.subs.push(this.activatedRoute.params.subscribe(params => {
|
|
||||||
const groupUuid = params['uuid'];
|
const groupUuid = params['uuid'];
|
||||||
this.uuid = groupUuid;
|
this.uuid = groupUuid;
|
||||||
this.granted = null;
|
this.granted = null;
|
||||||
@ -83,44 +64,38 @@ export class GroupComponent implements OnInit, OnDestroy {
|
|||||||
this.groupService.canAccess(groupUuid, granted => {
|
this.groupService.canAccess(groupUuid, granted => {
|
||||||
this.granted = granted;
|
this.granted = granted;
|
||||||
if (granted) {
|
if (granted) {
|
||||||
this.groupService.get(groupUuid, group => {
|
this.groupService.get(groupUuid, group => this.group.value = group);
|
||||||
this.group = group;
|
this.numbersService.page(groupUuid, 0, 10, numbersList => this.numbersList = numbersList);
|
||||||
this.updateNumbersList();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}));
|
});
|
||||||
}
|
|
||||||
|
|
||||||
private updateNumbersList() {
|
|
||||||
if (this.group) {
|
|
||||||
this.numbersService.page(this.group.uuid, 0, 10, numbersList => this.numbersList = numbersList);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.subs.forEach(sub => sub.unsubscribe());
|
if (this.timer) {
|
||||||
|
this.timer.unsubscribe();
|
||||||
|
this.timer = undefined;
|
||||||
|
}
|
||||||
|
this.group.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected changeTitle(group: Group, title: string): void {
|
protected changeTitle(group: Group, title: string): void {
|
||||||
this.groupService.changeTitle(group, title, group => this.group = group);
|
this.groupService.changeTitle(group, title, group => this.group.value = group);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected changePassword(group: Group, password: string): void {
|
protected changePassword(group: Group, password: string): void {
|
||||||
this.groupService.changePassword(group, password, group => this.group = group);
|
this.groupService.changePassword(group, password, group => this.group.value = group);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected join(password: string): void {
|
protected join(password: string): void {
|
||||||
if (this.uuid) {
|
if (this.uuid) {
|
||||||
this.groupService.join(this.uuid, password, group => this.group = group);
|
this.groupService.join(this.uuid, password, group => this.group.value = group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected groupDelete(group: Group): void {
|
protected delete(group: Group): void {
|
||||||
if (confirm("Gruppe \"" + group.title + "\" wirklich löschen?")) {
|
|
||||||
this.groupService.delete(group, () => this.groupService.gotoGroups());
|
this.groupService.delete(group, () => this.groupService.gotoGroups());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,9 +11,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
<div class="tileFooter">
|
<div class="tileFooter">
|
||||||
<div class="buttons">
|
<button (click)="create()">+ Neue Gruppen erstellen</button>
|
||||||
<div class="button buttonRight buttonCreate" (click)="create()">+ Neue Gruppen erstellen</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -5,24 +5,20 @@ import {NgIf} from "@angular/common";
|
|||||||
import {GroupService} from "../../../api/group/group.service";
|
import {GroupService} from "../../../api/group/group.service";
|
||||||
import {Group} from "../../../api/group/Group";
|
import {Group} from "../../../api/group/Group";
|
||||||
import {Subscription} from "rxjs";
|
import {Subscription} from "rxjs";
|
||||||
import {ReactiveFormsModule} from "@angular/forms";
|
|
||||||
import {GroupLeftEvent} from "../../../api/group/events/GroupLeftEvent";
|
|
||||||
import {GroupDeletedEvent} from "../../../api/group/events/GroupDeletedEvent";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-groups',
|
selector: 'app-groups',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [
|
imports: [
|
||||||
GroupListComponent,
|
GroupListComponent,
|
||||||
NgIf,
|
NgIf
|
||||||
ReactiveFormsModule
|
|
||||||
],
|
],
|
||||||
templateUrl: './groups.component.html',
|
templateUrl: './groups.component.html',
|
||||||
styleUrl: './groups.component.less'
|
styleUrl: './groups.component.less'
|
||||||
})
|
})
|
||||||
export class GroupsComponent implements OnInit, OnDestroy {
|
export class GroupsComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
private readonly subs: Subscription[] = [];
|
private readonly subscriptions: Subscription[] = [];
|
||||||
|
|
||||||
protected groups: Group[] = [];
|
protected groups: Group[] = [];
|
||||||
|
|
||||||
@ -34,18 +30,13 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.subs.push(this.userService.subscribePush(Group, _ => this.updateGroups()));
|
this.subscriptions.push(this.userService.subscribe(_ => {
|
||||||
this.subs.push(this.userService.subscribePush(GroupLeftEvent, _ => this.updateGroups()));
|
this.groupService.findAllJoined(groups => this.groups = groups);
|
||||||
this.subs.push(this.userService.subscribePush(GroupDeletedEvent, _ => this.updateGroups()));
|
}));
|
||||||
this.updateGroups();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.subs.forEach(sub => sub.unsubscribe());
|
this.subscriptions.forEach(subscription => subscription.unsubscribe());
|
||||||
}
|
|
||||||
|
|
||||||
private updateGroups() {
|
|
||||||
this.groupService.findAllJoined(groups => this.groups = groups);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
create(): void {
|
create(): void {
|
||||||
|
|||||||
@ -5,18 +5,16 @@
|
|||||||
[class.date_old]="now.getTime() - numbers.date.getTime() >= 5 * 60 * 1000"
|
[class.date_old]="now.getTime() - numbers.date.getTime() >= 5 * 60 * 1000"
|
||||||
>
|
>
|
||||||
|
|
||||||
|
<button *ngIf="userService.iOwn(numbers.group)" (click)="numbersService.create(numbers.group.uuid)">
|
||||||
|
Nächste Runde
|
||||||
|
</button>
|
||||||
|
|
||||||
<div class="date">
|
<div class="date">
|
||||||
{{ numbers.date | relative:now }}
|
{{ numbers.date | relative:now }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="huge" (click)="gotoGroup()">
|
<div class="huge">
|
||||||
{{ numbers.number || '-' }}
|
{{ numbers.number }}
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="buttons">
|
|
||||||
<div class="button buttonRight buttonNext" *ngIf="userService.iOwn(numbers.group)" (click)="numbersService.create(numbers.group.uuid)">
|
|
||||||
Nächste Runde
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import {Component, HostListener, OnDestroy, OnInit} from '@angular/core';
|
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||||
import {Numbers} from "../../../api/tools/Numbers/Numbers";
|
import {Numbers} from "../../../api/tools/Numbers/Numbers";
|
||||||
import {ActivatedRoute} from "@angular/router";
|
import {ActivatedRoute} from "@angular/router";
|
||||||
import {NumbersService} from "../../../api/tools/Numbers/numbers.service";
|
import {NumbersService} from "../../../api/tools/Numbers/numbers.service";
|
||||||
@ -46,7 +46,7 @@ export class NumbersComponent implements OnInit, OnDestroy {
|
|||||||
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));
|
||||||
}
|
}
|
||||||
@ -64,11 +64,4 @@ export class NumbersComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@HostListener('window:keydown.escape')
|
|
||||||
protected gotoGroup() {
|
|
||||||
if (this.numbers?.group) {
|
|
||||||
this.groupService.goto(this.numbers.group.uuid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
<ng-container *ngIf="visible">
|
<ng-container *ngIf="visible">
|
||||||
<h1>Passwort</h1>
|
<h1>Passwort</h1>
|
||||||
<input type="text" [(ngModel)]="password" (keydown.enter)="join.emit(password)">
|
<input type="text" [(ngModel)]="password" (keydown.enter)="join.emit(password)">
|
||||||
<div class="buttons">
|
<button (click)="join.emit(password)">Beitreten</button>
|
||||||
<div class="button buttonRight buttonJoin" (click)="join.emit(password)">Beitreten</div>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|||||||
@ -1,52 +1,2 @@
|
|||||||
@import "./tile.less";
|
@import "./tile.less";
|
||||||
@import "./user.less";
|
@import "./user.less";
|
||||||
|
|
||||||
.buttons {
|
|
||||||
margin-bottom: @halfSpace;
|
|
||||||
|
|
||||||
.button {
|
|
||||||
float: left;
|
|
||||||
margin-left: @quarterSpace;
|
|
||||||
margin-right: @quarterSpace;
|
|
||||||
padding: @halfSpace;
|
|
||||||
border-radius: @halfSpace;
|
|
||||||
background-color: #dddddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonRight {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonCreate {
|
|
||||||
background-color: lightgreen;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonCreate:hover {
|
|
||||||
background-color: limegreen;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonJoin {
|
|
||||||
background-color: lightskyblue;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonJoin:hover {
|
|
||||||
background-color: dodgerblue;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonNext {
|
|
||||||
background-color: lightgreen;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonNext:hover {
|
|
||||||
background-color: limegreen;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonDelete {
|
|
||||||
background-color: indianred;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonDelete:hover {
|
|
||||||
background-color: palevioletred;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,3 +1,2 @@
|
|||||||
@space: 0.5em;
|
@space: 0.5em;
|
||||||
@halfSpace: calc(@space / 2);
|
@halfSpace: calc(@space / 2);
|
||||||
@quarterSpace: calc(@halfSpace / 2);
|
|
||||||
|
|||||||
@ -55,15 +55,8 @@ public class Group extends GroupAbstract implements IWebSocketMessage {
|
|||||||
@NonNull
|
@NonNull
|
||||||
@ManyToMany
|
@ManyToMany
|
||||||
@ToString.Exclude
|
@ToString.Exclude
|
||||||
@JoinTable(name = "`group_user`")
|
|
||||||
private Set<User> users = new HashSet<>();
|
private Set<User> users = new HashSet<>();
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@ManyToMany
|
|
||||||
@ToString.Exclude
|
|
||||||
@JoinTable(name = "`group_banned`")
|
|
||||||
private Set<User> banned = new HashSet<>();
|
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
@NonNull
|
@NonNull
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
@ -96,8 +89,4 @@ public class Group extends GroupAbstract implements IWebSocketMessage {
|
|||||||
return List.of("Number", uuid);
|
return List.of("Number", uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isBanned(@NonNull final User user) {
|
|
||||||
return banned.stream().anyMatch(u -> u.equals(user));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,26 +0,0 @@
|
|||||||
package de.ph87.tools.group;
|
|
||||||
|
|
||||||
import de.ph87.tools.group.uuid.GroupUuid;
|
|
||||||
import de.ph87.tools.user.uuid.UserPrivateUuid;
|
|
||||||
import jakarta.annotation.Nullable;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
@CrossOrigin
|
|
||||||
@RestController
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@RequestMapping("Group")
|
|
||||||
public class GroupAccessController {
|
|
||||||
|
|
||||||
private final GroupAccessService groupAccessService;
|
|
||||||
|
|
||||||
@PostMapping("canAccess")
|
|
||||||
public boolean canAccess(@Nullable final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) {
|
|
||||||
return groupAccessService.canAccess(privateUuid, groupUuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package de.ph87.tools.group;
|
package de.ph87.tools.group;
|
||||||
|
|
||||||
import de.ph87.tools.group.uuid.GroupUuid;
|
import de.ph87.tools.group.uuid.GroupUuid;
|
||||||
|
import de.ph87.tools.tools.numbers.NumbersRepository;
|
||||||
import de.ph87.tools.user.User;
|
import de.ph87.tools.user.User;
|
||||||
import de.ph87.tools.user.UserService;
|
import de.ph87.tools.user.UserService;
|
||||||
import de.ph87.tools.user.uuid.UserPrivateUuid;
|
import de.ph87.tools.user.uuid.UserPrivateUuid;
|
||||||
@ -23,6 +24,8 @@ public class GroupAccessService {
|
|||||||
|
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
|
|
||||||
|
private final NumbersRepository numbersRepository;
|
||||||
|
|
||||||
public boolean canAccess(@Nullable final UserPrivateUuid userPrivateUuid, @NonNull final GroupUuid groupUuid) {
|
public boolean canAccess(@Nullable final UserPrivateUuid userPrivateUuid, @NonNull final GroupUuid groupUuid) {
|
||||||
final User user = userService.accessOrNull(userPrivateUuid);
|
final User user = userService.accessOrNull(userPrivateUuid);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
@ -32,6 +35,13 @@ public class GroupAccessService {
|
|||||||
return group.getUsers().contains(user);
|
return group.getUsers().contains(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void delete(@NonNull final UserPrivateUuid userPrivateUuid, @NonNull final GroupUuid groupUuid) {
|
||||||
|
final GroupAccess groupAccess = accessAsOwner(userPrivateUuid, groupUuid);
|
||||||
|
numbersRepository.deleteAllByGroup(groupAccess.group);
|
||||||
|
groupRepository.delete(groupAccess.group);
|
||||||
|
log.info("Group deleted: group={}", groupAccess.group);
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public GroupAccess access(@NonNull final UserPrivateUuid userPrivateUuid, @NonNull final GroupUuid groupUuid) {
|
public GroupAccess access(@NonNull final UserPrivateUuid userPrivateUuid, @NonNull final GroupUuid groupUuid) {
|
||||||
final User user = userService.access(userPrivateUuid);
|
final User user = userService.access(userPrivateUuid);
|
||||||
@ -40,7 +50,7 @@ public class GroupAccessService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public GroupAccess ownerAccess(@NonNull final UserPrivateUuid userPrivateUuid, @NonNull final GroupUuid groupUuid) {
|
public GroupAccess accessAsOwner(@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.user)) {
|
||||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
|
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
|
||||||
|
|||||||
79
src/main/java/de/ph87/tools/group/GroupController.java
Normal file
79
src/main/java/de/ph87/tools/group/GroupController.java
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
package de.ph87.tools.group;
|
||||||
|
|
||||||
|
import de.ph87.tools.group.requests.GroupChangePasswordRequest;
|
||||||
|
import de.ph87.tools.group.requests.GroupChangeTitleRequest;
|
||||||
|
import de.ph87.tools.group.requests.GroupJoinRequest;
|
||||||
|
import de.ph87.tools.group.uuid.GroupUuid;
|
||||||
|
import de.ph87.tools.user.uuid.UserPrivateUuid;
|
||||||
|
import de.ph87.tools.user.uuid.UserPublicUuid;
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@CrossOrigin
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("Group")
|
||||||
|
public class GroupController {
|
||||||
|
|
||||||
|
private final GroupService groupService;
|
||||||
|
|
||||||
|
private final GroupAccessService groupAccessService;
|
||||||
|
|
||||||
|
@GetMapping("create")
|
||||||
|
public GroupDto create(@Nullable final UserPrivateUuid privateUuid, @NonNull final HttpServletResponse response) {
|
||||||
|
return groupService.create(privateUuid, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("canAccess")
|
||||||
|
public boolean canAccess(@Nullable final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) {
|
||||||
|
return groupAccessService.canAccess(privateUuid, groupUuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("delete")
|
||||||
|
public void delete(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) {
|
||||||
|
groupAccessService.delete(privateUuid, groupUuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("get")
|
||||||
|
public GroupDto get(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) {
|
||||||
|
return groupService.get(privateUuid, groupUuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@GetMapping("findAllJoined")
|
||||||
|
public Set<GroupDto> findAllJoined(@NonNull final UserPrivateUuid userUuid) {
|
||||||
|
return groupService.findAllJoined(userUuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@PostMapping("findAllCommon")
|
||||||
|
public Set<GroupDto> findAllCommon(@NonNull final UserPrivateUuid userUuid, @NonNull final UserPublicUuid targetUuid) {
|
||||||
|
return groupService.findAllCommon(userUuid, targetUuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("join")
|
||||||
|
public GroupDto join(@Nullable final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupJoinRequest request, @NonNull final HttpServletResponse response) {
|
||||||
|
return groupService.join(privateUuid, request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("changeTitle")
|
||||||
|
public GroupDto changeTitle(@NonNull final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupChangeTitleRequest request) {
|
||||||
|
return groupService.changeTitle(privateUuid, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("changePassword")
|
||||||
|
public GroupDto changePassword(@NonNull final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupChangePasswordRequest request) {
|
||||||
|
return groupService.changePassword(privateUuid, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("leave")
|
||||||
|
public void leave(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) {
|
||||||
|
groupService.leave(privateUuid, groupUuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,9 +1,7 @@
|
|||||||
package de.ph87.tools.group.dto;
|
package de.ph87.tools.group;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
|
||||||
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.Group;
|
|
||||||
import de.ph87.tools.group.uuid.GroupUuid;
|
import de.ph87.tools.group.uuid.GroupUuid;
|
||||||
import de.ph87.tools.user.UserPublicDto;
|
import de.ph87.tools.user.UserPublicDto;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@ -28,50 +26,23 @@ public class GroupDto {
|
|||||||
public final ZonedDateTime created;
|
public final ZonedDateTime created;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@ToString.Exclude
|
|
||||||
public final String password;
|
public final String password;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@ToString.Exclude
|
|
||||||
public final UserPublicDto owner;
|
public final UserPublicDto owner;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@JsonIgnore
|
|
||||||
@ToString.Include
|
|
||||||
public String ownerPublicUuid() {
|
|
||||||
return owner.publicUuid.uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@ToString.Exclude
|
|
||||||
public final Set<UserPublicDto> users;
|
public final Set<UserPublicDto> users;
|
||||||
|
|
||||||
@JsonIgnore
|
|
||||||
@ToString.Include
|
|
||||||
public int users() {
|
|
||||||
return users.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@ToString.Exclude
|
|
||||||
public final Set<UserPublicDto> banned;
|
|
||||||
|
|
||||||
@JsonIgnore
|
|
||||||
@ToString.Include
|
|
||||||
public int banned() {
|
|
||||||
return banned.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean initial;
|
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) {
|
||||||
this.uuid = group.getUuid();
|
this.uuid = group.getUuid();
|
||||||
this.title = group.getTitle();
|
this.title = group.getTitle();
|
||||||
this.created = group.getCreated();
|
this.created = group.getCreated();
|
||||||
this.password = group.getPassword();
|
this.password = group.getPassword();
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
this.users = users;
|
this.users = users;
|
||||||
this.banned = banned;
|
|
||||||
this.initial = group.isInitial();
|
this.initial = group.isInitial();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
package de.ph87.tools.group;
|
|
||||||
|
|
||||||
import de.ph87.tools.group.dto.GroupDto;
|
|
||||||
import de.ph87.tools.group.requests.GroupJoinRequest;
|
|
||||||
import de.ph87.tools.group.uuid.GroupUuid;
|
|
||||||
import de.ph87.tools.user.uuid.UserPrivateUuid;
|
|
||||||
import jakarta.annotation.Nullable;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
@CrossOrigin
|
|
||||||
@RestController
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@RequestMapping("Group")
|
|
||||||
public class GroupMemberController {
|
|
||||||
|
|
||||||
private final GroupMemberService groupMemberService;
|
|
||||||
|
|
||||||
@PostMapping("join")
|
|
||||||
public GroupDto join(@Nullable final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupJoinRequest request, @NonNull final HttpServletResponse response) {
|
|
||||||
return groupMemberService.join(privateUuid, request, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("leave")
|
|
||||||
public void leave(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) {
|
|
||||||
groupMemberService.leave(privateUuid, groupUuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,78 +0,0 @@
|
|||||||
package de.ph87.tools.group;
|
|
||||||
|
|
||||||
import de.ph87.tools.group.dto.GroupDto;
|
|
||||||
import de.ph87.tools.group.events.GroupLeftEvent;
|
|
||||||
import de.ph87.tools.group.requests.GroupJoinRequest;
|
|
||||||
import de.ph87.tools.group.uuid.GroupUuid;
|
|
||||||
import de.ph87.tools.user.User;
|
|
||||||
import de.ph87.tools.user.UserService;
|
|
||||||
import de.ph87.tools.user.push.UserPushService;
|
|
||||||
import de.ph87.tools.user.uuid.UserPrivateUuid;
|
|
||||||
import jakarta.annotation.Nullable;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
import org.springframework.web.server.ResponseStatusException;
|
|
||||||
|
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
@Transactional
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class GroupMemberService {
|
|
||||||
|
|
||||||
private final UserService userService;
|
|
||||||
|
|
||||||
private final GroupReadService groupReadService;
|
|
||||||
|
|
||||||
private final UserPushService userPushService;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public GroupDto join(@Nullable final UserPrivateUuid privateUuid, @NonNull final GroupJoinRequest request, @NonNull final HttpServletResponse response) {
|
|
||||||
final User user = userService.getUserByPrivateUuidOrElseCreate(privateUuid, response);
|
|
||||||
final Group group = groupReadService.getGroupByGroupUuid(request.groupUuid);
|
|
||||||
if (group.isBanned(user)) {
|
|
||||||
log.error("User is banned from Group and cannot join it: user={}, group={}", user, group);
|
|
||||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
|
|
||||||
}
|
|
||||||
if (!group.getPassword().equals(request.password)) {
|
|
||||||
log.error("Wrong password: user={}, group={}", user, group);
|
|
||||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
|
|
||||||
}
|
|
||||||
return _add_user_to_group_unchecked(group, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void leave(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) {
|
|
||||||
final User user = userService.access(privateUuid);
|
|
||||||
final Group group = groupReadService.getGroupByGroupUuid(groupUuid);
|
|
||||||
if (group.isOwnedBy(user)) {
|
|
||||||
// owner cannot remove itself from group
|
|
||||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
|
|
||||||
}
|
|
||||||
_remove_user_from_group_unchecked(group, user, (g, u) -> log.info("User left Group: user={}, group={}", u, g));
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public GroupDto _add_user_to_group_unchecked(@NonNull final Group group, @NonNull final User user) {
|
|
||||||
group.getUsers().add(user);
|
|
||||||
group.touch();
|
|
||||||
user.touch();
|
|
||||||
log.info("User joined Group: user={}, group={}", user, group);
|
|
||||||
return groupReadService.publish(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void _remove_user_from_group_unchecked(@NonNull final Group group, @NonNull final User user, @NonNull final BiConsumer<Group, User> beforePush) {
|
|
||||||
group.getUsers().remove(user);
|
|
||||||
group.touch();
|
|
||||||
user.touch();
|
|
||||||
beforePush.accept(group, user);
|
|
||||||
userPushService.push(user, new GroupLeftEvent(group));
|
|
||||||
groupReadService.publish(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,58 +0,0 @@
|
|||||||
package de.ph87.tools.group;
|
|
||||||
|
|
||||||
import de.ph87.tools.group.dto.GroupDto;
|
|
||||||
import de.ph87.tools.group.requests.GroupChangePasswordRequest;
|
|
||||||
import de.ph87.tools.group.requests.GroupChangeTitleRequest;
|
|
||||||
import de.ph87.tools.group.requests.GroupUserRequest;
|
|
||||||
import de.ph87.tools.group.uuid.GroupUuid;
|
|
||||||
import de.ph87.tools.user.uuid.UserPrivateUuid;
|
|
||||||
import jakarta.annotation.Nullable;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
@CrossOrigin
|
|
||||||
@RestController
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@RequestMapping("Group")
|
|
||||||
public class GroupOwnerController {
|
|
||||||
|
|
||||||
private final GroupOwnerService groupOwnerService;
|
|
||||||
|
|
||||||
@GetMapping("create")
|
|
||||||
public GroupDto create(@Nullable final UserPrivateUuid privateUuid, @NonNull final HttpServletResponse response) {
|
|
||||||
return groupOwnerService.create(privateUuid, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("delete")
|
|
||||||
public void delete(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) {
|
|
||||||
groupOwnerService.delete(privateUuid, groupUuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("kick")
|
|
||||||
public void kick(@NonNull final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupUserRequest request) {
|
|
||||||
groupOwnerService.kick(privateUuid, request);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("ban")
|
|
||||||
public void ban(@NonNull final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupUserRequest request) {
|
|
||||||
groupOwnerService.ban(privateUuid, request);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("unban")
|
|
||||||
public void unban(@NonNull final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupUserRequest request) {
|
|
||||||
groupOwnerService.unban(privateUuid, request);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("changeTitle")
|
|
||||||
public GroupDto changeTitle(@NonNull final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupChangeTitleRequest request) {
|
|
||||||
return groupOwnerService.changeTitle(privateUuid, request);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("changePassword")
|
|
||||||
public GroupDto changePassword(@NonNull final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupChangePasswordRequest request) {
|
|
||||||
return groupOwnerService.changePassword(privateUuid, request);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,141 +0,0 @@
|
|||||||
package de.ph87.tools.group;
|
|
||||||
|
|
||||||
import de.ph87.tools.group.dto.GroupDto;
|
|
||||||
import de.ph87.tools.group.events.GroupDeletedEvent;
|
|
||||||
import de.ph87.tools.group.requests.GroupChangePasswordRequest;
|
|
||||||
import de.ph87.tools.group.requests.GroupChangeTitleRequest;
|
|
||||||
import de.ph87.tools.group.requests.GroupUserRequest;
|
|
||||||
import de.ph87.tools.group.uuid.GroupUuid;
|
|
||||||
import de.ph87.tools.tools.numbers.NumbersRepository;
|
|
||||||
import de.ph87.tools.user.User;
|
|
||||||
import de.ph87.tools.user.UserService;
|
|
||||||
import de.ph87.tools.user.push.UserPushService;
|
|
||||||
import de.ph87.tools.user.uuid.UserPrivateUuid;
|
|
||||||
import jakarta.annotation.Nullable;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.ToString;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
import org.springframework.web.server.ResponseStatusException;
|
|
||||||
|
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
@Transactional
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class GroupOwnerService {
|
|
||||||
|
|
||||||
private final GroupAccessService groupAccessService;
|
|
||||||
|
|
||||||
private final GroupRepository groupRepository;
|
|
||||||
|
|
||||||
private final UserService userService;
|
|
||||||
|
|
||||||
private final GroupReadService groupReadService;
|
|
||||||
|
|
||||||
private final GroupMemberService groupMemberService;
|
|
||||||
|
|
||||||
private final NumbersRepository numbersRepository;
|
|
||||||
|
|
||||||
private final UserPushService userPushService;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public GroupDto create(@Nullable final UserPrivateUuid privateUuid, @NonNull final HttpServletResponse response) {
|
|
||||||
final User user = userService.getUserByPrivateUuidOrElseCreate(privateUuid, response);
|
|
||||||
final Group group = _create_unchecked(user);
|
|
||||||
return groupMemberService._add_user_to_group_unchecked(group, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void delete(@NonNull final UserPrivateUuid userPrivateUuid, @NonNull final GroupUuid groupUuid) {
|
|
||||||
final GroupAccess access = groupAccessService.ownerAccess(userPrivateUuid, groupUuid);
|
|
||||||
numbersRepository.deleteAllByGroup(access.group);
|
|
||||||
groupRepository.delete(access.group);
|
|
||||||
log.info("Group deleted: group={}", access.group);
|
|
||||||
|
|
||||||
final GroupDeletedEvent event = new GroupDeletedEvent(access.group);
|
|
||||||
access.group.getUsers().forEach(user -> userPushService.push(user, event));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void kick(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUserRequest request) {
|
|
||||||
final OwnerRemoveResult result = _removeUser(privateUuid, request, (group, user) -> log.info("User kicked out of group: user={}, group={}", user, group));
|
|
||||||
groupReadService.publish(result.group);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ban(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUserRequest request) {
|
|
||||||
final OwnerRemoveResult result = _removeUser(privateUuid, request, (group, user) -> log.info("User banned from group: user={}, group={}", user, group));
|
|
||||||
result.group.getBanned().add(result.kicked);
|
|
||||||
groupReadService.publish(result.group);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unban(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUserRequest request) {
|
|
||||||
final GroupAccess access = groupAccessService.ownerAccess(privateUuid, request.groupUuid);
|
|
||||||
final User user = access.group.getBanned().stream().filter(u -> u.getPublicUuid().equals(request.userPublicUuid)).findFirst().orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
|
||||||
access.group.getBanned().remove(user);
|
|
||||||
log.info("User unbanned from group: user={}, group={}", user, access.group);
|
|
||||||
groupReadService.publish(access.group);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public GroupDto changeTitle(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupChangeTitleRequest request) {
|
|
||||||
final GroupAccess ug = groupAccessService.access(privateUuid, request.groupUuid);
|
|
||||||
if (!ug.group.isOwnedBy(ug.user)) {
|
|
||||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
|
|
||||||
}
|
|
||||||
ug.group.setTitle(request.title);
|
|
||||||
return groupReadService.publish(ug.group);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public GroupDto changePassword(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupChangePasswordRequest request) {
|
|
||||||
final GroupAccess access = groupAccessService.ownerAccess(privateUuid, request.groupUuid);
|
|
||||||
access.group.setPassword(request.password);
|
|
||||||
return groupReadService.publish(access.group);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* EXECUTORS ------------------------------------------------------------------------------------ */
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private Group _create_unchecked(@NonNull final User user) {
|
|
||||||
final Group group = groupRepository.save(new Group(user));
|
|
||||||
log.info("Group CREATED: {}", group);
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private 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 User user = access.group.getUsers().stream().filter(u -> u.getPublicUuid().equals(request.userPublicUuid)).findFirst().orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
|
||||||
if (user.equals(access.user)) {
|
|
||||||
// owner cannot kick itself from group
|
|
||||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
|
|
||||||
}
|
|
||||||
groupMemberService._remove_user_from_group_unchecked(access.group, user, beforePush);
|
|
||||||
return new OwnerRemoveResult(access, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* RESULT CLASSES ------------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@ToString
|
|
||||||
private static class OwnerRemoveResult {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final Group group;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final User kicked;
|
|
||||||
|
|
||||||
public OwnerRemoveResult(@NonNull final GroupAccess access, @NonNull final User kicked) {
|
|
||||||
this.group = access.group;
|
|
||||||
this.kicked = kicked;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
package de.ph87.tools.group;
|
|
||||||
|
|
||||||
import de.ph87.tools.group.dto.GroupDto;
|
|
||||||
import de.ph87.tools.group.uuid.GroupUuid;
|
|
||||||
import de.ph87.tools.user.uuid.UserPrivateUuid;
|
|
||||||
import de.ph87.tools.user.uuid.UserPublicUuid;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
@CrossOrigin
|
|
||||||
@RestController
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@RequestMapping("Group")
|
|
||||||
public class GroupReadController {
|
|
||||||
|
|
||||||
private final GroupReadService groupReadService;
|
|
||||||
|
|
||||||
@PostMapping("get")
|
|
||||||
public GroupDto get(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) {
|
|
||||||
return groupReadService.get(privateUuid, groupUuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@GetMapping("findAllJoined")
|
|
||||||
public Set<GroupDto> findAllJoined(@NonNull final UserPrivateUuid userUuid) {
|
|
||||||
return groupReadService.findAllJoined(userUuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@PostMapping("findAllCommon")
|
|
||||||
public Set<GroupDto> findAllCommon(@NonNull final UserPrivateUuid userUuid, @NonNull final UserPublicUuid targetUuid) {
|
|
||||||
return groupReadService.findAllCommon(userUuid, targetUuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,86 +0,0 @@
|
|||||||
package de.ph87.tools.group;
|
|
||||||
|
|
||||||
import de.ph87.tools.group.dto.GroupDto;
|
|
||||||
import de.ph87.tools.group.uuid.GroupUuid;
|
|
||||||
import de.ph87.tools.user.User;
|
|
||||||
import de.ph87.tools.user.UserPublicDto;
|
|
||||||
import de.ph87.tools.user.UserService;
|
|
||||||
import de.ph87.tools.user.push.UserPushService;
|
|
||||||
import de.ph87.tools.user.uuid.UserPrivateUuid;
|
|
||||||
import de.ph87.tools.user.uuid.UserPublicUuid;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
import org.springframework.web.server.ResponseStatusException;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
@Transactional
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class GroupReadService {
|
|
||||||
|
|
||||||
private final GroupAccessService groupAccessService;
|
|
||||||
|
|
||||||
private final GroupRepository groupRepository;
|
|
||||||
|
|
||||||
private final UserPushService userPushService;
|
|
||||||
|
|
||||||
private final UserService userService;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public GroupDto get(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) {
|
|
||||||
final GroupAccess ug = groupAccessService.access(privateUuid, groupUuid);
|
|
||||||
return toDto(ug.group);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public Group getGroupByGroupUuid(@NonNull final GroupUuid groupUuid) {
|
|
||||||
return groupRepository.findByUuid(groupUuid.uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* DTO ------------------------------------------------------------------------------------------ */
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public GroupDto toDto(@NonNull final Group group) {
|
|
||||||
final UserPublicDto owner = new UserPublicDto(group.getOwner());
|
|
||||||
final Set<UserPublicDto> users = group.getUsers().stream().map(UserPublicDto::new).collect(Collectors.toSet());
|
|
||||||
final Set<UserPublicDto> banned = group.getBanned().stream().map(UserPublicDto::new).collect(Collectors.toSet());
|
|
||||||
return new GroupDto(group, owner, users, banned);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* PUBLISH -------------------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public GroupDto publish(@NonNull final Group group) {
|
|
||||||
final GroupDto dto = toDto(group);
|
|
||||||
group.getUsers().forEach(user -> userPushService.push(user, dto));
|
|
||||||
return dto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIND & GET ----------------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public Set<GroupDto> findAllCommonGroups(@NonNull final User a, @NonNull final User b) {
|
|
||||||
return groupRepository.findAllByUsersContainsAndUsersContains(a, b).stream().map(this::toDto).collect(Collectors.toSet());
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public Set<GroupDto> findAllJoined(@NonNull final UserPrivateUuid privateUuid) {
|
|
||||||
final User principal = userService.access(privateUuid);
|
|
||||||
return groupRepository.findAllByUsersContains(principal).stream().map(this::toDto).collect(Collectors.toSet());
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public Set<GroupDto> findAllCommon(@NonNull final UserPrivateUuid privateUuid, @NonNull final UserPublicUuid targetUuid) {
|
|
||||||
final User principal = userService.access(privateUuid);
|
|
||||||
final User target = userService.getByPublicUuid(targetUuid);
|
|
||||||
return findAllCommonGroups(principal, target);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
156
src/main/java/de/ph87/tools/group/GroupService.java
Normal file
156
src/main/java/de/ph87/tools/group/GroupService.java
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
package de.ph87.tools.group;
|
||||||
|
|
||||||
|
import de.ph87.tools.group.requests.GroupChangePasswordRequest;
|
||||||
|
import de.ph87.tools.group.requests.GroupChangeTitleRequest;
|
||||||
|
import de.ph87.tools.group.requests.GroupJoinRequest;
|
||||||
|
import de.ph87.tools.group.uuid.GroupUuid;
|
||||||
|
import de.ph87.tools.user.User;
|
||||||
|
import de.ph87.tools.user.UserPublicDto;
|
||||||
|
import de.ph87.tools.user.UserService;
|
||||||
|
import de.ph87.tools.user.push.UserPushService;
|
||||||
|
import de.ph87.tools.user.uuid.UserPrivateUuid;
|
||||||
|
import de.ph87.tools.user.uuid.UserPublicUuid;
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class GroupService {
|
||||||
|
|
||||||
|
private final GroupAccessService groupAccessService;
|
||||||
|
|
||||||
|
private final GroupRepository groupRepository;
|
||||||
|
|
||||||
|
private final UserPushService userPushService;
|
||||||
|
|
||||||
|
private final UserService userService;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public GroupDto create(@Nullable final UserPrivateUuid privateUuid, @NonNull final HttpServletResponse response) {
|
||||||
|
final User user = userService.getUserByPrivateUuidOrElseCreate(privateUuid, response);
|
||||||
|
final Group group = createUnchecked(user);
|
||||||
|
return doJoinUnchecked(group, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public GroupDto get(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) {
|
||||||
|
final GroupAccess ug = groupAccessService.access(privateUuid, groupUuid);
|
||||||
|
return toDto(ug.group);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public GroupDto join(@Nullable final UserPrivateUuid privateUuid, @NonNull final GroupJoinRequest request, @NonNull final HttpServletResponse response) {
|
||||||
|
final User user = userService.getUserByPrivateUuidOrElseCreate(privateUuid, response);
|
||||||
|
final Group group = getByGroupByGroupUuid(request.uuid);
|
||||||
|
if (!group.getPassword().equals(request.password)) {
|
||||||
|
log.error("Wrong password: user={}, group={}", user, group);
|
||||||
|
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
|
||||||
|
}
|
||||||
|
return doJoinUnchecked(group, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private Group getByGroupByGroupUuid(@NonNull final GroupUuid groupUuid) {
|
||||||
|
return groupRepository.findByUuid(groupUuid.uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public GroupDto changeTitle(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupChangeTitleRequest request) {
|
||||||
|
final GroupAccess ug = groupAccessService.access(privateUuid, request.uuid);
|
||||||
|
if (!ug.group.isOwnedBy(ug.user)) {
|
||||||
|
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
|
||||||
|
}
|
||||||
|
ug.group.setTitle(request.title);
|
||||||
|
return publish(ug.group);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public GroupDto changePassword(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupChangePasswordRequest request) {
|
||||||
|
final GroupAccess access = groupAccessService.accessAsOwner(privateUuid, request.uuid);
|
||||||
|
access.group.setPassword(request.password);
|
||||||
|
return publish(access.group);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void leave(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) {
|
||||||
|
final User user = userService.access(privateUuid);
|
||||||
|
final Group group = getByGroupByGroupUuid(groupUuid);
|
||||||
|
doLeaveUnchecked(group, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CREATE, JOIN, LEAVE -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private Group createUnchecked(@NonNull final User user) {
|
||||||
|
final Group group = groupRepository.save(new Group(user));
|
||||||
|
log.info("Group CREATED: {}", group);
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private GroupDto doJoinUnchecked(@NonNull final Group group, @NonNull final User user) {
|
||||||
|
group.getUsers().add(user);
|
||||||
|
group.touch();
|
||||||
|
user.touch();
|
||||||
|
log.info("User joined Group: user={}, group={}", user, group);
|
||||||
|
return publish(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doLeaveUnchecked(final Group group, final User user) {
|
||||||
|
group.getUsers().remove(user);
|
||||||
|
group.touch();
|
||||||
|
user.touch();
|
||||||
|
log.info("User left Group: user={}, group={}", user, group);
|
||||||
|
publish(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DTO ------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public GroupDto toDto(@NonNull final Group group) {
|
||||||
|
final UserPublicDto owner = new UserPublicDto(group.getOwner());
|
||||||
|
final Set<UserPublicDto> users = group.getUsers().stream().map(UserPublicDto::new).collect(Collectors.toSet());
|
||||||
|
return new GroupDto(group, owner, users);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PUBLISH -------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public GroupDto publish(@NonNull final Group group) {
|
||||||
|
final GroupDto dto = toDto(group);
|
||||||
|
group.getUsers().forEach(user -> userPushService.push(user, dto));
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIND & GET ----------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public Set<GroupDto> findAllCommonGroups(@NonNull final User a, @NonNull final User b) {
|
||||||
|
return groupRepository.findAllByUsersContainsAndUsersContains(a, b).stream().map(this::toDto).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public Set<GroupDto> findAllJoined(@NonNull final UserPrivateUuid privateUuid) {
|
||||||
|
final User principal = userService.access(privateUuid);
|
||||||
|
return groupRepository.findAllByUsersContains(principal).stream().map(this::toDto).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public Set<GroupDto> findAllCommon(@NonNull final UserPrivateUuid privateUuid, @NonNull final UserPublicUuid targetUuid) {
|
||||||
|
final User principal = userService.access(privateUuid);
|
||||||
|
final User target = userService.getByPublicUuid(targetUuid);
|
||||||
|
return findAllCommonGroups(principal, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,22 +0,0 @@
|
|||||||
package de.ph87.tools.group.events;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
|
||||||
import de.ph87.tools.common.uuid.UuidSerializer;
|
|
||||||
import de.ph87.tools.group.Group;
|
|
||||||
import de.ph87.tools.group.uuid.GroupUuid;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.ToString;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@ToString
|
|
||||||
public class GroupDeletedEvent {
|
|
||||||
|
|
||||||
@JsonSerialize(using = UuidSerializer.class)
|
|
||||||
public final GroupUuid uuid;
|
|
||||||
|
|
||||||
public GroupDeletedEvent(@NonNull final Group group) {
|
|
||||||
this.uuid = group.getUuid();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
package de.ph87.tools.group.events;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
|
||||||
import de.ph87.tools.common.uuid.UuidSerializer;
|
|
||||||
import de.ph87.tools.group.Group;
|
|
||||||
import de.ph87.tools.group.uuid.GroupUuid;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.ToString;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@ToString
|
|
||||||
public class GroupLeftEvent {
|
|
||||||
|
|
||||||
@JsonSerialize(using = UuidSerializer.class)
|
|
||||||
public final GroupUuid uuid;
|
|
||||||
|
|
||||||
public GroupLeftEvent(@NonNull final Group group) {
|
|
||||||
this.uuid = group.getUuid();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -15,7 +15,7 @@ public class GroupChangePasswordRequest {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@JsonDeserialize(using = GroupUuidDeserializer.class)
|
@JsonDeserialize(using = GroupUuidDeserializer.class)
|
||||||
public final GroupUuid groupUuid;
|
public final GroupUuid uuid;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final String password;
|
public final String password;
|
||||||
|
|||||||
@ -15,7 +15,7 @@ public class GroupChangeTitleRequest {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@JsonDeserialize(using = GroupUuidDeserializer.class)
|
@JsonDeserialize(using = GroupUuidDeserializer.class)
|
||||||
public final GroupUuid groupUuid;
|
public final GroupUuid uuid;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final String title;
|
public final String title;
|
||||||
|
|||||||
@ -15,7 +15,7 @@ public class GroupJoinRequest {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@JsonDeserialize(using = GroupUuidDeserializer.class)
|
@JsonDeserialize(using = GroupUuidDeserializer.class)
|
||||||
public final GroupUuid groupUuid;
|
public final GroupUuid uuid;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final String password;
|
public final String password;
|
||||||
|
|||||||
@ -1,26 +0,0 @@
|
|||||||
package de.ph87.tools.group.requests;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
|
||||||
import de.ph87.tools.group.uuid.GroupUuid;
|
|
||||||
import de.ph87.tools.group.uuid.GroupUuidDeserializer;
|
|
||||||
import de.ph87.tools.user.uuid.UserPublicUuid;
|
|
||||||
import de.ph87.tools.user.uuid.UserPublicUuidDeserializer;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.ToString;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@ToString
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class GroupUserRequest {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@JsonDeserialize(using = GroupUuidDeserializer.class)
|
|
||||||
public final GroupUuid groupUuid;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@JsonDeserialize(using = UserPublicUuidDeserializer.class)
|
|
||||||
public final UserPublicUuid userPublicUuid;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -5,7 +5,6 @@ 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 de.ph87.tools.user.reference.UserReference;
|
||||||
import jakarta.annotation.Nullable;
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
@ -44,12 +43,7 @@ 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
|
|
||||||
@OneToMany(orphanRemoval = true)
|
@OneToMany(orphanRemoval = true)
|
||||||
private List<UserReference> users;
|
private List<UserReference> users;
|
||||||
|
|
||||||
@ -58,22 +52,14 @@ public class Numbers extends NumbersAbstract {
|
|||||||
this.users = users;
|
this.users = users;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRead(@NonNull final ZonedDateTime date) {
|
public int getNumberForUser(@NonNull final User user) {
|
||||||
if (this.read != null) {
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
this.read = date;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public Integer getNumberForUser(@NonNull final User user) {
|
|
||||||
for (int userReferenceIndex = 0; userReferenceIndex < users.size(); userReferenceIndex++) {
|
for (int userReferenceIndex = 0; userReferenceIndex < users.size(); userReferenceIndex++) {
|
||||||
final UserReference userReference = users.get(userReferenceIndex);
|
final UserReference userReference = users.get(userReferenceIndex);
|
||||||
if (userReference.getUser() != null && userReference.getUser().equals(user)) {
|
if (userReference.getUser() != null && userReference.getUser().equals(user)) {
|
||||||
return userReferenceIndex + 1;
|
return userReferenceIndex + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean containsUser(@NonNull final User user) {
|
public boolean containsUser(@NonNull final User user) {
|
||||||
|
|||||||
@ -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.dtoByUuid(privateUuid, numbersUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,10 +2,9 @@ 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.GroupDto;
|
||||||
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 lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
@ -26,16 +25,11 @@ public class NumbersDto extends NumbersAbstract {
|
|||||||
@NonNull
|
@NonNull
|
||||||
private final ZonedDateTime date;
|
private final ZonedDateTime date;
|
||||||
|
|
||||||
@Nullable
|
private final int number;
|
||||||
private final ZonedDateTime read;
|
|
||||||
|
|
||||||
@Nullable
|
public NumbersDto(@NonNull final Numbers numbers, @NonNull final GroupDto group, final int number) {
|
||||||
private final Integer number;
|
|
||||||
|
|
||||||
public NumbersDto(@NonNull final Numbers numbers, @NonNull final GroupDto group, @Nullable final Integer number) {
|
|
||||||
this.uuid = numbers.getUuid();
|
this.uuid = numbers.getUuid();
|
||||||
this.date = numbers.getDate();
|
this.date = numbers.getDate();
|
||||||
this.read = numbers.getRead();
|
|
||||||
this.group = group;
|
this.group = group;
|
||||||
this.number = number;
|
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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,8 +2,8 @@ package de.ph87.tools.tools.numbers;
|
|||||||
|
|
||||||
import de.ph87.tools.group.GroupAccess;
|
import de.ph87.tools.group.GroupAccess;
|
||||||
import de.ph87.tools.group.GroupAccessService;
|
import de.ph87.tools.group.GroupAccessService;
|
||||||
import de.ph87.tools.group.dto.GroupDto;
|
import de.ph87.tools.group.GroupDto;
|
||||||
import de.ph87.tools.group.GroupReadService;
|
import de.ph87.tools.group.GroupService;
|
||||||
import de.ph87.tools.group.uuid.GroupUuid;
|
import de.ph87.tools.group.uuid.GroupUuid;
|
||||||
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;
|
||||||
@ -23,7 +23,6 @@ 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.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -41,14 +40,14 @@ public class NumbersService {
|
|||||||
|
|
||||||
private final UserReferenceService userReferenceService;
|
private final UserReferenceService userReferenceService;
|
||||||
|
|
||||||
private final GroupReadService groupReadService;
|
private final GroupService groupService;
|
||||||
|
|
||||||
private final UserPushService userPushService;
|
private final UserPushService userPushService;
|
||||||
|
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
|
|
||||||
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.accessAsOwner(userPrivateUuid, groupUuid);
|
||||||
final List<UserReference> users = access.getGroup().getUsers().stream().map(userReferenceService::create).collect(Collectors.toList());
|
final List<UserReference> users = access.getGroup().getUsers().stream().map(userReferenceService::create).collect(Collectors.toList());
|
||||||
Collections.shuffle(users);
|
Collections.shuffle(users);
|
||||||
final Numbers numbers = numbersRepository.save(new Numbers(access.getGroup(), users));
|
final Numbers numbers = numbersRepository.save(new Numbers(access.getGroup(), users));
|
||||||
@ -71,8 +70,8 @@ public class NumbersService {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public NumbersDto toDto(@NonNull final Numbers numbers, @NonNull final User user) {
|
public NumbersDto toDto(@NonNull final Numbers numbers, @NonNull final User user) {
|
||||||
final GroupDto group = groupReadService.toDto(numbers.getGroup());
|
final GroupDto group = groupService.toDto(numbers.getGroup());
|
||||||
final Integer number = numbers.getNumberForUser(user);
|
final int number = numbers.getNumberForUser(user);
|
||||||
return new NumbersDto(numbers, group, number);
|
return new NumbersDto(numbers, group, number);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,10 +88,8 @@ public class NumbersService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public NumbersDto fetchAndMarkAsRead(@NonNull final UserPrivateUuid privateUuid, @NonNull final NumbersUuid numbersUuid) {
|
public NumbersDto dtoByUuid(@NonNull final UserPrivateUuid privateUuid, @NonNull final NumbersUuid numbersUuid) {
|
||||||
final NumbersAccess access = access(privateUuid, 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);
|
return toDto(access.numbers, access.user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -35,15 +35,12 @@ public class UserPrivateDto extends UserPublicAbstract {
|
|||||||
|
|
||||||
private final boolean password;
|
private final boolean password;
|
||||||
|
|
||||||
private final boolean admin;
|
|
||||||
|
|
||||||
public UserPrivateDto(@NonNull final User user) {
|
public UserPrivateDto(@NonNull final User user) {
|
||||||
this.publicUuid = user.getPublicUuid();
|
this.publicUuid = user.getPublicUuid();
|
||||||
this.privateUuid = user.getPrivateUuid();
|
this.privateUuid = user.getPrivateUuid();
|
||||||
this.name = user.getName();
|
this.name = user.getName();
|
||||||
this.created = user.getCreated();
|
this.created = user.getCreated();
|
||||||
this.password = !user.getPassword().isEmpty();
|
this.password = !user.getPassword().isEmpty();
|
||||||
this.admin = user.isAdmin();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|||||||
@ -19,12 +19,9 @@ public class UserPublicDto extends UserPublicAbstract {
|
|||||||
@NonNull
|
@NonNull
|
||||||
public final String name;
|
public final String name;
|
||||||
|
|
||||||
public final boolean admin;
|
|
||||||
|
|
||||||
public UserPublicDto(@NonNull final User user) {
|
public UserPublicDto(@NonNull final User user) {
|
||||||
this.publicUuid = user.getPublicUuid();
|
this.publicUuid = user.getPublicUuid();
|
||||||
this.name = user.getName();
|
this.name = user.getName();
|
||||||
this.admin = user.isAdmin();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,14 +31,7 @@ public class UserPrivateUuidArgumentResolver implements HandlerMethodArgumentRes
|
|||||||
if (!(webRequest.getNativeRequest() instanceof final HttpServletRequest request)) {
|
if (!(webRequest.getNativeRequest() instanceof final HttpServletRequest request)) {
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
final Cookie[] cookies = request.getCookies();
|
final String uuid = Arrays.stream(request.getCookies()).filter(cookie -> USER_UUID_COOKIE_NAME.equalsIgnoreCase(cookie.getName())).findFirst().map(Cookie::getValue).orElse(null);
|
||||||
if (cookies == null) {
|
|
||||||
if (!nullable) {
|
|
||||||
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final String uuid = Arrays.stream(cookies).filter(cookie -> USER_UUID_COOKIE_NAME.equalsIgnoreCase(cookie.getName())).findFirst().map(Cookie::getValue).orElse(null);
|
|
||||||
if (uuid == null || uuid.length() != 36) {
|
if (uuid == null || uuid.length() != 36) {
|
||||||
if (!nullable) {
|
if (!nullable) {
|
||||||
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
|
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
|
||||||
|
|||||||
@ -1,18 +0,0 @@
|
|||||||
package de.ph87.tools.user.uuid;
|
|
||||||
|
|
||||||
import de.ph87.tools.common.uuid.AbstractUuidDeserializer;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.NonNull;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@NoArgsConstructor
|
|
||||||
public class UserPublicUuidDeserializer extends AbstractUuidDeserializer {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
protected UserPublicUuid create(@NonNull final String s) {
|
|
||||||
return new UserPublicUuid(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user