Admin.deleteUser

This commit is contained in:
Patrick Haßel 2024-11-07 16:47:11 +01:00
parent f7af71d52b
commit f47d30a4c8
25 changed files with 341 additions and 16 deletions

View File

@ -7,6 +7,7 @@ export class UserPrivate extends UserPublic {
readonly privateUuid: string, readonly privateUuid: string,
publicUuid: string, publicUuid: string,
readonly created: Date, readonly created: Date,
readonly lastAccess: Date,
name: string, name: string,
readonly password: boolean, readonly password: boolean,
readonly email: string, readonly email: string,
@ -21,6 +22,7 @@ export class UserPrivate extends UserPublic {
validateString(json['privateUuid']), validateString(json['privateUuid']),
validateString(json['publicUuid']), validateString(json['publicUuid']),
validateDate(json['created']), validateDate(json['created']),
validateDate(json['lastAccess']),
validateString(json['name']), validateString(json['name']),
validateBoolean(json['password']), validateBoolean(json['password']),
validateString(json['email']), validateString(json['email']),

View File

@ -13,6 +13,7 @@ import {GroupLeftEvent} from "../group/events/GroupLeftEvent";
import {UserLogoutEvent} from "./events/UserLogoutEvent"; import {UserLogoutEvent} from "./events/UserLogoutEvent";
import {validateBoolean} from "../common/validators"; import {validateBoolean} from "../common/validators";
import {UserLoginRequest} from "./requests/UserLoginRequest"; import {UserLoginRequest} from "./requests/UserLoginRequest";
import {Page} from "../common/Page";
function userPushMessageFromJson(json: any): object { function userPushMessageFromJson(json: any): object {
const type = json['_type_']; const type = json['_type_'];
@ -143,4 +144,14 @@ export class UserService {
this.router.navigate(['Profile']); this.router.navigate(['Profile']);
} }
adminPage(pageIndex: number, pageSize: number, next: Next<Page<UserPrivate>>) {
this.api.postPage(['User', 'Admin', 'page'], {pageIndex: pageIndex, pageSize: pageSize, orders: [{property: 'lastAccess', direction: 'ASC'}]}, UserPrivate.fromJson, next);
}
adminDelete(user: UserPrivate, next?: Next<void>) {
if (confirm("Benutzer \"" + user.name + "\" wirklich löschen?")) {
this.api.postNone(['User', 'Admin', 'delete'], user.privateUuid, next);
}
}
} }

View File

@ -9,6 +9,7 @@ import {GroupComponent} from "./pages/group/group/group.component";
import {NumbersComponent} from "./pages/tools/numbers/numbers.component"; import {NumbersComponent} from "./pages/tools/numbers/numbers.component";
import {EmailConfirmationComponent} from "./pages/email-confirmation/email-confirmation.component"; import {EmailConfirmationComponent} from "./pages/email-confirmation/email-confirmation.component";
import {LoginComponent} from "./pages/login/login.component"; import {LoginComponent} from "./pages/login/login.component";
import {AdminComponent} from "./pages/admin/admin.component";
export const routes: Routes = [ export const routes: Routes = [
{path: 'SolarSystemPrintout', component: SolarSystemPrintoutComponent}, {path: 'SolarSystemPrintout', component: SolarSystemPrintoutComponent},
@ -27,6 +28,8 @@ export const routes: Routes = [
{path: 'Profile', component: ProfileComponent}, {path: 'Profile', component: ProfileComponent},
{path: 'emailConfirmation/:emailConfirmation', component: EmailConfirmationComponent}, {path: 'emailConfirmation/:emailConfirmation', component: EmailConfirmationComponent},
{path: 'Admin', component: AdminComponent},
// fallback // fallback
{path: '**', redirectTo: '/SolarSystem'}, {path: '**', redirectTo: '/SolarSystem'},
]; ];

View File

@ -0,0 +1,27 @@
<div class="tileContainer">
<div class="tile">
<div class="tileInner">
<div class="tileTitle">
Benutzer
</div>
<div class="tileContent">
<app-pagination [page]="page" (goto)="goto($event)"></app-pagination>
<table>
<tr>
<th>Benutzername</th>
<th>Zuletzt</th>
<th>Aktion</th>
</tr>
<tr *ngFor="let user of page.content">
<td>{{ user.name }}</td>
<td>{{ user.lastAccess | relative:now }}</td>
<td class="buttons">
<div class="button buttonDelete" (click)="userService.adminDelete(user)">Löschen</div>
</td>
</tr>
</table>
<app-pagination [page]="page" (goto)="goto($event)"></app-pagination>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,42 @@
import {Component, OnInit} from '@angular/core';
import {NgForOf} from "@angular/common";
import {Page} from "../../api/common/Page";
import {PaginationComponent} from "../../shared/pagination/pagination.component";
import {UserService} from "../../api/User/user.service";
import {UserPrivate} from "../../api/User/UserPrivate";
import {RelativePipe} from "../../shared/relative.pipe";
@Component({
selector: 'app-admin',
standalone: true,
imports: [
NgForOf,
PaginationComponent,
RelativePipe
],
templateUrl: './admin.component.html',
styleUrl: './admin.component.less'
})
export class AdminComponent implements OnInit {
private readonly PER_PAGE: number = 20;
protected page: Page<UserPrivate> = Page.EMPTY;
protected now: Date = new Date();
constructor(
protected readonly userService: UserService,
) {
// -
}
ngOnInit(): void {
this.goto(0);
}
goto(pageIndex: number) {
this.userService.adminPage(pageIndex, this.PER_PAGE, page => this.page = page);
}
}

View File

@ -0,0 +1,5 @@
<div class="pagination">
<div class="number" *ngFor="let number of numbers" (click)="goto.emit(number)" [class.currentPage]="number === page.number">
{{ number + 1 }}
</div>
</div>

View File

@ -0,0 +1,16 @@
@import "../../../styles/config";
.pagination {
.number {
float: left;
padding: @halfSpace;
margin: @halfSpace;
text-align: center;
}
.currentPage {
color: dodgerblue;
}
}

View File

@ -0,0 +1,34 @@
import {Component, EventEmitter, Input, Output} from '@angular/core';
import {Page} from '../../api/common/Page';
import {NgForOf, NgIf} from "@angular/common";
@Component({
selector: 'app-pagination',
standalone: true,
imports: [
NgForOf,
NgIf
],
templateUrl: './pagination.component.html',
styleUrl: './pagination.component.less'
})
export class PaginationComponent {
_page: Page<any> = Page.EMPTY;
protected numbers: number[] = [];
@Output()
readonly goto: EventEmitter<number> = new EventEmitter<number>();
@Input()
set page(page: Page<any>) {
this._page = page;
this.numbers = [...Array(this.page.totalPages).keys()];
}
get page(): Page<any> {
return this._page;
}
}

View File

@ -1,5 +1,6 @@
package de.ph87.tools.email; package de.ph87.tools.email;
import de.ph87.tools.user.User;
import lombok.NonNull; import lombok.NonNull;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
@ -8,6 +9,7 @@ import org.springframework.data.repository.ListCrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.PagingAndSortingRepository;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.util.List;
public interface EmailRepository extends ListCrudRepository<Email, String>, PagingAndSortingRepository<Email, String> { public interface EmailRepository extends ListCrudRepository<Email, String>, PagingAndSortingRepository<Email, String> {
@ -15,4 +17,7 @@ public interface EmailRepository extends ListCrudRepository<Email, String>, Pagi
@Query("select e from Email e where e.sent is null and (e.tried is null or e.tried <= :earliest) and e.tries < 5") @Query("select e from Email e where e.sent is null and (e.tried is null or e.tried <= :earliest) and e.tries < 5")
Page<Email> findNextToSend(@NonNull final ZonedDateTime earliest, @NonNull Pageable pageable); Page<Email> findNextToSend(@NonNull final ZonedDateTime earliest, @NonNull Pageable pageable);
@NonNull
List<Email> findAllByUser(@NonNull User user);
} }

View File

@ -80,4 +80,11 @@ public class EmailService {
.replaceAll("%EMAIL_CONFIRMATION%", user.getEmailConfirmation()); .replaceAll("%EMAIL_CONFIRMATION%", user.getEmailConfirmation());
} }
public void deleteAllByUser(@NonNull final User user) {
emailRepository.findAllByUser(user).forEach(email -> {
emailRepository.delete(email);
log.info("Email deleted: {}", email);
});
}
} }

View File

@ -27,6 +27,7 @@ public class Group extends GroupAbstract implements IWebSocketMessage {
@Transient @Transient
@ToString.Exclude @ToString.Exclude
@Getter(AccessLevel.NONE)
private GroupUuid _uuid; private GroupUuid _uuid;
@NonNull @NonNull

View File

@ -1,6 +1,7 @@
package de.ph87.tools.group; package de.ph87.tools.group;
import de.ph87.tools.group.dto.GroupDto; import de.ph87.tools.group.dto.GroupDto;
import de.ph87.tools.user.User;
import de.ph87.tools.user.UserPublicDto; import de.ph87.tools.user.UserPublicDto;
import de.ph87.tools.user.push.UserPushService; import de.ph87.tools.user.push.UserPushService;
import lombok.NonNull; import lombok.NonNull;
@ -20,6 +21,8 @@ public class GroupMapper {
private final UserPushService userPushService; private final UserPushService userPushService;
private final GroupRepository groupRepository;
@NonNull @NonNull
public GroupDto toDto(@NonNull final Group group) { public GroupDto toDto(@NonNull final Group group) {
final UserPublicDto owner = new UserPublicDto(group.getOwner()); final UserPublicDto owner = new UserPublicDto(group.getOwner());
@ -35,4 +38,8 @@ public class GroupMapper {
return dto; return dto;
} }
public void pushAllByUser(@NonNull final User user) {
groupRepository.findAllByUsersContains(user).forEach(this::push);
}
} }

View File

@ -4,6 +4,7 @@ import de.ph87.tools.user.User;
import lombok.NonNull; import lombok.NonNull;
import org.springframework.data.repository.ListCrudRepository; import org.springframework.data.repository.ListCrudRepository;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
@ -12,6 +13,9 @@ public interface GroupRepository extends ListCrudRepository<Group, String> {
@NonNull @NonNull
Optional<Group> findByUuid(@NonNull String uuid); Optional<Group> findByUuid(@NonNull String uuid);
@NonNull
List<Group> findAllByOwner(@NonNull User user);
@NonNull @NonNull
Set<Group> findAllByUsersContains(@NonNull User user); Set<Group> findAllByUsersContains(@NonNull User user);

View File

@ -22,8 +22,6 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException; import org.springframework.web.server.ResponseStatusException;
import java.util.function.BiConsumer;
@Slf4j @Slf4j
@Service @Service
@Transactional @Transactional
@ -62,7 +60,7 @@ public class GroupMemberService {
// owner cannot remove itself from group // owner cannot remove itself from group
throw new ResponseStatusException(HttpStatus.BAD_REQUEST); throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
} }
_remove_user_from_group_unchecked(group, user, (g, u) -> log.info("User left Group: user={}, group={}", u, g)); _remove_user_from_group_unchecked(group, user);
} }
@NonNull @NonNull
@ -74,11 +72,11 @@ public class GroupMemberService {
return groupMapper.push(group); return groupMapper.push(group);
} }
public void _remove_user_from_group_unchecked(@NonNull final Group group, @NonNull final User user, @NonNull final BiConsumer<Group, User> beforePush) { public void _remove_user_from_group_unchecked(@NonNull final Group group, @NonNull final User user) {
group.getUsers().remove(user); group.getUsers().remove(user);
group.touch(); group.touch();
user.touch(); user.touch();
beforePush.accept(group, user); log.info("User left Group: user={}, group={}", user, group);
userPushService.push(user, new GroupLeftEvent(group)); userPushService.push(user, new GroupLeftEvent(group));
groupMapper.push(group); groupMapper.push(group);
} }

View File

@ -29,8 +29,6 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException; import org.springframework.web.server.ResponseStatusException;
import java.util.function.BiConsumer;
@Slf4j @Slf4j
@Service @Service
@Transactional @Transactional
@ -69,12 +67,12 @@ public class GroupOwnerService {
} }
public void kick(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUserRequest request) { public void kick(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUserRequest request) {
final OwnerRemoveResult result = _removeUser(privateUuid, request, (group, user) -> log.info("User kicked out of group: user={}, group={}", user, group)); final OwnerRemoveResult result = _removeUser(privateUuid, request);
groupMapper.push(result.group); groupMapper.push(result.group);
} }
public void ban(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUserRequest request) { public void ban(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUserRequest request) {
final OwnerRemoveResult result = _removeUser(privateUuid, request, (group, user) -> log.info("User banned from group: user={}, group={}", user, group)); final OwnerRemoveResult result = _removeUser(privateUuid, request);
result.group.getBanned().add(result.kicked); result.group.getBanned().add(result.kicked);
groupMapper.push(result.group); groupMapper.push(result.group);
} }
@ -114,14 +112,14 @@ public class GroupOwnerService {
} }
@NonNull @NonNull
private OwnerRemoveResult _removeUser(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUserRequest request, @NonNull final BiConsumer<Group, User> beforePush) { private OwnerRemoveResult _removeUser(@NonNull final UserPrivateUuid privateUuid, @NonNull final GroupUserRequest request) {
final GroupAccess access = groupAccessService.ownerAccess(privateUuid, request.groupUuid); final GroupAccess access = groupAccessService.ownerAccess(privateUuid, request.groupUuid);
final User user = access.group.getUsers().stream().filter(u -> u.getPublicUuid().equals(request.userPublicUuid)).findFirst().orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST)); final User user = access.group.getUsers().stream().filter(u -> u.getPublicUuid().equals(request.userPublicUuid)).findFirst().orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
if (user.equals(access.principal)) { if (user.equals(access.principal)) {
// owner cannot kick itself from group // owner cannot kick itself from group
throw new ResponseStatusException(HttpStatus.BAD_REQUEST); throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
} }
groupMemberService._remove_user_from_group_unchecked(access.group, user, beforePush); groupMemberService._remove_user_from_group_unchecked(access.group, user);
return new OwnerRemoveResult(access, user); return new OwnerRemoveResult(access, user);
} }

View File

@ -25,6 +25,7 @@ public class Numbers extends NumbersAbstract {
@Transient @Transient
@ToString.Exclude @ToString.Exclude
@Getter(AccessLevel.NONE)
private NumbersUuid _uuid; private NumbersUuid _uuid;
@NonNull @NonNull

View File

@ -1,11 +1,14 @@
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.user.User;
import lombok.NonNull; import lombok.NonNull;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.ListCrudRepository; import org.springframework.data.repository.ListCrudRepository;
import java.util.List;
public interface NumbersRepository extends ListCrudRepository<Numbers, String> { public interface NumbersRepository extends ListCrudRepository<Numbers, String> {
@NonNull @NonNull
@ -13,4 +16,7 @@ public interface NumbersRepository extends ListCrudRepository<Numbers, String> {
void deleteAllByGroup(@NonNull Group group); void deleteAllByGroup(@NonNull Group group);
@NonNull
List<Numbers> findAllByLotsUser(@NonNull User user);
} }

View File

@ -24,6 +24,7 @@ public class User extends UserPublicAbstract {
@Transient @Transient
@ToString.Exclude @ToString.Exclude
@Getter(AccessLevel.NONE)
private UserPublicUuid _publicUuid; private UserPublicUuid _publicUuid;
@NonNull @NonNull
@ -41,6 +42,7 @@ public class User extends UserPublicAbstract {
@Transient @Transient
@ToString.Exclude @ToString.Exclude
@Getter(AccessLevel.NONE)
private UserPrivateUuid _privateUuid; private UserPrivateUuid _privateUuid;
@NonNull @NonNull

View File

@ -35,6 +35,9 @@ public class UserPrivateDto extends UserPublicAbstract {
@NonNull @NonNull
public final ZonedDateTime created; public final ZonedDateTime created;
@NonNull
public final ZonedDateTime lastAccess;
private final boolean password; private final boolean password;
private final String email; private final String email;
@ -48,6 +51,7 @@ public class UserPrivateDto extends UserPublicAbstract {
this.privateUuid = user.getPrivateUuid(); this.privateUuid = user.getPrivateUuid();
this.name = user.getName(); this.name = user.getName();
this.created = user.getCreated(); this.created = user.getCreated();
this.lastAccess = user.getLastAccess();
this.password = !user.getPassword().isEmpty(); this.password = !user.getPassword().isEmpty();
this.email = obfuscateEmail(user.getEmail()); this.email = obfuscateEmail(user.getEmail());
this.emailConfirmed = user.isEmailConfirmed(); this.emailConfirmed = user.isEmailConfirmed();

View File

@ -2,10 +2,11 @@ package de.ph87.tools.user;
import lombok.NonNull; import lombok.NonNull;
import org.springframework.data.repository.ListCrudRepository; import org.springframework.data.repository.ListCrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import java.util.Optional; import java.util.Optional;
public interface UserRepository extends ListCrudRepository<User, String> { public interface UserRepository extends ListCrudRepository<User, String>, PagingAndSortingRepository<User, String> {
boolean existsByName(@NonNull String name); boolean existsByName(@NonNull String name);

View File

@ -3,7 +3,6 @@ package de.ph87.tools.user;
import de.ph87.tools.common.uuid.AbstractUuid; import de.ph87.tools.common.uuid.AbstractUuid;
import de.ph87.tools.email.EmailService; import de.ph87.tools.email.EmailService;
import de.ph87.tools.group.GroupMapper; import de.ph87.tools.group.GroupMapper;
import de.ph87.tools.group.GroupRepository;
import de.ph87.tools.user.push.UserPushService; import de.ph87.tools.user.push.UserPushService;
import de.ph87.tools.user.requests.UserLoginRequest; import de.ph87.tools.user.requests.UserLoginRequest;
import de.ph87.tools.user.uuid.UserPrivateUuid; import de.ph87.tools.user.uuid.UserPrivateUuid;
@ -50,8 +49,6 @@ public class UserService {
private final PasswordEncoder passwordEncoder; private final PasswordEncoder passwordEncoder;
private final GroupRepository groupRepository;
private final UserAccessService userAccessService; private final UserAccessService userAccessService;
private final GroupMapper groupMapper; private final GroupMapper groupMapper;
@ -133,7 +130,7 @@ public class UserService {
} }
user.setName(name); user.setName(name);
log.info("User name changed: user={}", user); log.info("User name changed: user={}", user);
groupRepository.findAllByUsersContains(user).forEach(groupMapper::push); groupMapper.pushAllByUser(user);
}); });
} }

View File

@ -0,0 +1,31 @@
package de.ph87.tools.user.admin;
import de.ph87.tools.user.UserPrivateDto;
import de.ph87.tools.user.uuid.UserPrivateUuid;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.*;
@Slf4j
@CrossOrigin
@RestController
@RequiredArgsConstructor
@RequestMapping("User/Admin")
public class UserAdminController {
private final UserAdminService userAdminService;
@NonNull
@PostMapping("page")
public Page<UserPrivateDto> page(@NonNull final UserPrivateUuid privateUuid, @NonNull @RequestBody final UserAdminPageRequest request) {
return userAdminService.page(privateUuid, request);
}
@PostMapping("delete")
public void delete(@NonNull final UserPrivateUuid privateUuid, @RequestBody @NonNull final String deletePrivateUuid) { // TODO we cannot use UserPrivateUuid for 'deletePrivateUuid' because it would be filled with cookie's UserPrivateUuid
userAdminService.delete(privateUuid, new UserPrivateUuid(deletePrivateUuid));
}
}

View File

@ -0,0 +1,48 @@
package de.ph87.tools.user.admin;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NonNull;
import lombok.ToString;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import java.util.List;
@Getter
@ToString
@AllArgsConstructor
public class UserAdminPageRequest {
public final int pageIndex;
public final int pageSize;
@NonNull
public final List<Order> orders;
@NonNull
public Pageable getPageable() {
return PageRequest.of(pageIndex, pageSize, Sort.by(orders.stream().map(Order::toSortOrder).toList()));
}
@Getter
@ToString
@AllArgsConstructor
public static class Order {
@NonNull
public final String property;
@NonNull
public final Sort.Direction direction;
@NonNull
public Sort.Order toSortOrder() {
return new Sort.Order(direction, property);
}
}
}

View File

@ -0,0 +1,75 @@
package de.ph87.tools.user.admin;
import de.ph87.tools.email.EmailService;
import de.ph87.tools.group.GroupRepository;
import de.ph87.tools.group.member.GroupMemberService;
import de.ph87.tools.group.owner.GroupOwnerService;
import de.ph87.tools.tools.numbers.NumbersRepository;
import de.ph87.tools.user.User;
import de.ph87.tools.user.UserAccessService;
import de.ph87.tools.user.UserPrivateDto;
import de.ph87.tools.user.UserRepository;
import de.ph87.tools.user.uuid.UserPrivateUuid;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;
@Slf4j
@Service
@Transactional
@RequiredArgsConstructor
public class UserAdminService {
private final UserRepository userRepository;
private final UserAccessService userAccessService;
private final GroupRepository groupRepository;
private final GroupMemberService groupMemberService;
private final NumbersRepository numbersRepository;
private final GroupOwnerService groupOwnerService;
private final EmailService emailService;
@NonNull
public Page<UserPrivateDto> page(@NonNull final UserPrivateUuid privateUuid, @NonNull final UserAdminPageRequest request) {
adminAccess(privateUuid);
return userRepository.findAll(request.getPageable()).map(UserPrivateDto::new);
}
public void delete(@NonNull final UserPrivateUuid privateUuid, @NonNull final UserPrivateUuid deletePrivateUuid) {
adminAccess(privateUuid);
final User user = userAccessService.access(deletePrivateUuid);
groupRepository.findAllByOwner(user).forEach(group -> groupOwnerService.delete(group.getOwner().getPrivateUuid(), group.getUuid()));
groupRepository.findAllByUsersContains(user).forEach(group -> groupMemberService._remove_user_from_group_unchecked(group, user));
numbersRepository.findAllByLotsUser(user).forEach(numbers -> numbers.getLots().removeIf(lot -> {
if (lot.getUser().equals(user)) {
log.info("Deleting NumbersLot: {}", lot);
return true;
}
return false;
}));
emailService.deleteAllByUser(user);
userRepository.delete(user);
log.info("User deleted: {}", user);
}
@NonNull
@SuppressWarnings("UnusedReturnValue")
private User adminAccess(@NonNull final UserPrivateUuid privateUuid) {
final User user = userAccessService.access(privateUuid);
if (!user.isAdmin()) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
}
return user;
}
}