HUGE REFACTOR: Using immutable Uuid classes + ArgumentResolvers in Controllers
This commit is contained in:
parent
24c873f0ba
commit
a678cf3416
@ -7,15 +7,17 @@ import {EventType, Router} from "@angular/router";
|
|||||||
import {BehaviorSubject, filter, 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 {NumbersPrivateDto} from "../tools/Numbers/NumbersPrivateDto";
|
import {Numbers} from "../tools/Numbers/Numbers";
|
||||||
|
|
||||||
function userPushMessageFromJson(json: any): object {
|
function userPushMessageFromJson(json: any): object {
|
||||||
const type = json['_type_'];
|
const type = json['_type_'];
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'NumbersPrivateDto':
|
case 'NumbersDto':
|
||||||
return NumbersPrivateDto.fromJson(json['payload']);
|
return Numbers.fromJson(json['payload']);
|
||||||
case 'UserPrivateDto':
|
case 'UserPrivateDto':
|
||||||
return UserPrivate.fromJson(json['payload']);
|
return UserPrivate.fromJson(json['payload']);
|
||||||
|
case 'GroupDto':
|
||||||
|
return Group.fromJson(json['payload']);
|
||||||
}
|
}
|
||||||
throw new Error("Not implemented UserPushMessage._type_ = " + type);
|
throw new Error("Not implemented UserPushMessage._type_ = " + type);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,10 +17,10 @@ export class Page<T> {
|
|||||||
|
|
||||||
static fromJson<T>(fromJson: FromJson<T>): FromJson<Page<T>> {
|
static fromJson<T>(fromJson: FromJson<T>): FromJson<Page<T>> {
|
||||||
return (json: any) => new Page<T>(
|
return (json: any) => new Page<T>(
|
||||||
validateNumber(json.page.size),
|
validateNumber(json.size),
|
||||||
validateNumber(json.page.number),
|
validateNumber(json.number),
|
||||||
validateNumber(json.page.totalPages),
|
validateNumber(json.totalPages),
|
||||||
validateNumber(json.page.totalElements),
|
validateNumber(json.totalElements),
|
||||||
validateList(json.content, fromJson),
|
validateList(json.content, fromJson),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,6 +52,10 @@ export class ApiService {
|
|||||||
return this.http.get<any>(getApiUrl('http', path), {withCredentials: true}).pipe(map(fromJson)).subscribe(next);
|
return this.http.get<any>(getApiUrl('http', path), {withCredentials: true}).pipe(map(fromJson)).subscribe(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPage<T>(path: any[], fromJson: FromJson<T>, next: Next<Page<T>> | undefined = undefined): Subscription {
|
||||||
|
return this.http.get<any>(getApiUrl('http', path), {withCredentials: true}).pipe(map(Page.fromJson(fromJson))).subscribe(next);
|
||||||
|
}
|
||||||
|
|
||||||
getList<T>(path: any[], fromJson: FromJson<T>, next: Next<T[]> | undefined = undefined): Subscription {
|
getList<T>(path: any[], fromJson: FromJson<T>, next: Next<T[]> | undefined = undefined): Subscription {
|
||||||
return this.http.get<any[]>(getApiUrl('http', path), {withCredentials: true}).pipe(map(list => list.map(fromJson))).subscribe(next);
|
return this.http.get<any[]>(getApiUrl('http', path), {withCredentials: true}).pipe(map(list => list.map(fromJson))).subscribe(next);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import {Group} from "../../group/Group";
|
import {Group} from "../../group/Group";
|
||||||
import {validateDate, validateNumber, validateString} from "../../common/validators";
|
import {validateDate, validateNumber, validateString} from "../../common/validators";
|
||||||
|
|
||||||
export class NumbersPrivateDto {
|
export class Numbers {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly uuid: string,
|
readonly uuid: string,
|
||||||
@ -12,8 +12,8 @@ export class NumbersPrivateDto {
|
|||||||
// -
|
// -
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJson(json: any): NumbersPrivateDto {
|
static fromJson(json: any): Numbers {
|
||||||
return new NumbersPrivateDto(
|
return new Numbers(
|
||||||
validateString(json['uuid']),
|
validateString(json['uuid']),
|
||||||
Group.fromJson(json['group']),
|
Group.fromJson(json['group']),
|
||||||
validateDate(json['date']),
|
validateDate(json['date']),
|
||||||
@ -3,8 +3,9 @@ import {ApiService} from "../../common/api.service";
|
|||||||
import {Router} from "@angular/router";
|
import {Router} from "@angular/router";
|
||||||
import {UserService} from "../../User/user.service";
|
import {UserService} from "../../User/user.service";
|
||||||
import {Next} from "../../common/types";
|
import {Next} from "../../common/types";
|
||||||
import {NumbersPrivateDto} from "./NumbersPrivateDto";
|
import {Numbers} from "./Numbers";
|
||||||
import {validateBoolean, validateString} from "../../common/validators";
|
import {validateBoolean, validateString} from "../../common/validators";
|
||||||
|
import {Page} from "../../common/Page";
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@ -16,25 +17,29 @@ export class NumbersService {
|
|||||||
protected readonly router: Router,
|
protected readonly router: Router,
|
||||||
protected readonly userService: UserService
|
protected readonly userService: UserService
|
||||||
) {
|
) {
|
||||||
this.userService.subscribePush<NumbersPrivateDto>(m => m instanceof NumbersPrivateDto, message => {
|
this.userService.subscribePush<Numbers>(m => m instanceof Numbers, message => {
|
||||||
this.router.navigate(['Numbers', message.uuid])
|
this.router.navigate(['Numbers', message.uuid])
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
create(groupUuid: string) {
|
create(groupUuid: string): void {
|
||||||
this.api.getNone(['Numbers', 'create', groupUuid]);
|
this.api.getNone(['Numbers', 'create', groupUuid]);
|
||||||
}
|
}
|
||||||
|
|
||||||
byUuid(uuid: string, next: Next<NumbersPrivateDto>) {
|
page(groupUuid: string, page: number, pageSize: number, next: Next<Page<Numbers>>): void {
|
||||||
this.api.postSingle(['Numbers', 'byUuid'], uuid, NumbersPrivateDto.fromJson, next);
|
this.api.getPage(['Numbers', 'page', groupUuid, page, pageSize], Numbers.fromJson, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
canAccess(uuid: string, next: Next<boolean>) {
|
byUuid(numbersUuid: string, next: Next<Numbers>): void {
|
||||||
this.api.postSingle(['Numbers', 'canAccess'], uuid, validateBoolean, next);
|
this.api.postSingle(['Numbers', 'byUuid'], numbersUuid, Numbers.fromJson, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
getGroupUuid(uuid: string | null, next: Next<string>) {
|
canAccess(numbersUuid: string, next: Next<boolean>): void {
|
||||||
this.api.postSingle(['Numbers', 'getGroupUuid'], uuid, validateString, next);
|
this.api.postSingle(['Numbers', 'canAccess'], numbersUuid, validateBoolean, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
getGroupUuid(numbersUuid: string | null, next: Next<string>): void {
|
||||||
|
this.api.postSingle(['Numbers', 'getGroupUuid'], numbersUuid, validateString, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,24 @@
|
|||||||
<ng-container *ngIf="group.value">
|
<div class="tileContainer">
|
||||||
<h1>Gruppe</h1>
|
|
||||||
|
<div class="tile" *ngIf="granted === false">
|
||||||
|
<div class="tileInner">
|
||||||
|
<div class="tileTitle">
|
||||||
|
Passwort
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tileContent">
|
||||||
|
<app-password [visible]="true" (join)="join($event)"></app-password>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ng-container *ngIf="group.value">
|
||||||
|
|
||||||
|
<div class="tile">
|
||||||
|
<div class="tileInner">
|
||||||
|
<div class="tileTitle">
|
||||||
|
Gruppe
|
||||||
|
</div>
|
||||||
|
<div class="tileContent">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Erstellt</th>
|
<th>Erstellt</th>
|
||||||
@ -26,9 +45,29 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tile">
|
||||||
|
<div class="tileInner">
|
||||||
|
<div class="tileTitle">
|
||||||
|
Nummern
|
||||||
|
</div>
|
||||||
|
<div class="tileContent">
|
||||||
|
<div class="numbers">
|
||||||
|
<table>
|
||||||
|
<tr class="number" *ngFor="let numbers of numbersList.content">
|
||||||
|
<td>{{ numbers.date | relative:now }}</td>
|
||||||
|
<td>{{ numbers.number }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
<button *ngIf="userService.iOwn(group.value)" (click)="numbersService.create(group.value.uuid)">Numbers</button>
|
<button *ngIf="userService.iOwn(group.value)" (click)="numbersService.create(group.value.uuid)">Numbers</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<app-password [visible]="granted === false" (join)="join($event)"></app-password>
|
</div>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||||
import {DatePipe, NgForOf, NgIf} from "@angular/common";
|
import {DatePipe, NgForOf, NgIf} from "@angular/common";
|
||||||
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
|
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
|
||||||
import {TextComponent} from "../../../shared/text/text.component";
|
import {TextComponent} from "../../../shared/text/text.component";
|
||||||
@ -9,6 +9,10 @@ import {Group} from "../../../api/group/Group";
|
|||||||
import {Subscribed} from "../../../api/Subscribed";
|
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 {Page} from "../../../api/common/Page";
|
||||||
|
import {RelativePipe} from "../../../shared/relative.pipe";
|
||||||
|
import {Subscription, timer} from "rxjs";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-group',
|
selector: 'app-group',
|
||||||
@ -20,19 +24,26 @@ import {PasswordComponent} from "../../../shared/password/password.component";
|
|||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
TextComponent,
|
TextComponent,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
PasswordComponent
|
PasswordComponent,
|
||||||
|
RelativePipe
|
||||||
],
|
],
|
||||||
templateUrl: './group.component.html',
|
templateUrl: './group.component.html',
|
||||||
styleUrl: './group.component.less'
|
styleUrl: './group.component.less'
|
||||||
})
|
})
|
||||||
export class GroupComponent implements OnInit {
|
export class GroupComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
protected readonly group: Subscribed<Group>;
|
protected readonly group: Subscribed<Group>;
|
||||||
|
|
||||||
|
protected numbersList: Page<Numbers> = Page.EMPTY;
|
||||||
|
|
||||||
protected granted: boolean | null = null;
|
protected granted: boolean | null = null;
|
||||||
|
|
||||||
protected uuid: string | null = null;
|
protected uuid: string | null = null;
|
||||||
|
|
||||||
|
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,
|
||||||
@ -44,21 +55,30 @@ export class GroupComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
this.timer = timer(1000, 1000).subscribe(() => this.now = new Date());
|
||||||
this.activatedRoute.params.subscribe(params => {
|
this.activatedRoute.params.subscribe(params => {
|
||||||
const uuid = params['uuid'];
|
const groupUuid = params['uuid'];
|
||||||
this.uuid = uuid;
|
this.uuid = groupUuid;
|
||||||
this.granted = null;
|
this.granted = null;
|
||||||
if (uuid) {
|
if (groupUuid) {
|
||||||
this.groupService.canAccess(uuid, granted => {
|
this.groupService.canAccess(groupUuid, granted => {
|
||||||
this.granted = granted;
|
this.granted = granted;
|
||||||
if (granted) {
|
if (granted) {
|
||||||
this.groupService.get(uuid, group => this.group.value = group);
|
this.groupService.get(groupUuid, group => this.group.value = group);
|
||||||
|
this.numbersService.page(groupUuid, 0, 10, numbersList => this.numbersList = numbersList);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
if (this.timer) {
|
||||||
|
this.timer.unsubscribe();
|
||||||
|
this.timer = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected changeTitle(group: Group, title: string) {
|
protected changeTitle(group: Group, title: string) {
|
||||||
this.groupService.changeTitle(group, title, group => this.group.value = group);
|
this.groupService.changeTitle(group, title, group => this.group.value = group);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||||
import {NumbersPrivateDto} from "../../../api/tools/Numbers/NumbersPrivateDto";
|
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";
|
||||||
import {NgIf} from "@angular/common";
|
import {NgIf} from "@angular/common";
|
||||||
@ -24,7 +24,7 @@ import {Subscription, timer} from "rxjs";
|
|||||||
})
|
})
|
||||||
export class NumbersComponent implements OnInit, OnDestroy {
|
export class NumbersComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
protected numbers: NumbersPrivateDto | null = null;
|
protected numbers: Numbers | null = null;
|
||||||
|
|
||||||
protected now: Date = new Date();
|
protected now: Date = new Date();
|
||||||
|
|
||||||
|
|||||||
@ -1,40 +0,0 @@
|
|||||||
package de.ph87.tools;
|
|
||||||
|
|
||||||
import de.ph87.tools.user.User;
|
|
||||||
import jakarta.servlet.http.Cookie;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import org.springframework.core.MethodParameter;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
|
||||||
import org.springframework.web.context.request.NativeWebRequest;
|
|
||||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
|
||||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
public class UserArgumentResolver implements HandlerMethodArgumentResolver {
|
|
||||||
|
|
||||||
public static final String USER_UUID_COOKIE_NAME = "PatrixToolsUserUuid";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supportsParameter(@NonNull final MethodParameter parameter) {
|
|
||||||
return parameter.getParameterType() == User.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public User resolveArgument(@NonNull final MethodParameter parameter, final ModelAndViewContainer mavContainer, @NonNull final NativeWebRequest webRequest, final WebDataBinderFactory binderFactory) {
|
|
||||||
if (!(webRequest instanceof final HttpServletRequest request)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String uuid = Arrays.stream(request.getCookies()).filter(cookie -> USER_UUID_COOKIE_NAME.equalsIgnoreCase(cookie.getName())).findFirst().map(Cookie::getValue).orElse(null);
|
|
||||||
if (uuid == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
43
src/main/java/de/ph87/tools/common/uuid/AbstractUuid.java
Normal file
43
src/main/java/de/ph87/tools/common/uuid/AbstractUuid.java
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package de.ph87.tools.common.uuid;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public abstract class AbstractUuid {
|
||||||
|
|
||||||
|
public final String uuid;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused") // used by lombok @NoArgsConstructor
|
||||||
|
protected AbstractUuid() {
|
||||||
|
this(UUID.randomUUID().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractUuid(@NonNull final String uuid) {
|
||||||
|
if (uuid.length() != 36) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
this.uuid = uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return uuid.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object obj) {
|
||||||
|
if (obj instanceof final AbstractUuid casted) {
|
||||||
|
return uuid.equals(casted.uuid);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package de.ph87.tools.common.uuid;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||||
|
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public abstract class AbstractUuidDeserializer extends JsonDeserializer<AbstractUuid> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbstractUuid deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext) throws IOException {
|
||||||
|
return create(jsonParser.readValueAs(String.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
protected abstract AbstractUuid create(@NonNull final String s);
|
||||||
|
|
||||||
|
}
|
||||||
20
src/main/java/de/ph87/tools/common/uuid/UuidSerializer.java
Normal file
20
src/main/java/de/ph87/tools/common/uuid/UuidSerializer.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package de.ph87.tools.common.uuid;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
|
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||||
|
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class UuidSerializer extends JsonSerializer<AbstractUuid> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serialize(final AbstractUuid t, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider) throws IOException {
|
||||||
|
if (t == null) {
|
||||||
|
jsonGenerator.writeNull();
|
||||||
|
} else {
|
||||||
|
jsonGenerator.writeString(t.uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
package de.ph87.tools.group;
|
package de.ph87.tools.group;
|
||||||
|
|
||||||
|
import de.ph87.tools.group.uuid.GroupAbstract;
|
||||||
|
import de.ph87.tools.group.uuid.GroupUuid;
|
||||||
import de.ph87.tools.user.User;
|
import de.ph87.tools.user.User;
|
||||||
import de.ph87.tools.web.IWebSocketMessage;
|
import de.ph87.tools.web.IWebSocketMessage;
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
@ -16,13 +18,24 @@ import java.util.UUID;
|
|||||||
@ToString
|
@ToString
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@Table(name = "`group`")
|
@Table(name = "`group`")
|
||||||
public class Group implements IWebSocketMessage {
|
public class Group extends GroupAbstract implements IWebSocketMessage {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@NonNull
|
@NonNull
|
||||||
@Column(nullable = false)
|
@Getter(AccessLevel.NONE)
|
||||||
private String uuid = UUID.randomUUID().toString();
|
private String uuid = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private GroupUuid _uuid;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public GroupUuid getUuid() {
|
||||||
|
if (_uuid == null) {
|
||||||
|
_uuid = new GroupUuid(uuid);
|
||||||
|
}
|
||||||
|
return _uuid;
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@ManyToOne(optional = false)
|
@ManyToOne(optional = false)
|
||||||
private User owner;
|
private User owner;
|
||||||
@ -68,22 +81,4 @@ public class Group implements IWebSocketMessage {
|
|||||||
return List.of("Number", uuid);
|
return List.of("Number", uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
|
||||||
public boolean isOwnedBy(@NonNull final User user) {
|
|
||||||
return owner.equals(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(final Object obj) {
|
|
||||||
if (!(obj instanceof final Group group)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return group.uuid.equals(this.uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return uuid.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import de.ph87.tools.user.User;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class Access {
|
public class GroupAccess {
|
||||||
|
|
||||||
public final User user;
|
public final User user;
|
||||||
|
|
||||||
@ -1,7 +1,9 @@
|
|||||||
package de.ph87.tools.group;
|
package de.ph87.tools.group;
|
||||||
|
|
||||||
|
import de.ph87.tools.group.uuid.GroupUuid;
|
||||||
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 jakarta.annotation.Nullable;
|
import jakarta.annotation.Nullable;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -21,7 +23,7 @@ public class GroupAccessService {
|
|||||||
|
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
|
|
||||||
public boolean canAccess(@NonNull final String groupUuid, @Nullable final String userPrivateUuid) {
|
public boolean canAccess(@NonNull final GroupUuid groupUuid, @Nullable final UserPrivateUuid userPrivateUuid) {
|
||||||
final User user = userService.accessOrNull(userPrivateUuid);
|
final User user = userService.accessOrNull(userPrivateUuid);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return false;
|
return false;
|
||||||
@ -31,14 +33,14 @@ public class GroupAccessService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public Access access(@NonNull final String groupUuid, @NonNull final String userPrivateUuid) {
|
public GroupAccess access(@NonNull final UserPrivateUuid userPrivateUuid, @NonNull final GroupUuid groupUuid) {
|
||||||
final User user = userService.access(userPrivateUuid);
|
final User user = userService.access(userPrivateUuid);
|
||||||
final Group group = getByUuidOrThrow(groupUuid);
|
final Group group = getByUuidOrThrow(groupUuid);
|
||||||
return new Access(user, group);
|
return new GroupAccess(user, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Access accessAsOwner(@NonNull final String userPrivateUuid, @NonNull final String groupUuid) {
|
public GroupAccess accessAsOwner(@NonNull final UserPrivateUuid userPrivateUuid, @NonNull final GroupUuid groupUuid) {
|
||||||
final Access access = access(groupUuid, userPrivateUuid);
|
final GroupAccess access = access(userPrivateUuid, groupUuid);
|
||||||
if (!access.group.isOwnedBy(access.user)) {
|
if (!access.group.isOwnedBy(access.user)) {
|
||||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
|
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
@ -46,8 +48,8 @@ public class GroupAccessService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private Group getByUuidOrThrow(@NonNull final String groupUuid) {
|
private Group getByUuidOrThrow(@NonNull final GroupUuid groupUuid) {
|
||||||
return groupRepository.findById(groupUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
return groupRepository.findByUuid(groupUuid.uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +0,0 @@
|
|||||||
package de.ph87.tools.group;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.ToString;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@ToString
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class GroupChangePasswordInbound {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final String uuid;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final String password;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
package de.ph87.tools.group;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.ToString;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@ToString
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class GroupChangeTitleRequest {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final String uuid;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final String title;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,5 +1,11 @@
|
|||||||
package de.ph87.tools.group;
|
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.annotation.Nullable;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
@ -8,8 +14,6 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static de.ph87.tools.UserArgumentResolver.USER_UUID_COOKIE_NAME;
|
|
||||||
|
|
||||||
@CrossOrigin
|
@CrossOrigin
|
||||||
@RestController
|
@RestController
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@ -21,49 +25,49 @@ public class GroupController {
|
|||||||
private final GroupAccessService groupAccessService;
|
private final GroupAccessService groupAccessService;
|
||||||
|
|
||||||
@GetMapping("create")
|
@GetMapping("create")
|
||||||
public GroupDto create(@CookieValue(name = USER_UUID_COOKIE_NAME, required = false) @Nullable final String privateUuid, @NonNull final HttpServletResponse response) {
|
public GroupDto create(@Nullable final UserPrivateUuid privateUuid, @NonNull final HttpServletResponse response) {
|
||||||
return groupService.create(privateUuid, response);
|
return groupService.create(privateUuid, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("canAccess")
|
@PostMapping("canAccess")
|
||||||
public boolean canAccess(@CookieValue(name = USER_UUID_COOKIE_NAME, required = false) @Nullable final String privateUuid, @NonNull @RequestBody final String groupUuid) {
|
public boolean canAccess(@Nullable final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) {
|
||||||
return groupAccessService.canAccess(groupUuid, privateUuid);
|
return groupAccessService.canAccess(groupUuid, privateUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("get")
|
@PostMapping("get")
|
||||||
public GroupDto get(@CookieValue(name = USER_UUID_COOKIE_NAME) @NonNull final String privateUuid, @NonNull @RequestBody final String groupUuid) {
|
public GroupDto get(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) {
|
||||||
return groupService.get(privateUuid, groupUuid);
|
return groupService.get(privateUuid, groupUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@GetMapping("findAllJoined")
|
@GetMapping("findAllJoined")
|
||||||
public Set<GroupDto> findAllJoined(@CookieValue(name = USER_UUID_COOKIE_NAME) @NonNull final String userUuid) {
|
public Set<GroupDto> findAllJoined(@NonNull final UserPrivateUuid userUuid) {
|
||||||
return groupService.findAllJoined(userUuid);
|
return groupService.findAllJoined(userUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@PostMapping("findAllCommon")
|
@PostMapping("findAllCommon")
|
||||||
public Set<GroupDto> findAllCommon(@CookieValue(name = USER_UUID_COOKIE_NAME) @NonNull final String userUuid, @NonNull @RequestBody final String targetUuid) {
|
public Set<GroupDto> findAllCommon(@NonNull final UserPrivateUuid userUuid, @NonNull final UserPublicUuid targetUuid) {
|
||||||
return groupService.findAllCommon(userUuid, targetUuid);
|
return groupService.findAllCommon(userUuid, targetUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("join")
|
@PostMapping("join")
|
||||||
public GroupDto join(@CookieValue(name = USER_UUID_COOKIE_NAME, required = false) @Nullable final String privateUuid, @NonNull @RequestBody final GroupJoinRequest request, @NonNull final HttpServletResponse response) {
|
public GroupDto join(@Nullable final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupJoinRequest request, @NonNull final HttpServletResponse response) {
|
||||||
return groupService.join(privateUuid, request, response);
|
return groupService.join(privateUuid, request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("changeTitle")
|
@PostMapping("changeTitle")
|
||||||
public GroupDto changeTitle(@CookieValue(name = USER_UUID_COOKIE_NAME) @NonNull final String privateUuid, @NonNull @RequestBody final GroupChangeTitleRequest request) {
|
public GroupDto changeTitle(@NonNull final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupChangeTitleRequest request) {
|
||||||
return groupService.changeTitle(privateUuid, request);
|
return groupService.changeTitle(privateUuid, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("changePassword")
|
@PostMapping("changePassword")
|
||||||
public GroupDto changePassword(@CookieValue(name = USER_UUID_COOKIE_NAME) @NonNull final String privateUuid, @NonNull @RequestBody final GroupChangePasswordInbound request) {
|
public GroupDto changePassword(@NonNull final UserPrivateUuid privateUuid, @NonNull @RequestBody final GroupChangePasswordRequest request) {
|
||||||
return groupService.changePassword(privateUuid, request);
|
return groupService.changePassword(privateUuid, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("leave")
|
@PostMapping("leave")
|
||||||
public void leave(@CookieValue(name = USER_UUID_COOKIE_NAME) @NonNull final String privateUuid, @NonNull @RequestBody final String groupUuid) {
|
public void leave(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) {
|
||||||
groupService.leave(privateUuid, groupUuid);
|
groupService.leave(privateUuid, groupUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
package de.ph87.tools.group;
|
package de.ph87.tools.group;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
import de.ph87.tools.common.uuid.UuidSerializer;
|
||||||
|
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;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
@ -13,7 +16,8 @@ import java.util.Set;
|
|||||||
public class GroupDto {
|
public class GroupDto {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final String uuid;
|
@JsonSerialize(using = UuidSerializer.class)
|
||||||
|
public final GroupUuid uuid;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final String title;
|
public final String title;
|
||||||
|
|||||||
@ -1,19 +0,0 @@
|
|||||||
package de.ph87.tools.group;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.ToString;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@ToString
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class GroupJoinRequest {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final String uuid;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final String password;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,9 +1,15 @@
|
|||||||
package de.ph87.tools.group;
|
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.User;
|
||||||
import de.ph87.tools.user.UserPublicDto;
|
import de.ph87.tools.user.UserPublicDto;
|
||||||
import de.ph87.tools.user.UserService;
|
import de.ph87.tools.user.UserService;
|
||||||
import de.ph87.tools.user.push.UserPushService;
|
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.annotation.Nullable;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
@ -32,20 +38,20 @@ public class GroupService {
|
|||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public GroupDto create(@Nullable final String privateUuid, @NonNull final HttpServletResponse response) {
|
public GroupDto create(@Nullable final UserPrivateUuid privateUuid, @NonNull final HttpServletResponse response) {
|
||||||
final User user = userService.getUserByPrivateUuidOrElseCreate(privateUuid, response);
|
final User user = userService.getUserByPrivateUuidOrElseCreate(privateUuid, response);
|
||||||
final Group group = createUnchecked(user);
|
final Group group = createUnchecked(user);
|
||||||
return doJoinUnchecked(group, user);
|
return doJoinUnchecked(group, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public GroupDto get(@NonNull final String privateUuid, @NonNull final String groupUuid) {
|
public GroupDto get(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) {
|
||||||
final Access ug = groupAccessService.access(groupUuid, privateUuid);
|
final GroupAccess ug = groupAccessService.access(privateUuid, groupUuid);
|
||||||
return toDto(ug.group);
|
return toDto(ug.group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public GroupDto join(@Nullable final String privateUuid, @NonNull final GroupJoinRequest request, @NonNull final HttpServletResponse response) {
|
public GroupDto join(@Nullable final UserPrivateUuid privateUuid, @NonNull final GroupJoinRequest request, @NonNull final HttpServletResponse response) {
|
||||||
final User user = userService.getUserByPrivateUuidOrElseCreate(privateUuid, response);
|
final User user = userService.getUserByPrivateUuidOrElseCreate(privateUuid, response);
|
||||||
final Group group = getByGroupByGroupUuid(request.uuid);
|
final Group group = getByGroupByGroupUuid(request.uuid);
|
||||||
if (!group.getPassword().equals(request.password)) {
|
if (!group.getPassword().equals(request.password)) {
|
||||||
@ -56,13 +62,13 @@ public class GroupService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private Group getByGroupByGroupUuid(@NonNull final String groupUuid) {
|
private Group getByGroupByGroupUuid(@NonNull final GroupUuid groupUuid) {
|
||||||
return groupRepository.findByUuid(groupUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
return groupRepository.findByUuid(groupUuid.uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public GroupDto changeTitle(@NonNull final String privateUuid, @NonNull final GroupChangeTitleRequest request) {
|
public GroupDto changeTitle(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupChangeTitleRequest request) {
|
||||||
final Access ug = groupAccessService.access(request.uuid, privateUuid);
|
final GroupAccess ug = groupAccessService.access(privateUuid, request.uuid);
|
||||||
if (!ug.group.isOwnedBy(ug.user)) {
|
if (!ug.group.isOwnedBy(ug.user)) {
|
||||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
|
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
|
||||||
}
|
}
|
||||||
@ -71,13 +77,13 @@ public class GroupService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public GroupDto changePassword(@NonNull final String privateUuid, @NonNull final GroupChangePasswordInbound request) {
|
public GroupDto changePassword(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupChangePasswordRequest request) {
|
||||||
final Access access = groupAccessService.accessAsOwner(privateUuid, request.uuid);
|
final GroupAccess access = groupAccessService.accessAsOwner(privateUuid, request.uuid);
|
||||||
access.group.setPassword(request.password);
|
access.group.setPassword(request.password);
|
||||||
return publish(access.group);
|
return publish(access.group);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void leave(@NonNull final String privateUuid, @NonNull final String groupUuid) {
|
public void leave(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid) {
|
||||||
final User user = userService.access(privateUuid);
|
final User user = userService.access(privateUuid);
|
||||||
final Group group = getByGroupByGroupUuid(groupUuid);
|
final Group group = getByGroupByGroupUuid(groupUuid);
|
||||||
doLeaveUnchecked(group, user);
|
doLeaveUnchecked(group, user);
|
||||||
@ -135,13 +141,13 @@ public class GroupService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public Set<GroupDto> findAllJoined(@NonNull final String privateUuid) {
|
public Set<GroupDto> findAllJoined(@NonNull final UserPrivateUuid privateUuid) {
|
||||||
final User principal = userService.access(privateUuid);
|
final User principal = userService.access(privateUuid);
|
||||||
return groupRepository.findAllByUsersContains(principal).stream().map(this::toDto).collect(Collectors.toSet());
|
return groupRepository.findAllByUsersContains(principal).stream().map(this::toDto).collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public Set<GroupDto> findAllCommon(@NonNull final String privateUuid, @NonNull final String targetUuid) {
|
public Set<GroupDto> findAllCommon(@NonNull final UserPrivateUuid privateUuid, @NonNull final UserPublicUuid targetUuid) {
|
||||||
final User principal = userService.access(privateUuid);
|
final User principal = userService.access(privateUuid);
|
||||||
final User target = userService.getByPublicUuid(targetUuid);
|
final User target = userService.getByPublicUuid(targetUuid);
|
||||||
return findAllCommonGroups(principal, target);
|
return findAllCommonGroups(principal, target);
|
||||||
|
|||||||
@ -0,0 +1,23 @@
|
|||||||
|
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 lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class GroupChangePasswordRequest {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@JsonDeserialize(using = GroupUuidDeserializer.class)
|
||||||
|
public final GroupUuid uuid;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final String password;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
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 lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class GroupChangeTitleRequest {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@JsonDeserialize(using = GroupUuidDeserializer.class)
|
||||||
|
public final GroupUuid uuid;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final String title;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
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 lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class GroupJoinRequest {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@JsonDeserialize(using = GroupUuidDeserializer.class)
|
||||||
|
public final GroupUuid uuid;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final String password;
|
||||||
|
|
||||||
|
}
|
||||||
30
src/main/java/de/ph87/tools/group/uuid/GroupAbstract.java
Normal file
30
src/main/java/de/ph87/tools/group/uuid/GroupAbstract.java
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package de.ph87.tools.group.uuid;
|
||||||
|
|
||||||
|
import de.ph87.tools.user.uuid.UserPublicAbstract;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
public abstract class GroupAbstract {
|
||||||
|
|
||||||
|
public abstract GroupUuid getUuid();
|
||||||
|
|
||||||
|
public abstract UserPublicAbstract getOwner();
|
||||||
|
|
||||||
|
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||||
|
public boolean isOwnedBy(@NonNull final UserPublicAbstract user) {
|
||||||
|
return getOwner().equals(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object obj) {
|
||||||
|
if (obj instanceof final GroupAbstract casted) {
|
||||||
|
return casted.getUuid().equals(this.getUuid());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return getUuid().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
16
src/main/java/de/ph87/tools/group/uuid/GroupUuid.java
Normal file
16
src/main/java/de/ph87/tools/group/uuid/GroupUuid.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package de.ph87.tools.group.uuid;
|
||||||
|
|
||||||
|
import de.ph87.tools.common.uuid.AbstractUuid;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class GroupUuid extends AbstractUuid {
|
||||||
|
|
||||||
|
public GroupUuid(@NonNull final String uuid) {
|
||||||
|
super(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
package de.ph87.tools.group.uuid;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.springframework.core.MethodParameter;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||||
|
import org.springframework.web.context.request.NativeWebRequest;
|
||||||
|
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||||
|
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class GroupUuidArgumentResolver implements HandlerMethodArgumentResolver {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsParameter(@NonNull final MethodParameter parameter) {
|
||||||
|
return parameter.getParameterType() == GroupUuid.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SneakyThrows(IOException.class)
|
||||||
|
public GroupUuid resolveArgument(@NonNull final MethodParameter parameter, final ModelAndViewContainer mavContainer, @NonNull final NativeWebRequest webRequest, final WebDataBinderFactory binderFactory) {
|
||||||
|
if (!(webRequest.getNativeRequest() instanceof final HttpServletRequest request)) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
final String uuid = new String(request.getInputStream().readAllBytes());
|
||||||
|
return new GroupUuid(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
package de.ph87.tools.group.uuid;
|
||||||
|
|
||||||
|
import de.ph87.tools.common.uuid.AbstractUuidDeserializer;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class GroupUuidDeserializer extends AbstractUuidDeserializer {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
protected GroupUuid create(@NonNull final String s) {
|
||||||
|
return new GroupUuid(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,13 +1,12 @@
|
|||||||
package de.ph87.tools.tools.numbers;
|
package de.ph87.tools.tools.numbers;
|
||||||
|
|
||||||
import de.ph87.tools.group.Group;
|
import de.ph87.tools.group.Group;
|
||||||
|
import de.ph87.tools.tools.numbers.uuid.NumbersAbstract;
|
||||||
|
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.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import lombok.Getter;
|
import lombok.*;
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.ToString;
|
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -18,13 +17,24 @@ import java.util.UUID;
|
|||||||
@ToString
|
@ToString
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@Table(name = "`numbers`")
|
@Table(name = "`numbers`")
|
||||||
public class Numbers {
|
public class Numbers extends NumbersAbstract {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@NonNull
|
@NonNull
|
||||||
@Column(nullable = false)
|
@Getter(AccessLevel.NONE)
|
||||||
private String uuid = UUID.randomUUID().toString();
|
private String uuid = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private NumbersUuid _uuid;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public NumbersUuid getUuid() {
|
||||||
|
if (_uuid == null) {
|
||||||
|
_uuid = new NumbersUuid(uuid);
|
||||||
|
}
|
||||||
|
return _uuid;
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@ManyToOne(optional = false)
|
@ManyToOne(optional = false)
|
||||||
private Group group;
|
private Group group;
|
||||||
@ -42,31 +52,18 @@ public class Numbers {
|
|||||||
this.users = users;
|
this.users = users;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(final Object obj) {
|
|
||||||
if (!(obj instanceof final Numbers numbers)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return numbers.uuid.equals(this.uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return uuid.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumberForUser(@NonNull final User user) {
|
public int 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;
|
return userReferenceIndex + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean containsUser(@NonNull final User user) {
|
public boolean containsUser(@NonNull final User user) {
|
||||||
return users.stream().anyMatch(u -> user.equalsIUser(u.getUser()));
|
return users.stream().anyMatch(u -> user.equals(u.getUser()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
20
src/main/java/de/ph87/tools/tools/numbers/NumbersAccess.java
Normal file
20
src/main/java/de/ph87/tools/tools/numbers/NumbersAccess.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package de.ph87.tools.tools.numbers;
|
||||||
|
|
||||||
|
import de.ph87.tools.user.User;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
class NumbersAccess {
|
||||||
|
|
||||||
|
public final Numbers numbers;
|
||||||
|
|
||||||
|
public final User user;
|
||||||
|
|
||||||
|
public NumbersAccess(final Numbers numbers, final User user) {
|
||||||
|
this.numbers = numbers;
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,12 +1,14 @@
|
|||||||
package de.ph87.tools.tools.numbers;
|
package de.ph87.tools.tools.numbers;
|
||||||
|
|
||||||
|
import de.ph87.tools.group.uuid.GroupUuid;
|
||||||
|
import de.ph87.tools.tools.numbers.uuid.NumbersUuid;
|
||||||
|
import de.ph87.tools.user.uuid.UserPrivateUuid;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import static de.ph87.tools.UserArgumentResolver.USER_UUID_COOKIE_NAME;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@CrossOrigin
|
@CrossOrigin
|
||||||
@RestController
|
@RestController
|
||||||
@ -17,25 +19,31 @@ public class NumbersController {
|
|||||||
private final NumbersService numbersService;
|
private final NumbersService numbersService;
|
||||||
|
|
||||||
@GetMapping("create/{groupUuid}")
|
@GetMapping("create/{groupUuid}")
|
||||||
public void create(@CookieValue(name = USER_UUID_COOKIE_NAME) @NonNull final String privateUuid, @PathVariable final String groupUuid) {
|
public void create(@NonNull final UserPrivateUuid privateUuid, @PathVariable final GroupUuid groupUuid) {
|
||||||
numbersService.create(privateUuid, groupUuid);
|
numbersService.create(privateUuid, groupUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@GetMapping("page/{groupUuid}/{page}/{pageSize}")
|
||||||
|
public Page<NumbersDto> page(@NonNull final UserPrivateUuid privateUuid, @PathVariable final GroupUuid groupUuid, @PathVariable final int page, @PathVariable final int pageSize) {
|
||||||
|
return numbersService.page(privateUuid, groupUuid, page, pageSize);
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("canAccess")
|
@PostMapping("canAccess")
|
||||||
public boolean canAccess(@CookieValue(name = USER_UUID_COOKIE_NAME) @NonNull final String privateUuid, @RequestBody final String groupUuid) {
|
public boolean canAccess(@NonNull final UserPrivateUuid privateUuid, final NumbersUuid numbersUuid) {
|
||||||
return numbersService.canAccess(privateUuid, groupUuid);
|
return numbersService.canAccess(privateUuid, numbersUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@PostMapping("getGroupUuid")
|
@PostMapping("getGroupUuid")
|
||||||
public String getGroupUuid(@RequestBody final String groupUuid) {
|
public GroupUuid getGroupUuid(final NumbersUuid numbersUuid) {
|
||||||
return numbersService.getGroupUuid(groupUuid);
|
return numbersService.getGroupUuid(numbersUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@PostMapping("byUuid")
|
@PostMapping("byUuid")
|
||||||
public NumbersPrivateDto byUuid(@CookieValue(name = USER_UUID_COOKIE_NAME) @NonNull final String privateUuid, @RequestBody final String groupUuid) {
|
public NumbersDto byUuid(@NonNull final UserPrivateUuid privateUuid, final NumbersUuid numbersUuid) {
|
||||||
return numbersService.dtoByUuid(privateUuid, groupUuid);
|
return numbersService.dtoByUuid(privateUuid, numbersUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
package de.ph87.tools.tools.numbers;
|
package de.ph87.tools.tools.numbers;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
import de.ph87.tools.common.uuid.UuidSerializer;
|
||||||
import de.ph87.tools.group.GroupDto;
|
import de.ph87.tools.group.GroupDto;
|
||||||
|
import de.ph87.tools.tools.numbers.uuid.NumbersAbstract;
|
||||||
|
import de.ph87.tools.tools.numbers.uuid.NumbersUuid;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
@ -9,10 +13,11 @@ import java.time.ZonedDateTime;
|
|||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
public class NumbersPrivateDto {
|
public class NumbersDto extends NumbersAbstract {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final String uuid;
|
@JsonSerialize(using = UuidSerializer.class)
|
||||||
|
private final NumbersUuid uuid;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final GroupDto group;
|
private final GroupDto group;
|
||||||
@ -22,7 +27,7 @@ public class NumbersPrivateDto {
|
|||||||
|
|
||||||
private final int number;
|
private final int number;
|
||||||
|
|
||||||
public NumbersPrivateDto(@NonNull final Numbers numbers, @NonNull final GroupDto group, final int number) {
|
public NumbersDto(@NonNull final Numbers numbers, @NonNull final GroupDto group, final int number) {
|
||||||
this.uuid = numbers.getUuid();
|
this.uuid = numbers.getUuid();
|
||||||
this.date = numbers.getDate();
|
this.date = numbers.getDate();
|
||||||
this.group = group;
|
this.group = group;
|
||||||
@ -1,7 +1,14 @@
|
|||||||
package de.ph87.tools.tools.numbers;
|
package de.ph87.tools.tools.numbers;
|
||||||
|
|
||||||
|
import de.ph87.tools.group.Group;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.repository.ListCrudRepository;
|
import org.springframework.data.repository.ListCrudRepository;
|
||||||
|
|
||||||
public interface NumbersRepository extends ListCrudRepository<Numbers, String> {
|
public interface NumbersRepository extends ListCrudRepository<Numbers, String> {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
Page<Numbers> findAllByGroup(@NonNull Group group, @NonNull Pageable pageable);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,18 +1,23 @@
|
|||||||
package de.ph87.tools.tools.numbers;
|
package de.ph87.tools.tools.numbers;
|
||||||
|
|
||||||
|
import de.ph87.tools.group.GroupAccess;
|
||||||
import de.ph87.tools.group.GroupAccessService;
|
import de.ph87.tools.group.GroupAccessService;
|
||||||
import de.ph87.tools.group.GroupDto;
|
import de.ph87.tools.group.GroupDto;
|
||||||
import de.ph87.tools.group.GroupService;
|
import de.ph87.tools.group.GroupService;
|
||||||
|
import de.ph87.tools.group.uuid.GroupUuid;
|
||||||
|
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.UserService;
|
import de.ph87.tools.user.UserService;
|
||||||
import de.ph87.tools.user.push.UserPushService;
|
import de.ph87.tools.user.push.UserPushService;
|
||||||
import de.ph87.tools.user.reference.UserReference;
|
import de.ph87.tools.user.reference.UserReference;
|
||||||
import de.ph87.tools.user.reference.UserReferenceService;
|
import de.ph87.tools.user.reference.UserReferenceService;
|
||||||
import lombok.Getter;
|
import de.ph87.tools.user.uuid.UserPrivateUuid;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.ToString;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@ -41,8 +46,8 @@ public class NumbersService {
|
|||||||
|
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
|
|
||||||
public void create(@NonNull final String userPrivateUuid, @NonNull final String groupUuid) {
|
public void create(@NonNull final UserPrivateUuid userPrivateUuid, @NonNull final GroupUuid groupUuid) {
|
||||||
final de.ph87.tools.group.Access access = groupAccessService.accessAsOwner(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));
|
||||||
@ -58,59 +63,51 @@ public class NumbersService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void publish(@NonNull final Numbers numbers, @NonNull final User user) {
|
private void publish(@NonNull final Numbers numbers, @NonNull final User user) {
|
||||||
final NumbersPrivateDto dto = toPrivateDto(numbers, user);
|
final NumbersDto dto = toDto(numbers, user);
|
||||||
log.debug("Sending event: {}", dto);
|
log.debug("Sending event: {}", dto);
|
||||||
userPushService.push(user, dto);
|
userPushService.push(user, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public NumbersPrivateDto toPrivateDto(@NonNull final Numbers numbers, @NonNull final User user) {
|
public NumbersDto toDto(@NonNull final Numbers numbers, @NonNull final User user) {
|
||||||
final GroupDto group = groupService.toDto(numbers.getGroup());
|
final GroupDto group = groupService.toDto(numbers.getGroup());
|
||||||
final int number = numbers.getNumberForUser(user);
|
final int number = numbers.getNumberForUser(user);
|
||||||
return new NumbersPrivateDto(numbers, group, number);
|
return new NumbersDto(numbers, group, number);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canAccess(@NonNull final String privateUuid, @NonNull final String numbersUuid) {
|
public boolean canAccess(@NonNull final UserPrivateUuid privateUuid, @NonNull final NumbersUuid numbersUuid) {
|
||||||
final User user = userService.access(privateUuid);
|
final User user = userService.access(privateUuid);
|
||||||
final Numbers numbers = numbersRepository.findById(numbersUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
final Numbers numbers = numbersRepository.findById(numbersUuid.uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
||||||
return numbers.containsUser(user);
|
return numbers.containsUser(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public String getGroupUuid(@NonNull final String numbersUuid) {
|
public GroupUuid getGroupUuid(@NonNull final NumbersUuid numbersUuid) {
|
||||||
final Numbers numbers = numbersRepository.findById(numbersUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
final Numbers numbers = numbersRepository.findById(numbersUuid.uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
||||||
return numbers.getGroup().getUuid();
|
return numbers.getGroup().getUuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public NumbersPrivateDto dtoByUuid(@NonNull final String privateUuid, @NonNull final String numbersUuid) {
|
public NumbersDto dtoByUuid(@NonNull final UserPrivateUuid privateUuid, @NonNull final NumbersUuid numbersUuid) {
|
||||||
final Access access = access(privateUuid, numbersUuid);
|
final NumbersAccess access = access(privateUuid, numbersUuid);
|
||||||
return toPrivateDto(access.numbers, access.user);
|
return toDto(access.numbers, access.user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private Access access(@NonNull final String privateUuid, @NonNull final String numbersUuid) {
|
private NumbersAccess access(@NonNull final UserPrivateUuid privateUuid, @NonNull final NumbersUuid numbersUuid) {
|
||||||
final User user = userService.access(privateUuid);
|
final User user = userService.access(privateUuid);
|
||||||
final Numbers numbers = numbersRepository.findById(numbersUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
final Numbers numbers = numbersRepository.findById(numbersUuid.uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
||||||
if (!numbers.containsUser(user)) {
|
if (!numbers.containsUser(user)) {
|
||||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
|
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
return new Access(numbers, user);
|
return new NumbersAccess(numbers, user);
|
||||||
}
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@ToString
|
|
||||||
private static class Access {
|
|
||||||
|
|
||||||
public final Numbers numbers;
|
|
||||||
|
|
||||||
public final User user;
|
|
||||||
|
|
||||||
public Access(final Numbers numbers, final User user) {
|
|
||||||
this.numbers = numbers;
|
|
||||||
this.user = user;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public Page<NumbersDto> page(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUuid groupUuid, final int page, final int pageSize) {
|
||||||
|
final GroupAccess access = groupAccessService.access(privateUuid, groupUuid);
|
||||||
|
final PageRequest pageable = PageRequest.of(page, pageSize, Sort.by(new Sort.Order(Sort.Direction.DESC, "date")));
|
||||||
|
return numbersRepository.findAllByGroup(access.group, pageable).map(numbers -> toDto(numbers, access.user));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,20 @@
|
|||||||
|
package de.ph87.tools.tools.numbers.uuid;
|
||||||
|
|
||||||
|
public abstract class NumbersAbstract {
|
||||||
|
|
||||||
|
public abstract NumbersUuid getUuid();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object obj) {
|
||||||
|
if (obj instanceof final NumbersAbstract casted) {
|
||||||
|
return casted.getUuid().equals(this.getUuid());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return getUuid().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
package de.ph87.tools.tools.numbers.uuid;
|
||||||
|
|
||||||
|
import de.ph87.tools.common.uuid.AbstractUuid;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class NumbersUuid extends AbstractUuid {
|
||||||
|
|
||||||
|
public NumbersUuid(@NonNull final String uuid) {
|
||||||
|
super(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
package de.ph87.tools.tools.numbers.uuid;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.springframework.core.MethodParameter;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||||
|
import org.springframework.web.context.request.NativeWebRequest;
|
||||||
|
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||||
|
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class NumbersUuidArgumentResolver implements HandlerMethodArgumentResolver {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsParameter(@NonNull final MethodParameter parameter) {
|
||||||
|
return parameter.getParameterType() == NumbersUuid.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SneakyThrows(IOException.class)
|
||||||
|
public NumbersUuid resolveArgument(@NonNull final MethodParameter parameter, final ModelAndViewContainer mavContainer, @NonNull final NativeWebRequest webRequest, final WebDataBinderFactory binderFactory) {
|
||||||
|
if (!(webRequest.getNativeRequest() instanceof final HttpServletRequest request)) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
final String uuid = new String(request.getInputStream().readAllBytes());
|
||||||
|
return new NumbersUuid(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,10 +1,9 @@
|
|||||||
package de.ph87.tools.user;
|
package de.ph87.tools.user;
|
||||||
|
|
||||||
import de.ph87.tools.user.reference.IUser;
|
import de.ph87.tools.user.uuid.UserPrivateUuid;
|
||||||
import jakarta.persistence.Column;
|
import de.ph87.tools.user.uuid.UserPublicAbstract;
|
||||||
import jakarta.persistence.Entity;
|
import de.ph87.tools.user.uuid.UserPublicUuid;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.*;
|
||||||
import jakarta.persistence.Table;
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
|
||||||
@ -16,16 +15,39 @@ import java.util.UUID;
|
|||||||
@ToString
|
@ToString
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@Table(name = "`user`")
|
@Table(name = "`user`")
|
||||||
public class User extends IUser {
|
public class User extends UserPublicAbstract {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@NonNull
|
@NonNull
|
||||||
@Column(nullable = false)
|
@Getter(AccessLevel.NONE)
|
||||||
private String privateUuid = UUID.randomUUID().toString();
|
private String publicUuid = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private UserPublicUuid _publicUuid;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Column(nullable = false)
|
public UserPublicUuid getPublicUuid() {
|
||||||
private String publicUuid = UUID.randomUUID().toString();
|
if (_publicUuid == null) {
|
||||||
|
_publicUuid = new UserPublicUuid(publicUuid);
|
||||||
|
}
|
||||||
|
return _publicUuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Getter(AccessLevel.NONE)
|
||||||
|
@Column(nullable = false, unique = true, updatable = false)
|
||||||
|
private String privateUuid = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private UserPrivateUuid _privateUuid;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public UserPrivateUuid getPrivateUuid() {
|
||||||
|
if (_privateUuid == null) {
|
||||||
|
_privateUuid = new UserPrivateUuid(privateUuid);
|
||||||
|
}
|
||||||
|
return _privateUuid;
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
|
|||||||
@ -1,29 +0,0 @@
|
|||||||
package de.ph87.tools.user;
|
|
||||||
|
|
||||||
import de.ph87.tools.group.GroupDto;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.ToString;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@ToString
|
|
||||||
public class UserCommonDto {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final String publicUuid;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final String name;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final Set<GroupDto> commonGroups;
|
|
||||||
|
|
||||||
public UserCommonDto(@NonNull final User target, @NonNull final Set<GroupDto> commonGroups) {
|
|
||||||
this.publicUuid = target.getPublicUuid();
|
|
||||||
this.name = target.getName();
|
|
||||||
this.commonGroups = commonGroups;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,5 +1,8 @@
|
|||||||
package de.ph87.tools.user;
|
package de.ph87.tools.user;
|
||||||
|
|
||||||
|
import de.ph87.tools.user.requests.UserLoginRequest;
|
||||||
|
import de.ph87.tools.user.uuid.UserPrivateUuid;
|
||||||
|
import de.ph87.tools.user.uuid.UserPublicUuid;
|
||||||
import jakarta.annotation.Nullable;
|
import jakarta.annotation.Nullable;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
@ -7,8 +10,6 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import static de.ph87.tools.UserArgumentResolver.USER_UUID_COOKIE_NAME;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@CrossOrigin
|
@CrossOrigin
|
||||||
@RestController
|
@RestController
|
||||||
@ -20,36 +21,36 @@ public class UserController {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@GetMapping("whoAmI")
|
@GetMapping("whoAmI")
|
||||||
public UserPrivateDto whoAmI(@CookieValue(name = USER_UUID_COOKIE_NAME, required = false) @Nullable final String userUuid, @NonNull final HttpServletResponse response) {
|
public UserPrivateDto whoAmI(@Nullable final UserPrivateUuid userUuid, @NonNull final HttpServletResponse response) {
|
||||||
return userService.whoAmI(userUuid, response);
|
return userService.whoAmI(userUuid, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@PostMapping("getByPublicUuid")
|
@PostMapping("getByPublicUuid")
|
||||||
public UserPublicDto getByPublicUuid(@NonNull @RequestBody final String publicUuid) {
|
public UserPublicDto getByPublicUuid(@NonNull final UserPublicUuid publicUuid) {
|
||||||
return userService.getDtoByPublicUuid(publicUuid);
|
return userService.getDtoByPublicUuid(publicUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@GetMapping("login")
|
@GetMapping("login")
|
||||||
public UserPrivateDto login(@NonNull @RequestBody final LoginRequest loginRequest, @NonNull final HttpServletResponse response) {
|
public UserPrivateDto login(@NonNull @RequestBody final UserLoginRequest loginRequest, @NonNull final HttpServletResponse response) {
|
||||||
return userService.login(loginRequest, response);
|
return userService.login(loginRequest, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@PostMapping("changeName")
|
@PostMapping("changeName")
|
||||||
public UserPrivateDto changeName(@CookieValue(name = USER_UUID_COOKIE_NAME) @NonNull final String userUuid, @NonNull @RequestBody final String name) {
|
public UserPrivateDto changeName(@NonNull final UserPrivateUuid userUuid, @NonNull @RequestBody final String name) {
|
||||||
return userService.changeName(userUuid, name);
|
return userService.changeName(userUuid, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@PostMapping("changePassword")
|
@PostMapping("changePassword")
|
||||||
public UserPrivateDto changePassword(@CookieValue(name = USER_UUID_COOKIE_NAME) @NonNull final String userUuid, @NonNull @RequestBody final String password) {
|
public UserPrivateDto changePassword(@NonNull final UserPrivateUuid userUuid, @NonNull @RequestBody final String password) {
|
||||||
return userService.changePassword(userUuid, password);
|
return userService.changePassword(userUuid, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("delete")
|
@GetMapping("delete")
|
||||||
public void delete(@CookieValue(name = USER_UUID_COOKIE_NAME) @NonNull final String userUuid, @NonNull final HttpServletResponse response) {
|
public void delete(@NonNull final UserPrivateUuid userUuid, @NonNull final HttpServletResponse response) {
|
||||||
userService.delete(userUuid, response);
|
userService.delete(userUuid, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
package de.ph87.tools.user;
|
package de.ph87.tools.user;
|
||||||
|
|
||||||
import de.ph87.tools.user.reference.IUser;
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
import de.ph87.tools.common.uuid.UuidSerializer;
|
||||||
|
import de.ph87.tools.user.uuid.UserPrivateUuid;
|
||||||
|
import de.ph87.tools.user.uuid.UserPublicAbstract;
|
||||||
|
import de.ph87.tools.user.uuid.UserPublicUuid;
|
||||||
import jakarta.annotation.Nullable;
|
import jakarta.annotation.Nullable;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
@ -10,20 +14,22 @@ import java.time.ZonedDateTime;
|
|||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ToString
|
@ToString
|
||||||
public class UserPrivateDto extends IUser {
|
public class UserPrivateDto extends UserPublicAbstract {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final String pushType = "UserPrivate";
|
private final String pushType = "UserPrivate";
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final String publicUuid;
|
@JsonSerialize(using = UuidSerializer.class)
|
||||||
|
public final UserPublicUuid publicUuid;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@JsonSerialize(using = UuidSerializer.class)
|
||||||
|
public final UserPrivateUuid privateUuid;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final String name;
|
public final String name;
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final String privateUuid;
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final ZonedDateTime created;
|
public final ZonedDateTime created;
|
||||||
|
|
||||||
@ -31,8 +37,8 @@ public class UserPrivateDto extends IUser {
|
|||||||
|
|
||||||
public UserPrivateDto(@NonNull final User user) {
|
public UserPrivateDto(@NonNull final User user) {
|
||||||
this.publicUuid = user.getPublicUuid();
|
this.publicUuid = user.getPublicUuid();
|
||||||
this.name = user.getName();
|
|
||||||
this.privateUuid = user.getPrivateUuid();
|
this.privateUuid = user.getPrivateUuid();
|
||||||
|
this.name = user.getName();
|
||||||
this.created = user.getCreated();
|
this.created = user.getCreated();
|
||||||
this.password = !user.getPassword().isEmpty();
|
this.password = !user.getPassword().isEmpty();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,20 @@
|
|||||||
package de.ph87.tools.user;
|
package de.ph87.tools.user;
|
||||||
|
|
||||||
import de.ph87.tools.user.reference.IUser;
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
import de.ph87.tools.common.uuid.UuidSerializer;
|
||||||
|
import de.ph87.tools.user.uuid.UserPublicAbstract;
|
||||||
|
import de.ph87.tools.user.uuid.UserPublicUuid;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ToString
|
@ToString
|
||||||
public class UserPublicDto extends IUser {
|
public class UserPublicDto extends UserPublicAbstract {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final String publicUuid;
|
@JsonSerialize(using = UuidSerializer.class)
|
||||||
|
public final UserPublicUuid publicUuid;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final String name;
|
public final String name;
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
package de.ph87.tools.user;
|
package de.ph87.tools.user;
|
||||||
|
|
||||||
|
import de.ph87.tools.common.uuid.AbstractUuid;
|
||||||
|
import de.ph87.tools.user.requests.UserLoginRequest;
|
||||||
|
import de.ph87.tools.user.uuid.UserPrivateUuid;
|
||||||
|
import de.ph87.tools.user.uuid.UserPublicUuid;
|
||||||
import jakarta.annotation.Nullable;
|
import jakarta.annotation.Nullable;
|
||||||
import jakarta.servlet.http.Cookie;
|
import jakarta.servlet.http.Cookie;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
@ -18,7 +22,7 @@ import java.util.Random;
|
|||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import static de.ph87.tools.UserArgumentResolver.USER_UUID_COOKIE_NAME;
|
import static de.ph87.tools.user.uuid.UserPrivateUuidArgumentResolver.USER_UUID_COOKIE_NAME;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@ -42,7 +46,7 @@ public class UserService {
|
|||||||
private final PasswordEncoder passwordEncoder;
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public UserPrivateDto login(@NonNull final LoginRequest loginRequest, @NonNull final HttpServletResponse response) {
|
public UserPrivateDto login(@NonNull final UserLoginRequest loginRequest, @NonNull final HttpServletResponse response) {
|
||||||
final User user = userRepository.findByName(loginRequest.name).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
final User user = userRepository.findByName(loginRequest.name).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
||||||
if (passwordEncoder.matches(loginRequest.password, user.getPassword())) {
|
if (passwordEncoder.matches(loginRequest.password, user.getPassword())) {
|
||||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
|
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
|
||||||
@ -53,24 +57,30 @@ public class UserService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public User getUserByPrivateUuidOrElseCreate(@Nullable final String privateUuid, @NonNull final HttpServletResponse response) {
|
public User getUserByPrivateUuidOrElseCreate(@Nullable final UserPrivateUuid privateUuid, @NonNull final HttpServletResponse response) {
|
||||||
final User user = Optional.ofNullable(privateUuid).map(userRepository::findByPrivateUuid).filter(Optional::isPresent).map(Optional::get).orElseGet(this::createUnchecked);
|
final User user = Optional
|
||||||
|
.ofNullable(privateUuid)
|
||||||
|
.map(AbstractUuid::getUuid)
|
||||||
|
.map(userRepository::findByPrivateUuid)
|
||||||
|
.filter(Optional::isPresent)
|
||||||
|
.map(Optional::get)
|
||||||
|
.orElseGet(this::createUnchecked);
|
||||||
writeUserUuidCookie(response, user);
|
writeUserUuidCookie(response, user);
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public UserPrivateDto whoAmI(@Nullable final String privateUuid, final @NonNull HttpServletResponse response) {
|
public UserPrivateDto whoAmI(@Nullable final UserPrivateUuid privateUuid, @NonNull final HttpServletResponse response) {
|
||||||
if (privateUuid == null || privateUuid.isEmpty()) {
|
if (privateUuid == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final User user = userRepository.findByPrivateUuid(privateUuid).orElse(null);
|
final User user = userRepository.findByPrivateUuid(privateUuid.uuid).orElse(null);
|
||||||
writeUserUuidCookie(response, user);
|
writeUserUuidCookie(response, user);
|
||||||
return UserPrivateDto.orNull(user);
|
return UserPrivateDto.orNull(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public UserPrivateDto changeName(@NonNull final String privateUuid, @NonNull final String name) {
|
public UserPrivateDto changeName(@NonNull final UserPrivateUuid privateUuid, @NonNull final String name) {
|
||||||
return modify(privateUuid, user -> {
|
return modify(privateUuid, user -> {
|
||||||
if (user.getName().equals(name)) {
|
if (user.getName().equals(name)) {
|
||||||
return;
|
return;
|
||||||
@ -94,7 +104,7 @@ public class UserService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public UserPrivateDto changePassword(@NonNull final String privateUuid, @NonNull final String password) {
|
public UserPrivateDto changePassword(@NonNull final UserPrivateUuid privateUuid, @NonNull final String password) {
|
||||||
return modify(privateUuid, user -> {
|
return modify(privateUuid, user -> {
|
||||||
if (password.length() < PASSWORD_MIN_LENGTH) {
|
if (password.length() < PASSWORD_MIN_LENGTH) {
|
||||||
log.warn("Cannot change User password: too short: length={}/{}, user={}", password.length(), PASSWORD_MIN_LENGTH, user);
|
log.warn("Cannot change User password: too short: length={}/{}, user={}", password.length(), PASSWORD_MIN_LENGTH, user);
|
||||||
@ -109,8 +119,8 @@ public class UserService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete(@NonNull final String privateUuid, final @NonNull HttpServletResponse response) {
|
public void delete(@NonNull final UserPrivateUuid privateUuid, @NonNull final HttpServletResponse response) {
|
||||||
final User user = userRepository.findByPrivateUuid(privateUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
final User user = userRepository.findByPrivateUuid(privateUuid.uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
||||||
deleteUnchecked(response, user);
|
deleteUnchecked(response, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +146,7 @@ public class UserService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private UserPrivateDto modify(@NonNull final String privateUuid, @NonNull Consumer<User> modifier) {
|
private UserPrivateDto modify(@NonNull final UserPrivateUuid privateUuid, @NonNull Consumer<User> modifier) {
|
||||||
final User user = access(privateUuid);
|
final User user = access(privateUuid);
|
||||||
modifier.accept(user);
|
modifier.accept(user);
|
||||||
return new UserPrivateDto(user);
|
return new UserPrivateDto(user);
|
||||||
@ -151,8 +161,8 @@ public class UserService {
|
|||||||
/* ACCESS --------------------------------------------------------------------------------------- */
|
/* ACCESS --------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public User accessOrNull(@Nullable final String userPrivateUuid) {
|
public User accessOrNull(@Nullable final UserPrivateUuid userPrivateUuid) {
|
||||||
if (userPrivateUuid == null || userPrivateUuid.isEmpty()) {
|
if (userPrivateUuid == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return access(userPrivateUuid);
|
return access(userPrivateUuid);
|
||||||
@ -161,18 +171,18 @@ public class UserService {
|
|||||||
/* GETTERS & FINDERS ---------------------------------------------------------------------------- */
|
/* GETTERS & FINDERS ---------------------------------------------------------------------------- */
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public UserPublicDto getDtoByPublicUuid(@NonNull final String publicUuid) {
|
public UserPublicDto getDtoByPublicUuid(@NonNull final UserPublicUuid publicUuid) {
|
||||||
return new UserPublicDto(getByPublicUuid(publicUuid));
|
return new UserPublicDto(getByPublicUuid(publicUuid));
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public User access(@NonNull final String privateUuid) {
|
public User access(@NonNull final UserPrivateUuid privateUuid) {
|
||||||
return userRepository.findByPrivateUuid(privateUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
return userRepository.findByPrivateUuid(privateUuid.uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public User getByPublicUuid(@NonNull final String publicUuid) {
|
public User getByPublicUuid(@NonNull final UserPublicUuid publicUuid) {
|
||||||
return userRepository.findByPublicUuid(publicUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
return userRepository.findByPublicUuid(publicUuid.uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* COOKIES -------------------------------------------------------------------------------------- */
|
/* COOKIES -------------------------------------------------------------------------------------- */
|
||||||
@ -180,7 +190,7 @@ public class UserService {
|
|||||||
private static void writeUserUuidCookie(@NonNull final HttpServletResponse response, @Nullable final User user) {
|
private static void writeUserUuidCookie(@NonNull final HttpServletResponse response, @Nullable final User user) {
|
||||||
final Cookie cookie = new Cookie(USER_UUID_COOKIE_NAME, "");
|
final Cookie cookie = new Cookie(USER_UUID_COOKIE_NAME, "");
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
cookie.setValue(user.getPrivateUuid());
|
cookie.setValue(user.getPrivateUuid().uuid);
|
||||||
}
|
}
|
||||||
cookie.setMaxAge(PASSWORD_MIN_LENGTH * 365 * 24 * 60 * 60);
|
cookie.setMaxAge(PASSWORD_MIN_LENGTH * 365 * 24 * 60 * 60);
|
||||||
cookie.setPath("/");
|
cookie.setPath("/");
|
||||||
|
|||||||
@ -1,31 +0,0 @@
|
|||||||
package de.ph87.tools.user.reference;
|
|
||||||
|
|
||||||
import jakarta.annotation.Nullable;
|
|
||||||
import lombok.NonNull;
|
|
||||||
|
|
||||||
public abstract class IUser {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public abstract String getPublicUuid();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(final Object obj) {
|
|
||||||
if (!(obj instanceof final IUser user)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return equalsIUser(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean equalsIUser(@Nullable final IUser user) {
|
|
||||||
if (user == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return user.getPublicUuid().equals(this.getPublicUuid());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return getPublicUuid().hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package de.ph87.tools.user;
|
package de.ph87.tools.user.requests;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -7,7 +7,7 @@ import lombok.ToString;
|
|||||||
@Getter
|
@Getter
|
||||||
@ToString
|
@ToString
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class LoginRequest {
|
public class UserLoginRequest {
|
||||||
|
|
||||||
public final String name;
|
public final String name;
|
||||||
|
|
||||||
16
src/main/java/de/ph87/tools/user/uuid/UserPrivateUuid.java
Normal file
16
src/main/java/de/ph87/tools/user/uuid/UserPrivateUuid.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package de.ph87.tools.user.uuid;
|
||||||
|
|
||||||
|
import de.ph87.tools.common.uuid.AbstractUuid;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class UserPrivateUuid extends AbstractUuid {
|
||||||
|
|
||||||
|
public UserPrivateUuid(@NonNull final String uuid) {
|
||||||
|
super(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
package de.ph87.tools.user.uuid;
|
||||||
|
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import jakarta.servlet.http.Cookie;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import org.springframework.core.MethodParameter;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||||
|
import org.springframework.web.context.request.NativeWebRequest;
|
||||||
|
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||||
|
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class UserPrivateUuidArgumentResolver implements HandlerMethodArgumentResolver {
|
||||||
|
|
||||||
|
public static final String USER_UUID_COOKIE_NAME = "PatrixToolsUserUuid";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsParameter(@NonNull final MethodParameter parameter) {
|
||||||
|
return parameter.getParameterType() == UserPrivateUuid.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserPrivateUuid resolveArgument(@NonNull final MethodParameter parameter, final ModelAndViewContainer mavContainer, @NonNull final NativeWebRequest webRequest, final WebDataBinderFactory binderFactory) {
|
||||||
|
final boolean nullable = Arrays.stream(parameter.getParameterAnnotations()).anyMatch(annotation -> annotation.annotationType().equals(Nullable.class));
|
||||||
|
if (!(webRequest.getNativeRequest() instanceof final HttpServletRequest request)) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
final String uuid = Arrays.stream(request.getCookies()).filter(cookie -> USER_UUID_COOKIE_NAME.equalsIgnoreCase(cookie.getName())).findFirst().map(Cookie::getValue).orElse(null);
|
||||||
|
if (uuid == null || uuid.length() != 36) {
|
||||||
|
if (!nullable) {
|
||||||
|
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new UserPrivateUuid(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package de.ph87.tools.user.uuid;
|
||||||
|
|
||||||
|
public abstract class UserPublicAbstract {
|
||||||
|
|
||||||
|
public abstract UserPublicUuid getPublicUuid();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object obj) {
|
||||||
|
if (obj instanceof final UserPublicAbstract casted) {
|
||||||
|
return casted.getPublicUuid().equals(this.getPublicUuid());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return getPublicUuid().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
16
src/main/java/de/ph87/tools/user/uuid/UserPublicUuid.java
Normal file
16
src/main/java/de/ph87/tools/user/uuid/UserPublicUuid.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package de.ph87.tools.user.uuid;
|
||||||
|
|
||||||
|
import de.ph87.tools.common.uuid.AbstractUuid;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class UserPublicUuid extends AbstractUuid {
|
||||||
|
|
||||||
|
public UserPublicUuid(@NonNull final String uuid) {
|
||||||
|
super(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
package de.ph87.tools.user.uuid;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.springframework.core.MethodParameter;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||||
|
import org.springframework.web.context.request.NativeWebRequest;
|
||||||
|
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||||
|
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class UserPublicUuidArgumentResolver implements HandlerMethodArgumentResolver {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsParameter(@NonNull final MethodParameter parameter) {
|
||||||
|
return parameter.getParameterType() == UserPublicUuid.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SneakyThrows(IOException.class)
|
||||||
|
public UserPublicUuid resolveArgument(@NonNull final MethodParameter parameter, final ModelAndViewContainer mavContainer, @NonNull final NativeWebRequest webRequest, final WebDataBinderFactory binderFactory) {
|
||||||
|
if (!(webRequest.getNativeRequest() instanceof final HttpServletRequest request)) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
final String uuid = new String(request.getInputStream().readAllBytes());
|
||||||
|
return new UserPublicUuid(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,6 +1,9 @@
|
|||||||
package de.ph87.tools.web;
|
package de.ph87.tools.web;
|
||||||
|
|
||||||
import de.ph87.tools.UserArgumentResolver;
|
import de.ph87.tools.group.uuid.GroupUuidArgumentResolver;
|
||||||
|
import de.ph87.tools.tools.numbers.uuid.NumbersUuidArgumentResolver;
|
||||||
|
import de.ph87.tools.user.uuid.UserPrivateUuidArgumentResolver;
|
||||||
|
import de.ph87.tools.user.uuid.UserPublicUuidArgumentResolver;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@ -21,7 +24,10 @@ public class WebConfig implements WebMvcConfigurer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
|
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
|
||||||
argumentResolvers.add(new UserArgumentResolver());
|
argumentResolvers.add(new UserPrivateUuidArgumentResolver());
|
||||||
|
argumentResolvers.add(new UserPublicUuidArgumentResolver());
|
||||||
|
argumentResolvers.add(new GroupUuidArgumentResolver());
|
||||||
|
argumentResolvers.add(new NumbersUuidArgumentResolver());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user