Skip to content

Commit

Permalink
refact: [admin/users] modifie la section utilisateur de l’espace admi…
Browse files Browse the repository at this point in the history
…nistration

* restructuration du module adminstration en fragments / widgets
  • Loading branch information
matthieuaudemard committed Apr 30, 2023
1 parent f6011a6 commit a5bcb4d
Show file tree
Hide file tree
Showing 14 changed files with 87 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,12 @@ public UserDto enableUser(final String username) {
@Transactional
public UserDto updateUserRoles(final String username, final Set<RoleEnum> roles) {
final UserModel user = getUserByUsernameIfExists(username);
final Set<RoleModel> rolesModels = roles.stream().map(roleService::getRoleByName).collect(Collectors.toSet());
final Set<RoleModel> rolesModels = roles.stream()
.map(roleService::getRoleByName)
.collect(Collectors.toSet());

user.setRoles(rolesModels);

return userMapper.toDto(userRepository.save(user));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
import com.dynonuggets.refonteimplicaction.core.domain.repository.UserRepository;
import com.dynonuggets.refonteimplicaction.core.error.EntityNotFoundException;
import com.dynonuggets.refonteimplicaction.core.error.ImplicactionException;
import com.dynonuggets.refonteimplicaction.core.event.UserCreatedEvent;
import com.dynonuggets.refonteimplicaction.core.event.UserEnabledEvent;
import com.dynonuggets.refonteimplicaction.core.service.RoleService;
import com.dynonuggets.refonteimplicaction.core.service.UserService;
import com.dynonuggets.refonteimplicaction.core.utils.UserTestUtils;
import com.dynonuggets.refonteimplicaction.notification.service.NotificationService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
Expand Down Expand Up @@ -71,8 +71,6 @@ class AuthServiceTest {
JwtProvider jwtProvider;
@Mock
RefreshTokenService refreshTokenService;
@Mock
NotificationService notificationService;
@InjectMocks
AuthService authService;
@Captor
Expand Down Expand Up @@ -138,6 +136,7 @@ void should_register_user_when_request_is_valid_and_no_user_in_DB() {
verify(userRepository, times(1)).existsByEmail(any());
verify(passwordEncoder, times(1)).encode(any());
verify(roleService, times(3)).getRoleByName(any(RoleEnum.class));
verify(publisher, times(1)).publishEvent(any(UserEnabledEvent.class));
}

@Test
Expand Down Expand Up @@ -171,6 +170,7 @@ void should_register_user_when_request_is_valid_and_user_not_already_exists() {
verify(userRepository, times(1)).existsByUsername(any());
verify(userRepository, times(1)).existsByEmail(any());
verify(passwordEncoder, times(1)).encode(any());
verify(publisher, times(1)).publishEvent(any(UserCreatedEvent.class));
}

@Test
Expand Down Expand Up @@ -268,7 +268,7 @@ class LoginTest {
@DisplayName("doit identifier l'utilisateur quand il existe")
void should_log_user_when_exists() {
// given
final UserModel user = UserTestUtils.generateRandomUserModel();
final UserModel user = generateRandomUserModel();
final String username = user.getUsername();
final LoginRequest loginRequest = LoginRequest.builder().username(username).password("password").build();
final String jwtToken = "jwt-token";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import com.dynonuggets.refonteimplicaction.core.error.ImplicactionException;
import com.dynonuggets.refonteimplicaction.core.error.TechnicalException;
import com.dynonuggets.refonteimplicaction.core.service.UserService;
import com.dynonuggets.refonteimplicaction.core.utils.UserTestUtils;
import com.dynonuggets.refonteimplicaction.filemanagement.service.CloudService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
Expand All @@ -38,6 +37,7 @@
import static com.dynonuggets.refonteimplicaction.community.profile.utils.ProfileTestUtils.*;
import static com.dynonuggets.refonteimplicaction.core.error.CoreErrorResult.OPERATION_NOT_PERMITTED;
import static com.dynonuggets.refonteimplicaction.core.error.UserErrorResult.USERNAME_NOT_FOUND;
import static com.dynonuggets.refonteimplicaction.core.utils.UserTestUtils.generateRandomUserModel;
import static com.dynonuggets.refonteimplicaction.utils.AssertionUtils.assertImplicactionException;
import static java.lang.String.format;
import static java.util.List.of;
Expand Down Expand Up @@ -75,7 +75,7 @@ class CreateProfileTests {
@DisplayName("doit créer un profil utilisateur si l'utilisateur existe et que son profil n'existe pas encore")
void should_create_profile_if_user_exists_and_profile_is_not_already_created() {
// given
final UserModel userModel = UserTestUtils.generateRandomUserModel();
final UserModel userModel = generateRandomUserModel();
final String username = userModel.getUsername();
given(userService.getUserByUsernameIfExists(username)).willReturn(userModel);
given(profileRepository.findByUser_Username(username)).willReturn(Optional.empty());
Expand Down Expand Up @@ -109,7 +109,7 @@ void should_throw_exception_if_user_not_exists() {
@DisplayName("doit lancer une exception si le profil existe déjà")
void should_throw_exception_if_profile_already_exists() {
// given
final UserModel userModel = UserTestUtils.generateRandomUserModel();
final UserModel userModel = generateRandomUserModel();
final String username = userModel.getUsername();
given(userService.getUserByUsernameIfExists(username)).willReturn(userModel);
given(profileRepository.findByUser_Username(username)).willReturn(Optional.of(ProfileModel.builder().build()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
import com.dynonuggets.refonteimplicaction.community.profile.dto.ProfileUpdateRequest;
import com.dynonuggets.refonteimplicaction.community.training.domain.model.TrainingModel;
import com.dynonuggets.refonteimplicaction.community.workexperience.domain.model.WorkExperienceModel;
import com.dynonuggets.refonteimplicaction.core.utils.UserTestUtils;
import lombok.NoArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.test.web.servlet.ResultActions;

import java.util.List;

import static com.dynonuggets.refonteimplicaction.core.utils.AppUtils.callIfNotNull;
import static com.dynonuggets.refonteimplicaction.core.utils.UserTestUtils.generateRandomUserModel;
import static com.dynonuggets.refonteimplicaction.utils.TestUtils.generateRandomLocalDate;
import static com.dynonuggets.refonteimplicaction.utils.TestUtils.generateRandomNumber;
import static java.lang.String.format;
Expand All @@ -31,7 +31,7 @@ public class ProfileTestUtils {
public static ProfileModel generateRandomProfile() {
return ProfileModel.builder()
.id((long) generateRandomNumber())
.user(UserTestUtils.generateRandomUserModel())
.user(generateRandomUserModel())
.hobbies(randomAlphabetic(100))
.purpose(randomAlphabetic(100))
.presentation(randomAlphabetic(100))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import com.dynonuggets.refonteimplicaction.core.error.ImplicactionException;
import com.dynonuggets.refonteimplicaction.core.event.UserEnabledEvent;
import com.dynonuggets.refonteimplicaction.core.mapper.UserMapper;
import com.dynonuggets.refonteimplicaction.core.utils.UserTestUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
Expand Down Expand Up @@ -73,7 +72,7 @@ void setMockOutput() {
generateRandomUserModel(Set.of(ROLE_ADMIN), true),
generateRandomUserModel(Set.of(ROLE_USER, ROLE_ADMIN), true)
);
mockedUser = UserTestUtils.generateRandomUserModel();
mockedUser = generateRandomUserModel();
mockedUserDto = generateRandomUserDto();
}

Expand Down Expand Up @@ -232,7 +231,7 @@ void should_update_user_roles_when_user_exists() {
// given
final Set<RoleEnum> roleEnums = Set.of(ROLE_USER, ROLE_PREMIUM);
final Set<RoleModel> roles = roleEnums.stream().map(name -> RoleModel.builder().name(name).build()).collect(Collectors.toSet());
final UserModel expectedUser = UserTestUtils.generateRandomUserModel(Set.of(ROLE_USER), true);
final UserModel expectedUser = generateRandomUserModel(Set.of(ROLE_USER), true);
given(userRepository.findByUsername(expectedUser.getUsername())).willReturn(of(expectedUser));
given(userRepository.save(expectedUser)).willReturn(expectedUser);
roles.forEach(role -> given(roleService.getRoleByName(role.getName())).willReturn(role));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core';
import {Component, Input, OnInit} from '@angular/core';
import {User} from "../../../../shared/models/user";

@Component({
selector: 'app-user-status-badge',
templateUrl: './user-status-badge.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserStatusBadgeComponent implements OnInit {

@Input() enabled: boolean;
@Input() user: User;

status: string;
text: string;

ngOnInit(): void {
if (this.enabled) {
if (this.user.enabled) {
this.status = 'success';
this.text = 'actif';
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ <h2 class="card-title">{{title}}</h2>

<div class="datatable-wrapper datatable-loading sortable searchable fixed-columns">
<div class="datatable-top">
<div *ngIf="pageable?.rowsPerPages?.length" class="datatable-dropdown">
<div *ngIf="rowsPerPages?.length" class="datatable-dropdown">
<label>
<p-dropdown
(ngModelChange)="updateRowsPerPage($event)"
[options]="pageable.rowsPerPages"
[(ngModel)]="pageable.rows"
[options]="rowsPerPages"
[(ngModel)]="rows"
></p-dropdown>
<span class="ps-2">entrées par page</span>
</label>
Expand Down Expand Up @@ -66,7 +66,7 @@ <h2 class="card-title">{{title}}</h2>
<td role="cell">{{user.email}}</td>
<td role="cell">
<div class="options-wrapper d-flex justify-content-between align-items-center">
<app-user-status-badge [enabled]="user.enabled"></app-user-status-badge>
<app-user-status-badge [user]="user"></app-user-status-badge>
<div>
<a
id="dropdownMenuButton"
Expand All @@ -83,7 +83,7 @@ <h2 class="card-title">{{title}}</h2>
<i class="fa fa-times text-danger"></i> désactiver l'utilisateur (non fonctionnel)
</span>
</li>
<li>
<li *ngIf="!user.enabled">
<span (click)="enableUser(user)" class="dropdown-item cursor-pointer">
<i class="fa fa-check text-success"></i> activer l'utilisateur
</span>
Expand All @@ -99,8 +99,9 @@ <h2 class="card-title">{{title}}</h2>
</div>
<div class="d-flex justify-content-end align-items-center datatable-bottom">
<app-paginator
[pageable]="pageable"
(pageChange)="updatePage($event)"
[totalPages]="totalPage"
[page]="page"
(pageChange)="updatePage($event.page)"
></app-paginator>
</div>
</div>
Expand All @@ -111,7 +112,7 @@ <h2 class="card-title">{{title}}</h2>
</div>

<ng-template #templateLoading>
<tr *ngFor="let user of [].constructor(pageable.rows); let index = index" style="height: 58px">
<tr *ngFor="let user of [].constructor(rows); let index = index" style="height: 58px">
<td>
<p-skeleton width="60%"></p-skeleton>
</td>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Outp
import {User} from "../../../../shared/models/user";
import {RoleEnum} from "../../../../shared/enums/role.enum";
import {UserService} from "../../../../community/services/profile/user.service";
import {Pageable} from "../../../../shared/models/pageable";
import {PaginationUpdate} from "../../../../shared/models/pagination-update";

@Component({
selector: 'app-users-table',
Expand All @@ -12,16 +12,19 @@ import {Pageable} from "../../../../shared/models/pageable";
})
export class UsersTableComponent implements OnChanges {

@Input() pageable: Pageable<User>;
@Input() users: User[];
@Input() rowsPerPages: number[];
@Input() rows: number
@Input() page: number;
@Input() totalPage: number;
@Input() title: string;
@Input() loading = false;

@Output() paginationChange = new EventEmitter<Pageable<User>>();
@Output() paginationChange = new EventEmitter<PaginationUpdate>();
@Output() userUpdate = new EventEmitter<User>();
@Output() sortChange = new EventEmitter<string>();

roles = RoleEnum.all();
users: User[];


constructor(private userService: UserService) {
Expand All @@ -47,12 +50,12 @@ export class UsersTableComponent implements OnChanges {
.subscribe(userSaved => this.userUpdate.emit(userSaved));
}

updateRowsPerPage(rows: number): void {
this.paginationChange.emit({...this.pageable, rows});
updateRowsPerPage(rowsPerPage: number): void {
this.paginationChange.emit({rowsPerPage});
}

updatePage(number: number): void {
this.paginationChange.emit({...this.pageable, number});
updatePage(page: number): void {
this.paginationChange.emit({page});
}

updateSort(key: string): void {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
<app-users-table
(userUpdate)="updateUser($event)"
(paginationChange)="updateUserPageable($event)"
(paginationChange)="updatePagination($event)"
[loading]="loading"
[title]="title"
[pageable]="pageable"
[users]="pageable.content"
[rowsPerPages]="pageable.rowsPerPages"
[page]="pageable.number"
[totalPage]="pageable.totalPages"
></app-users-table>
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {Constants} from "../../../config/constants";
import {UserService} from "../../../community/services/profile/user.service";
import {ToasterService} from "../../../core/services/toaster.service";
import {finalize} from "rxjs/operators";
import {PaginationUpdate} from "../../../shared/models/pagination-update";

@Component({
selector: 'app-user-management-widget',
Expand Down Expand Up @@ -34,12 +35,19 @@ export class UserManagementWidgetComponent implements OnInit {

updateUser(userUpdated: User): void {
const index = this.pageable.content.findIndex(user => userUpdated.id === user.id);
this.pageable.content.splice(index, 1, userUpdated);
this.pageable.content.splice(index, 1, userUpdated)
this.pageable = {...this.pageable};
this.toasterService.success('Succès', 'L\'utilisateur a bien été mis à jour')
}

updateUserPageable(pageable: Pageable<User>) {
this.fetchUsers(pageable);
updatePagination(update: PaginationUpdate) {
if (update.rowsPerPage) {
this.pageable.rows = update.rowsPerPage;
}
if (update.page !== undefined) {
this.pageable.number = update.page;
}
this.fetchUsers();
}

private fetchUsers(pageable = this.pageable): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@
<div class="d-flex justify-content-end">
<app-paginator
class="align-self-end"
(pageChange)="setCurrentPage($event)"
[pageable]="pageable"
(pageChange)="setCurrentPage($event.page)"
[totalPages]="pageable.totalPages"
[page]="pageable.number"
></app-paginator>
</div>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
<nav>
<ul class="pagination justify-content-center align-items-end m-0">
<li *ngIf="!pageable.first" class="page-item cursor-pointer">
<li *ngIf="!first" class="page-item cursor-pointer">
<span
class="page-link"
tabindex="-1"
(click)="changePage(pageable.number - 1)"
(click)="changePage(page - 1)"
>‹ préc</span>
</li>
<ng-container *ngFor="let _ of [].constructor(pageable?.totalPages); let index = index">
<ng-container *ngFor="let _ of [].constructor(totalPages); let index = index">
<li
class="page-item"
(click)="changePage(index)"
[ngClass]="{'disabled': (pageable.number === index), 'cursor-pointer': (pageable.number !== index)}"
[ngClass]="{'disabled': (page === index), 'cursor-pointer': (page !== index)}"
>
<a class="page-link" [ngClass]="{'disabled': (pageable.number === index)}">{{index + 1}}</a>
<a class="page-link" [ngClass]="{'disabled': (page === index)}">{{index + 1}}</a>
</li>
</ng-container>
<li *ngIf="!pageable.last" class="page-item cursor-pointer">
<a class="page-link" (click)="changePage(pageable.number + 1)">suiv ›</a>
<li *ngIf="!last" class="page-item cursor-pointer">
<a class="page-link" (click)="changePage(page + 1)">suiv ›</a>
</li>
</ul>
</nav>
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
import {ChangeDetectionStrategy, Component, EventEmitter, Input, Output} from '@angular/core';
import {Pageable} from "../../models/pageable";
import {ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges} from '@angular/core';
import {PaginationUpdate} from "../../models/pagination-update";

@Component({
selector: 'app-paginator',
templateUrl: './paginator.component.html',
styleUrls: ['./paginator.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class PaginatorComponent {
export class PaginatorComponent implements OnChanges {

@Input() pageable: Pageable<any>;
@Input() page: number;
@Input() totalPages: number;

@Output() pageChange = new EventEmitter<number>();
@Output() pageChange = new EventEmitter<PaginationUpdate>();

first: boolean;
last: boolean;

ngOnChanges(changes: SimpleChanges): void {
if (changes.hasOwnProperty('page') || changes.hasOwnProperty('totalPages')) {
this.first = !this.page
this.last = this.page >= (this.totalPages - 1);
}
}

changePage(page: number): void {
this.pageChange.emit(page);
this.pageChange.emit({page});
}
}
Loading

0 comments on commit a5bcb4d

Please sign in to comment.