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 29, 2023
1 parent 0dacb41 commit 75efc18
Show file tree
Hide file tree
Showing 67 changed files with 653 additions and 706 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package com.dynonuggets.refonteimplicaction.core.controller;

import com.dynonuggets.refonteimplicaction.core.domain.model.properties.enums.RoleEnum;
import com.dynonuggets.refonteimplicaction.core.dto.UserDto;
import com.dynonuggets.refonteimplicaction.core.service.UserService;
import lombok.AllArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.Set;

import static com.dynonuggets.refonteimplicaction.core.utils.UserUris.*;


Expand All @@ -23,9 +27,11 @@ public class UserController {
@GetMapping
public ResponseEntity<Page<UserDto>> getAll(
@RequestParam(defaultValue = "0") final int page,
@RequestParam(defaultValue = "10") final int rows
@RequestParam(defaultValue = "10") final int rows,
@RequestParam(value = "sortBy", defaultValue = "id") final String[] sortBy,
@RequestParam(value = "sortOrder", defaultValue = "ASC") final String sortOrder
) {
final Pageable pageable = PageRequest.of(page, rows);
final Pageable pageable = PageRequest.of(page, rows, Sort.by(Sort.Direction.valueOf(sortOrder), sortBy));
final Page<UserDto> users = userService.getAll(pageable);
return ResponseEntity.ok(users);
}
Expand All @@ -43,8 +49,13 @@ public ResponseEntity<Page<UserDto>> getAllPendingUsers(

@PostMapping(ENABLE_USER)
@PreAuthorize("hasRole('ROLE_ADMIN')")
public ResponseEntity<Void> enableUser(@PathVariable final String username) {
userService.enableUser(username);
return ResponseEntity.ok().build();
public ResponseEntity<UserDto> enableUser(@PathVariable final String username) {
return ResponseEntity.ok(userService.enableUser(username));
}

@PostMapping(UPDATE_USER_ROLES)
@PreAuthorize("hasRole('ROLE_ADMIN')")
public ResponseEntity<UserDto> updateUserRoles(@PathVariable final String username, @RequestBody final Set<RoleEnum> roles) {
return ResponseEntity.ok(userService.updateUserRoles(username, roles));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.dynonuggets.refonteimplicaction.core.domain.model.RoleModel;
import com.dynonuggets.refonteimplicaction.core.domain.model.UserModel;
import com.dynonuggets.refonteimplicaction.core.domain.model.properties.enums.RoleEnum;
import com.dynonuggets.refonteimplicaction.core.domain.repository.UserRepository;
import com.dynonuggets.refonteimplicaction.core.dto.UserDto;
import com.dynonuggets.refonteimplicaction.core.error.EntityNotFoundException;
Expand All @@ -14,6 +15,9 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Set;
import java.util.stream.Collectors;

import static com.dynonuggets.refonteimplicaction.core.domain.model.properties.enums.RoleEnum.ROLE_USER;
import static com.dynonuggets.refonteimplicaction.core.error.UserErrorResult.USERNAME_NOT_FOUND;
import static com.dynonuggets.refonteimplicaction.core.error.UserErrorResult.USER_ID_NOT_FOUND;
Expand Down Expand Up @@ -71,7 +75,7 @@ public UserModel getUserByIdIfExists(final Long userId) {
}

@Transactional
public void enableUser(final String username) {
public UserDto enableUser(final String username) {
final UserModel user = getUserByUsernameIfExists(username);
final RoleModel roleUser = roleService.getRoleByName(ROLE_USER);

Expand All @@ -80,5 +84,17 @@ public void enableUser(final String username) {

userRepository.save(user);
publisher.publishEvent(new UserEnabledEvent(this, user.getUsername()));

return userMapper.toDto(user);
}

@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());

user.setRoles(rolesModels);

return userMapper.toDto(userRepository.save(user));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ public class UserUris {
public static final String USER_BASE_URI = "/api/users";
public static final String GET_PENDING_USER_URI = "/pending";
public static final String ENABLE_USER = "/{username}/enable";
public static final String UPDATE_USER_ROLES = "/{username}/roles";
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@
import static com.dynonuggets.refonteimplicaction.core.utils.UserUris.*;
import static java.util.List.of;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.willDoNothing;
import static org.mockito.Mockito.*;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest(controllers = UserController.class)
Expand Down Expand Up @@ -111,7 +111,7 @@ void should_response_ok_with_list_of_non_activated_users_when_user_is_authentica
given(userService.getAllPendingActivationUsers(any())).willReturn(expectedUsers);

// when
final ResultActions resultActions = mvc.perform(get(USER_BASE_URI + GET_PENDING_USER_URI));
final ResultActions resultActions = mvc.perform(get(getFullPath(GET_PENDING_USER_URI)));

// then
resultActionsValidationForPageUser(expectedUsers, resultActions);
Expand All @@ -122,7 +122,7 @@ void should_response_ok_with_list_of_non_activated_users_when_user_is_authentica
@DisplayName("doit répondre OK avec la liste des utilisateurs dont le compte n'est pas encore activé")
void should_response_forbidden_when_user_is_not_authenticated() throws Exception {
// when
final ResultActions resultActions = mvc.perform(get(USER_BASE_URI + GET_PENDING_USER_URI));
final ResultActions resultActions = mvc.perform(get(getFullPath(GET_PENDING_USER_URI)));

// then
resultActions.andExpect(status().isForbidden());
Expand All @@ -139,11 +139,14 @@ class EnableUserTests {
void should_response_ok_when_current_user_has_role_admin_and_csrf_token_is_present() throws Exception {
// given
final String username = "username";
willDoNothing().given(userService).enableUser(username);
given(userService.enableUser(username)).willReturn(UserDto.builder().username("username").enabled(true).build());

// when - then
mvc.perform(post(USER_BASE_URI + ENABLE_USER, username).with(csrf()))
.andExpect(status().isOk());
mvc.perform(post(getFullPath(ENABLE_USER), username).with(csrf()))
.andExpect(status().isOk())
.andExpect(jsonPath("$.username").value(username))
.andExpect(jsonPath("$.enabled").value(true));
verify(userService, times(1)).enableUser(username);
}

@Test
Expand All @@ -152,11 +155,13 @@ void should_response_ok_when_current_user_has_role_admin_and_csrf_token_is_prese
void should_response_ok_when_current_user_has_role_admin() throws Exception {
// given
final String username = "username";
willDoNothing().given(userService).enableUser(username);

// when - then
mvc.perform(post(USER_BASE_URI + ENABLE_USER, username))
.andExpect(status().isForbidden());
// when
final ResultActions resultActions = mvc.perform(post(getFullPath(ENABLE_USER), username));

// then
resultActions.andExpect(status().isForbidden());
verifyNoInteractions(userService);
}

@Test
Expand All @@ -165,11 +170,13 @@ void should_response_ok_when_current_user_has_role_admin() throws Exception {
void should_response_ok_when_current_user_is_not_admin() throws Exception {
// given
final String username = "username";
willDoNothing().given(userService).enableUser(username);

// when - then
mvc.perform(post(USER_BASE_URI + ENABLE_USER, username).with(csrf()))
.andExpect(status().isForbidden());
// when
final ResultActions resultActions = mvc.perform(post(getFullPath(ENABLE_USER), username).with(csrf()));

// then
resultActions.andExpect(status().isForbidden());
verifyNoInteractions(userService);
}

@Test
Expand All @@ -178,11 +185,13 @@ void should_response_ok_when_current_user_is_not_admin() throws Exception {
void should_response_ok_when_current_user_is_not_authenticated() throws Exception {
// given
final String username = "username";
willDoNothing().given(userService).enableUser(username);

// when - then
mvc.perform(post(USER_BASE_URI + ENABLE_USER, username).with(csrf()))
.andExpect(status().isForbidden());
final ResultActions resultActions = mvc.perform(post(getFullPath(ENABLE_USER), username).with(csrf()));

// then
resultActions.andExpect(status().isForbidden());
verifyNoInteractions(userService);
}
}
}
32 changes: 17 additions & 15 deletions frontend-implicaction/src/app/admin/admin-routing.module.ts
Original file line number Diff line number Diff line change
@@ -1,67 +1,69 @@
import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
import {AdminComponent} from './admin.component';
import {JobFilterComponent} from '../shared/components/job-filter/job-filter.component';
import {CompanyFilterComponent} from '../shared/components/company-filter/company-filter.component';
import {AdminPageComponent} from "./pages/admin-page/admin-page.component";
import {UserFragmentComponent} from "./fragments/user-fragment/user-fragment.component";
import {DashboardFragmentComponent} from "./fragments/dashboard-fragment/dashboard-fragment.component";


const routes: Routes = [
{
path: '', redirectTo: 'dashboard', pathMatch: 'full'
},
{
path: 'dashboard', component: AdminComponent, children: [
path: 'dashboard', component: AdminPageComponent, children: [
{
path: '',
loadChildren: () => import('./dashboard/dashboard.module').then(m => m.DashboardModule),
outlet: 'admin-content'
component: DashboardFragmentComponent,
outlet: 'fragment-content'
}
]
},
{
path: 'users', component: AdminComponent, children: [
path: 'users', component: AdminPageComponent, children: [
{
path: '',
loadChildren: () => import('./users/users.module').then(m => m.UsersModule),
outlet: 'admin-content'
component: UserFragmentComponent,
outlet: 'fragment-content'
}
]
},
{
path: 'jobs', component: AdminComponent, children: [
path: 'jobs', component: AdminPageComponent, children: [
{
path: '',
loadChildren: () => import('./jobs/admin-jobs.module').then(m => m.AdminJobsModule),
outlet: 'admin-content',
outlet: 'fragment-content',

},
{
path: '',
component: JobFilterComponent,
outlet: 'admin-filter'
outlet: 'fragment-content'
}
]
},
{
path: 'companies', component: AdminComponent, children: [
path: 'companies', component: AdminPageComponent, children: [
{
path: '',
loadChildren: () => import('./companies/companies.module').then(m => m.CompaniesModule),
outlet: 'admin-content'
outlet: 'fragment-content'
},
{
path: '',
component: CompanyFilterComponent,
outlet: 'admin-filter'
outlet: 'fragment-content'
}
]
},
{
path: 'forum', component: AdminComponent, children: [
path: 'forum', component: AdminPageComponent, children: [
{
path: '',
loadChildren: () => import('./forum/forum.module').then(m => m.ForumModule),
outlet: 'admin-content'
outlet: 'fragment-content'
}
]
},
Expand Down
11 changes: 0 additions & 11 deletions frontend-implicaction/src/app/admin/admin.component.html

This file was deleted.

10 changes: 0 additions & 10 deletions frontend-implicaction/src/app/admin/admin.component.ts

This file was deleted.

46 changes: 34 additions & 12 deletions frontend-implicaction/src/app/admin/admin.module.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,59 @@
import {LOCALE_ID, NgModule} from '@angular/core';
import {CommonModule, registerLocaleData} from '@angular/common';
import localeFr from '@angular/common/locales/fr';
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {AdminRoutingModule} from './admin-routing.module';
import {AdminComponent} from './admin.component';
import {SharedModule} from './shared/shared.module';
import {CompaniesComponent} from './companies/companies.component';
import {TableModule} from 'primeng/table';
import {CompaniesModule} from './companies/companies.module';
import {FeatherModule} from 'angular-feather';
import {PendingGroupTableComponent} from './groups/pending-group-table/pending-group-table.component';
import {AdminPageComponent} from './pages/admin-page/admin-page.component';
import {SharedModule} from "../shared/shared.module";
import {UsersTableComponent} from './components/users/users-table/users-table.component';
import {UserStatusBadgeComponent} from './components/users/user-status-badge/user-status-badge.component';
import {MultiSelectModule} from "primeng/multiselect";
import {FormsModule} from "@angular/forms";
import {TooltipModule} from "primeng/tooltip";
import {DropdownModule} from "primeng/dropdown";
import {UserManagementWidgetComponent} from './widgets/user-management-wiget/user-management-widget.component';
import {UserFragmentComponent} from './fragments/user-fragment/user-fragment.component';
import {SkeletonModule} from "primeng/skeleton";
import {DashboardFragmentComponent} from "./fragments/dashboard-fragment/dashboard-fragment.component";
import {AdminOverviewWidgetComponent} from "./widgets/admin-overview-widget/admin-overview-widget.component";
import {PendingJobTableComponent} from "./components/users/pending-job-table/pending-job-table.component";


@NgModule({
declarations: [
AdminComponent,
CompaniesComponent,
PendingGroupTableComponent,
AdminPageComponent,
UsersTableComponent,
UserStatusBadgeComponent,
UserManagementWidgetComponent,
UserFragmentComponent,
DashboardFragmentComponent,
AdminOverviewWidgetComponent,
PendingJobTableComponent
],
imports: [
CommonModule,
AdminRoutingModule,
SharedModule,
TableModule,
CompaniesModule,
FeatherModule
FeatherModule,
SharedModule,
MultiSelectModule,
FormsModule,
TooltipModule,
DropdownModule,
SkeletonModule
],
providers: [{provide: LOCALE_ID, useValue: 'fr'}],
exports: [
PendingGroupTableComponent
PendingGroupTableComponent,
UsersTableComponent,
UserManagementWidgetComponent
]
})
export class AdminModule {
constructor() {
registerLocaleData(localeFr, 'fr'); // passage du format de date en français
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<span class="badge bg-{{status}}">{{text}}</span>
Loading

0 comments on commit 75efc18

Please sign in to comment.