Compare commits
7 Commits
Author | SHA1 | Date |
---|---|---|
William Nolin | 576fa3c8b2 | |
William Nolin | 5aae63e545 | |
William Nolin | be92c22de0 | |
William Nolin | 63e70cd109 | |
William Nolin | deee043c66 | |
William Nolin | 3ff897fc85 | |
William Nolin | 24349ae051 |
|
@ -4,65 +4,69 @@ import {CatalogComponent} from './pages/catalog/catalog.component'
|
||||||
import {AdministrationComponent} from './pages/administration/administration.component'
|
import {AdministrationComponent} from './pages/administration/administration.component'
|
||||||
import {MiscComponent} from './pages/others/misc.component'
|
import {MiscComponent} from './pages/others/misc.component'
|
||||||
import {CreConfigEditor} from './modules/configuration/config-editor'
|
import {CreConfigEditor} from './modules/configuration/config-editor'
|
||||||
|
import {routes as routesConst} from './routes'
|
||||||
|
|
||||||
const routes: Routes = [{
|
const routes: Routes = [{
|
||||||
path: 'color',
|
path: routesConst.recipes.route,
|
||||||
loadChildren: () => import('./modules/recipes/recipes.module').then(m => m.RecipesModule)
|
loadChildren: () => import('./modules/recipes/recipes.module').then(m => m.RecipesModule)
|
||||||
}, {
|
}, {
|
||||||
path: 'account',
|
path: routesConst.accounts.route,
|
||||||
loadChildren: () => import('./modules/accounts/accounts.module').then(m => m.AccountsModule)
|
loadChildren: () => import('./modules/accounts/accounts.module').then(m => m.AccountsModule)
|
||||||
}, {
|
}, {
|
||||||
path: 'catalog',
|
path: routesConst.catalog.route,
|
||||||
component: CatalogComponent,
|
component: CatalogComponent,
|
||||||
children: [{
|
children: [{
|
||||||
path: 'materialtype',
|
path: routesConst.catalog.children.materialTypes.simpleRoute,
|
||||||
loadChildren: () => import('./modules/material-type/material-type.module').then(m => m.MaterialTypeModule),
|
loadChildren: () => import('./modules/material-type/material-type.module').then(m => m.MaterialTypeModule),
|
||||||
}, {
|
}, {
|
||||||
path: 'material',
|
path: routesConst.catalog.children.materials.simpleRoute,
|
||||||
loadChildren: () => import('./modules/material/material.module').then(m => m.MaterialModule)
|
loadChildren: () => import('./modules/material/material.module').then(m => m.MaterialModule)
|
||||||
}, {
|
}, {
|
||||||
path: 'company',
|
path: routesConst.catalog.children.companies.simpleRoute,
|
||||||
loadChildren: () => import('./modules/company/company.module').then(m => m.CompanyModule)
|
loadChildren: () => import('./modules/company/company.module').then(m => m.CompanyModule)
|
||||||
}, {
|
}, {
|
||||||
path: '',
|
path: '',
|
||||||
pathMatch: 'full',
|
pathMatch: 'full',
|
||||||
redirectTo: 'materialtype'
|
redirectTo: routesConst.catalog.children.materials.simpleRoute
|
||||||
}]
|
}]
|
||||||
}, {
|
}, {
|
||||||
path: 'admin',
|
path: routesConst.administration.route,
|
||||||
component: AdministrationComponent,
|
component: AdministrationComponent,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: 'user',
|
path: routesConst.administration.children.users.simpleRoute,
|
||||||
loadChildren: () => import('./modules/users/user.module').then(m => m.UserModule)
|
loadChildren: () => import('./modules/users/user.module').then(m => m.UserModule)
|
||||||
}, {
|
}, {
|
||||||
path: 'group',
|
path: routesConst.administration.children.groups.simpleRoute,
|
||||||
loadChildren: () => import('./modules/groups/group.module').then(m => m.GroupModule)
|
loadChildren: () => import('./modules/groups/group.module').then(m => m.GroupModule)
|
||||||
}, {
|
}, {
|
||||||
path: 'config',
|
path: routesConst.administration.children.groupTokens.simpleRoute,
|
||||||
|
loadChildren: () => import('./modules/groupTokens/group-tokens.module').then(m => m.GroupTokensModule)
|
||||||
|
}, {
|
||||||
|
path: routesConst.administration.children.configurations.simpleRoute,
|
||||||
loadChildren: () => import('./modules/configuration/config.module').then(m => m.ConfigModule),
|
loadChildren: () => import('./modules/configuration/config.module').then(m => m.ConfigModule),
|
||||||
component: CreConfigEditor
|
component: CreConfigEditor
|
||||||
}, {
|
}, {
|
||||||
path: '',
|
path: '',
|
||||||
pathMatch: 'full',
|
pathMatch: 'full',
|
||||||
redirectTo: 'user'
|
redirectTo: routesConst.administration.children.users.simpleRoute
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}, {
|
}, {
|
||||||
path: 'misc',
|
path: routesConst.misc.route,
|
||||||
component: MiscComponent,
|
component: MiscComponent,
|
||||||
children: [{
|
children: [{
|
||||||
path: 'touch-up-kit',
|
path: routesConst.misc.children.touchUpKits.simpleRoute,
|
||||||
loadChildren: () => import('./modules/touch-up-kit/touch-up-kit.module').then(m => m.TouchUpKitModule)
|
loadChildren: () => import('./modules/touch-up-kit/touch-up-kit.module').then(m => m.TouchUpKitModule)
|
||||||
}, {
|
}, {
|
||||||
path: '',
|
path: '',
|
||||||
pathMatch: 'full',
|
pathMatch: 'full',
|
||||||
redirectTo: 'touch-up-kit'
|
redirectTo: routesConst.misc.children.touchUpKits.simpleRoute
|
||||||
}]
|
}]
|
||||||
}]
|
}]
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forRoot(routes, {relativeLinkResolution: 'legacy'})],
|
imports: [RouterModule.forRoot(routes)],
|
||||||
exports: [RouterModule]
|
exports: [RouterModule]
|
||||||
})
|
})
|
||||||
export class AppRoutingModule {
|
export class AppRoutingModule {
|
||||||
|
|
|
@ -3,8 +3,8 @@ import {NgModule} from '@angular/core'
|
||||||
import {AccountsRoutingModule} from './accounts-routing.module'
|
import {AccountsRoutingModule} from './accounts-routing.module'
|
||||||
import {SharedModule} from '../shared/shared.module'
|
import {SharedModule} from '../shared/shared.module'
|
||||||
import {Login, Logout} from './accounts'
|
import {Login, Logout} from './accounts'
|
||||||
import {CreInputsModule} from '../shared/components/inputs/inputs.module'
|
import {CreInputsModule} from "../shared/components/inputs/inputs.module";
|
||||||
import {CreButtonsModule} from '../shared/components/buttons/buttons.module'
|
import {CreButtonsModule} from "../shared/components/buttons/buttons.module";
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@ -16,7 +16,7 @@ import {CreButtonsModule} from '../shared/components/buttons/buttons.module'
|
||||||
SharedModule,
|
SharedModule,
|
||||||
AccountsRoutingModule,
|
AccountsRoutingModule,
|
||||||
CreInputsModule,
|
CreInputsModule,
|
||||||
CreButtonsModule,
|
CreButtonsModule
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AccountsModule {
|
export class AccountsModule {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {ErrorHandler, ErrorService} from '../shared/service/error.service'
|
||||||
import {ActivatedRoute, Router} from '@angular/router'
|
import {ActivatedRoute, Router} from '@angular/router'
|
||||||
import {CreForm, ICreForm} from "../shared/components/forms/forms";
|
import {CreForm, ICreForm} from "../shared/components/forms/forms";
|
||||||
import {AlertService} from "../shared/service/alert.service";
|
import {AlertService} from "../shared/service/alert.service";
|
||||||
|
import {routes} from "../../routes";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-login',
|
selector: 'cre-login',
|
||||||
|
@ -48,8 +49,8 @@ export class Login extends ErrorHandlingComponent {
|
||||||
|
|
||||||
submit() {
|
submit() {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.accountService.login(this.userIdControl.value, this.passwordControl.value),
|
this.accountService.loginAsUser(this.userIdControl.value, this.passwordControl.value),
|
||||||
'/color/list'
|
`/${routes.recipes.route}/list`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,13 +80,10 @@ export class Logout extends SubscribingComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
if (!this.appState.isAuthenticated) {
|
if (this.appState.isAuthenticated) {
|
||||||
this.urlUtils.navigateTo('/account/login')
|
this.accountService.logout()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.subscribeAndNavigate(
|
this.urlUtils.navigateTo(`/${routes.accounts.route}/login`)
|
||||||
this.accountService.logout(),
|
|
||||||
'/account/login'
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,11 @@ import {Injectable, OnDestroy} from '@angular/core'
|
||||||
import {Observable, Subject} from 'rxjs'
|
import {Observable, Subject} from 'rxjs'
|
||||||
import {take, takeUntil} from 'rxjs/operators'
|
import {take, takeUntil} from 'rxjs/operators'
|
||||||
import {AppState} from '../../shared/app-state'
|
import {AppState} from '../../shared/app-state'
|
||||||
import {HttpClient, HttpResponse} from '@angular/common/http'
|
import {HttpClient} from '@angular/common/http'
|
||||||
import {environment} from '../../../../environments/environment'
|
import {environment} from '../../../../environments/environment'
|
||||||
import {ApiService} from '../../shared/service/api.service'
|
import {ApiService} from '../../shared/service/api.service'
|
||||||
import {Permission, User} from '../../shared/model/user'
|
import {LoginDto, Permission} from '../../shared/model/account.model'
|
||||||
import {ErrorService} from '../../shared/service/error.service'
|
import {ErrorService} from '../../shared/service/error.service'
|
||||||
import {AlertService} from '../../shared/service/alert.service'
|
|
||||||
import {JwtService} from "./jwt.service";
|
import {JwtService} from "./jwt.service";
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
|
@ -21,8 +20,7 @@ export class AccountService implements OnDestroy {
|
||||||
private api: ApiService,
|
private api: ApiService,
|
||||||
private appState: AppState,
|
private appState: AppState,
|
||||||
private jwtService: JwtService,
|
private jwtService: JwtService,
|
||||||
private errorService: ErrorService,
|
private errorService: ErrorService
|
||||||
private alertService: AlertService
|
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,95 +29,58 @@ export class AccountService implements OnDestroy {
|
||||||
this.destroy$.complete()
|
this.destroy$.complete()
|
||||||
}
|
}
|
||||||
|
|
||||||
checkAuthenticationStatus() {
|
loginAsGroupIfNotAuthenticated() {
|
||||||
if (!this.appState.isAuthenticated) {
|
if (this.appState.isAuthenticated) return
|
||||||
// Try to get current default group user
|
|
||||||
this.http.get<User>(`${environment.apiUrl}/user/group/currentuser`, {withCredentials: true})
|
this.loginAsGroup()
|
||||||
.pipe(
|
}
|
||||||
take(1),
|
|
||||||
takeUntil(this.destroy$),
|
loginAsUser(id: number, password: string): Observable<LoginDto> {
|
||||||
).subscribe(
|
return this.login(false, {id, password}, error => {
|
||||||
{
|
if (error.status !== 403) return false
|
||||||
next: user => this.appState.authenticateGroupUser(user),
|
|
||||||
error: err => {
|
this.errorService.handleError({status: error.status, type: 'invalid-credentials', obj: error})
|
||||||
if (err.status === 404 || err.status === 403) {
|
return true
|
||||||
console.warn('No default user is defined on this computer')
|
})
|
||||||
} else {
|
}
|
||||||
this.errorService.handleError(err)
|
|
||||||
}
|
loginAsGroup(): Observable<LoginDto> {
|
||||||
}
|
return this.login(true, {},
|
||||||
})
|
error => error.status === 403) // There is no group token, so do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
private login(isGroup: boolean, body: LoginBody, errorConsumer: (any) => boolean): Observable<LoginDto> {
|
||||||
|
let url = `${environment.apiUrl}/account/login`
|
||||||
|
if (isGroup) {
|
||||||
|
url += '/group'
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
login(userId: number, password: string): Observable<any> {
|
const login$ = this.http.post<LoginDto>(url, body, {withCredentials: true})
|
||||||
const subject = new Subject<void>()
|
.pipe(take(1), takeUntil(this.destroy$))
|
||||||
|
|
||||||
this.http.post<any>(`${environment.apiUrl}/login`, {id: userId, password}, {
|
login$.subscribe({
|
||||||
withCredentials: true,
|
next: result => this.appState.authenticateUser(result, isGroup),
|
||||||
observe: 'response' as 'body'
|
|
||||||
}).pipe(
|
|
||||||
take(1),
|
|
||||||
takeUntil(this.destroy$)
|
|
||||||
).subscribe({
|
|
||||||
next: (response: HttpResponse<void>) => {
|
|
||||||
this.loginUser(response)
|
|
||||||
|
|
||||||
subject.next()
|
|
||||||
subject.complete()
|
|
||||||
},
|
|
||||||
error: error => {
|
error: error => {
|
||||||
if (error.status === 403) {
|
if (errorConsumer(error)) return;
|
||||||
this.alertService.pushError('Les identifiants entrés sont invalides')
|
|
||||||
} else {
|
|
||||||
this.errorService.handleError(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
subject.next()
|
this.errorService.handleErrorResponse(error)
|
||||||
subject.complete()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return subject
|
return login$
|
||||||
}
|
}
|
||||||
|
|
||||||
private loginUser(response: HttpResponse<void>) {
|
logout() {
|
||||||
const authorization = response.headers.get("Authorization")
|
|
||||||
const user = this.jwtService.parseUser(authorization)
|
|
||||||
|
|
||||||
this.appState.authenticateUser(user)
|
|
||||||
}
|
|
||||||
|
|
||||||
logout(): Observable<void> {
|
|
||||||
const subject = new Subject<void>()
|
|
||||||
|
|
||||||
this.api.get<void>('/logout').pipe(
|
|
||||||
take(1),
|
|
||||||
takeUntil(this.destroy$)
|
|
||||||
).subscribe({
|
|
||||||
next: () => {
|
|
||||||
this.logoutUser()
|
|
||||||
|
|
||||||
subject.next()
|
|
||||||
subject.complete()
|
|
||||||
},
|
|
||||||
error: error => {
|
|
||||||
this.errorService.handleError(error)
|
|
||||||
|
|
||||||
subject.next()
|
|
||||||
subject.complete()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return subject
|
|
||||||
}
|
|
||||||
|
|
||||||
private logoutUser() {
|
|
||||||
this.appState.resetAuthenticatedUser()
|
this.appState.resetAuthenticatedUser()
|
||||||
this.checkAuthenticationStatus()
|
this.loginAsGroupIfNotAuthenticated()
|
||||||
}
|
}
|
||||||
|
|
||||||
hasPermission(permission: Permission): boolean {
|
hasPermission(permission: Permission): boolean {
|
||||||
return this.appState.authenticatedUser && this.appState.authenticatedUser.permissions.indexOf(permission) >= 0
|
return this.appState.authenticatedUser && this.appState.authenticatedUser.permissions.indexOf(permission) >= 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface LoginBody {
|
||||||
|
id?: number
|
||||||
|
password?: string
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
import {Injectable} from "@angular/core";
|
||||||
|
import {ApiService} from "../../shared/service/api.service";
|
||||||
|
import {Observable} from "rxjs";
|
||||||
|
import {GroupToken} from "../../shared/model/account.model";
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: "root"
|
||||||
|
})
|
||||||
|
export class GroupTokenService {
|
||||||
|
constructor(
|
||||||
|
private api: ApiService
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
get all(): Observable<GroupToken[]> {
|
||||||
|
return this.api.get<GroupToken[]>('/account/group/token')
|
||||||
|
}
|
||||||
|
|
||||||
|
get current(): Observable<GroupToken | null> {
|
||||||
|
return this.api.get<GroupToken | null>('/account/group/token/current')
|
||||||
|
}
|
||||||
|
|
||||||
|
save(name: string, groupId: number): Observable<GroupToken> {
|
||||||
|
return this.api.post<GroupToken>('/account/group/token', {name, groupId})
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle(token: GroupToken): Observable<void> {
|
||||||
|
return token.enabled ?
|
||||||
|
this.api.put<void>(`/account/group/token/${token.id}/disable`) :
|
||||||
|
this.api.put<void>(`/account/group/token/${token.id}/enable`)
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(id: string): Observable<void> {
|
||||||
|
return this.api.delete<void>(`/account/group/token/${id}`)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
import {Injectable} from "@angular/core";
|
import {Injectable} from "@angular/core";
|
||||||
import jwtDecode from "jwt-decode";
|
import jwtDecode from "jwt-decode";
|
||||||
import { User } from "../../shared/model/user";
|
import { AccountModel } from "../../shared/model/account.model";
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class JwtService {
|
export class JwtService {
|
||||||
parseUser(jwt: string): User {
|
parseUser(jwt: string): AccountModel {
|
||||||
const decoded = jwtDecode(jwt) as any
|
const decoded = jwtDecode(jwt) as any
|
||||||
return JSON.parse(decoded.user)
|
return JSON.parse(decoded.user)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {FormField} from '../../../shared/components/entity-add/entity-add.compon
|
||||||
import {ActivatedRoute, Router} from '@angular/router'
|
import {ActivatedRoute, Router} from '@angular/router'
|
||||||
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
||||||
import {AppState} from '../../../shared/app-state'
|
import {AppState} from '../../../shared/app-state'
|
||||||
|
import {routes} from "../../../../routes";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-add',
|
selector: 'cre-add',
|
||||||
|
@ -50,7 +51,7 @@ export class AddComponent extends ErrorHandlingComponent {
|
||||||
this.submittedValues = values
|
this.submittedValues = values
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.companyService.save(values.name),
|
this.companyService.save(values.name),
|
||||||
'/catalog/company/list'
|
routes.catalog.children.companies.route + '/list'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {CompanyService} from '../../service/company.service'
|
||||||
import {ActivatedRoute, Router} from '@angular/router'
|
import {ActivatedRoute, Router} from '@angular/router'
|
||||||
import {ErrorHandler, ErrorHandlerComponent, ErrorService} from '../../../shared/service/error.service'
|
import {ErrorHandler, ErrorHandlerComponent, ErrorService} from '../../../shared/service/error.service'
|
||||||
import {AppState} from '../../../shared/app-state'
|
import {AppState} from '../../../shared/app-state'
|
||||||
|
import {routes} from "../../../../routes";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-edit',
|
selector: 'cre-edit',
|
||||||
|
@ -29,7 +30,7 @@ export class EditComponent extends ErrorHandlingComponent {
|
||||||
|
|
||||||
errorHandlers: ErrorHandler[] = [{
|
errorHandlers: ErrorHandler[] = [{
|
||||||
filter: error => error.type === 'notfound-company-id',
|
filter: error => error.type === 'notfound-company-id',
|
||||||
consumer: error => this.urlUtils.navigateTo('/catalog/company/list')
|
consumer: _ => this.urlUtils.navigateTo(routes.catalog.children.companies.route + '/list')
|
||||||
}, {
|
}, {
|
||||||
filter: error => error.type === 'exists-company-name',
|
filter: error => error.type === 'exists-company-name',
|
||||||
messageProducer: error => `Une bannière avec le nom '${error.name}' existe déjà`
|
messageProducer: error => `Une bannière avec le nom '${error.name}' existe déjà`
|
||||||
|
@ -65,14 +66,14 @@ export class EditComponent extends ErrorHandlingComponent {
|
||||||
submit(values) {
|
submit(values) {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.companyService.update(this.company.id, values.name),
|
this.companyService.update(this.company.id, values.name),
|
||||||
'/catalog/company/list'
|
routes.catalog.children.companies.route + '/list'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
delete() {
|
delete() {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.companyService.delete(this.company.id),
|
this.companyService.delete(this.company.id),
|
||||||
'/catalog/company/list'
|
routes.catalog.children.companies.route + '/list'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {Component} from '@angular/core'
|
import {Component} from '@angular/core'
|
||||||
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
|
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
|
||||||
import {CompanyService} from '../../service/company.service'
|
import {CompanyService} from '../../service/company.service'
|
||||||
import {Permission} from '../../../shared/model/user'
|
import {Permission} from '../../../shared/model/account.model'
|
||||||
import {ActivatedRoute, Router} from '@angular/router'
|
import {ActivatedRoute, Router} from '@angular/router'
|
||||||
import {ErrorService} from '../../../shared/service/error.service'
|
import {ErrorService} from '../../../shared/service/error.service'
|
||||||
import {AppState} from '../../../shared/app-state'
|
import {AppState} from '../../../shared/app-state'
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
<cre-prompt-dialog
|
||||||
|
title="Définir le groupe par défaut de cet ordinateur"
|
||||||
|
[continueButtonDisabled]="!form.valid"
|
||||||
|
(continue)="submit()">
|
||||||
|
<cre-dialog-body>
|
||||||
|
<form [formGroup]="form" class="w-100">
|
||||||
|
<cre-input [control]="controls.name" label="Nom" icon="form-textbox"></cre-input>
|
||||||
|
</form>
|
||||||
|
</cre-dialog-body>
|
||||||
|
</cre-prompt-dialog>
|
|
@ -0,0 +1,17 @@
|
||||||
|
import {RouterModule, Routes} from "@angular/router";
|
||||||
|
import {GroupTokenList} from "./group-tokens";
|
||||||
|
import {NgModule} from "@angular/core";
|
||||||
|
|
||||||
|
const routes: Routes = [{
|
||||||
|
path: 'list',
|
||||||
|
component: GroupTokenList
|
||||||
|
}, {
|
||||||
|
path: '', redirectTo: 'list'
|
||||||
|
}]
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forChild(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class GroupTokensRoutingModule {
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
import {NgModule} from '@angular/core'
|
||||||
|
|
||||||
|
import {SharedModule} from '../shared/shared.module'
|
||||||
|
import {CreInputsModule} from '../shared/components/inputs/inputs.module'
|
||||||
|
import {CreButtonsModule} from '../shared/components/buttons/buttons.module'
|
||||||
|
import {GroupTokenAdd, GroupTokenList} from "../groupTokens/group-tokens";
|
||||||
|
import {GroupTokensRoutingModule} from "./group-tokens-routing.module";
|
||||||
|
import {CreTablesModule} from "../shared/components/tables/tables.module";
|
||||||
|
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
GroupTokenAdd,
|
||||||
|
GroupTokenList
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
GroupTokenAdd
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
GroupTokensRoutingModule,
|
||||||
|
SharedModule,
|
||||||
|
CreInputsModule,
|
||||||
|
CreButtonsModule,
|
||||||
|
CreTablesModule
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class GroupTokensModule {
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
import {Component, EventEmitter, Output, ViewChild} from "@angular/core";
|
||||||
|
import {CrePromptDialog} from "../shared/components/dialogs/dialogs";
|
||||||
|
import {Group, GroupToken} from "../shared/model/account.model";
|
||||||
|
import {FormControl, FormGroup, Validators} from "@angular/forms";
|
||||||
|
import {GroupTokenService} from "../accounts/services/group-token.service";
|
||||||
|
import {SubscribingComponent} from "../shared/components/subscribing.component";
|
||||||
|
import {ErrorService} from "../shared/service/error.service";
|
||||||
|
import {ActivatedRoute, Router} from "@angular/router";
|
||||||
|
import {tap} from "rxjs/operators";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'cre-group-token-list',
|
||||||
|
templateUrl: 'list.html'
|
||||||
|
})
|
||||||
|
export class GroupTokenList extends SubscribingComponent {
|
||||||
|
tokens$ = this.groupTokenService.all.pipe(tap(
|
||||||
|
tokens => this.tokensEmpty = tokens.length <= 0))
|
||||||
|
tokensEmpty = false
|
||||||
|
|
||||||
|
columns = ['id', 'name', 'groupName', 'state', 'stateButton', 'deleteButton']
|
||||||
|
|
||||||
|
@ViewChild(CrePromptDialog) removePrompt: CrePromptDialog
|
||||||
|
removePromptToken: GroupToken | null = null
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private groupTokenService: GroupTokenService,
|
||||||
|
errorService: ErrorService,
|
||||||
|
router: Router,
|
||||||
|
activatedRoute: ActivatedRoute
|
||||||
|
) {
|
||||||
|
super(errorService, activatedRoute, router)
|
||||||
|
}
|
||||||
|
|
||||||
|
showRemovePrompt(token: GroupToken) {
|
||||||
|
this.removePromptToken = token
|
||||||
|
this.removePrompt.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle(token: GroupToken) {
|
||||||
|
this.subscribe(
|
||||||
|
this.groupTokenService.toggle(token),
|
||||||
|
_ => window.location.reload()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
delete() {
|
||||||
|
this.subscribe(
|
||||||
|
this.groupTokenService.delete(this.removePromptToken.id),
|
||||||
|
_ => window.location.reload()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'cre-group-token-add',
|
||||||
|
templateUrl: 'add.html'
|
||||||
|
})
|
||||||
|
export class GroupTokenAdd extends SubscribingComponent {
|
||||||
|
@ViewChild(CrePromptDialog) dialog: CrePromptDialog
|
||||||
|
|
||||||
|
@Output() defaultGroupUpdate = new EventEmitter<GroupToken>()
|
||||||
|
|
||||||
|
controls = {name: new FormControl(null, Validators.required)}
|
||||||
|
form = new FormGroup(this.controls)
|
||||||
|
|
||||||
|
private group: Group | null
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private groupTokenService: GroupTokenService,
|
||||||
|
errorService: ErrorService,
|
||||||
|
router: Router,
|
||||||
|
activatedRoute: ActivatedRoute
|
||||||
|
) {
|
||||||
|
super(errorService, activatedRoute, router)
|
||||||
|
}
|
||||||
|
|
||||||
|
show(group: Group) {
|
||||||
|
this.group = group
|
||||||
|
this.dialog.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
submit() {
|
||||||
|
if (!this.group) {
|
||||||
|
console.error("Group token group id was not defined")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const name = this.controls.name.value
|
||||||
|
this.subscribe(
|
||||||
|
this.groupTokenService.save(name, this.group.id),
|
||||||
|
groupToken => this.defaultGroupUpdate.emit(groupToken)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
<div class="mt-5"></div>
|
||||||
|
|
||||||
|
<cre-warning-alert *ngIf="tokensEmpty">
|
||||||
|
<p>Il n'y a aucun ordinateur enregistré dans le système.</p>
|
||||||
|
<p>Vous pouvez en ajouter un en définissant un groupe par défaut <b><a routerLink="/admin/group/list">ici</a></b>.</p>
|
||||||
|
</cre-warning-alert>
|
||||||
|
|
||||||
|
<cre-table *ngIf="!tokensEmpty" class="mx-auto" [data]="tokens$ | async" [columns]="columns">
|
||||||
|
<ng-container matColumnDef="id">
|
||||||
|
<th mat-header-cell *matHeaderCellDef>Identifiant</th>
|
||||||
|
<td mat-cell *matCellDef="let token">{{token.id}}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="name">
|
||||||
|
<th mat-header-cell *matHeaderCellDef>Nom</th>
|
||||||
|
<td mat-cell *matCellDef="let token">{{token.name}}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="groupName">
|
||||||
|
<th mat-header-cell *matHeaderCellDef>Groupe</th>
|
||||||
|
<td mat-cell *matCellDef="let token">{{token.group.name}}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="state">
|
||||||
|
<th mat-header-cell *matHeaderCellDef>État</th>
|
||||||
|
<td mat-cell *matCellDef="let token">{{token.enabled ? 'Activé' : 'Désactivé'}}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="stateButton">
|
||||||
|
<th mat-header-cell *matHeaderCellDef></th>
|
||||||
|
<td mat-cell *matCellDef="let token; let i = index">
|
||||||
|
<cre-accent-button [creInteractiveCell]="i" (click)="toggle(token)">
|
||||||
|
<ng-container *ngIf="!token.enabled">Activer</ng-container>
|
||||||
|
<ng-container *ngIf="token.enabled">Désactiver</ng-container>
|
||||||
|
</cre-accent-button>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="deleteButton">
|
||||||
|
<th mat-header-cell *matHeaderCellDef></th>
|
||||||
|
<td mat-cell *matCellDef="let token; let i = index">
|
||||||
|
<cre-warn-button [creInteractiveCell]="i" (click)="showRemovePrompt(token)">
|
||||||
|
Supprimer
|
||||||
|
</cre-warn-button>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
</cre-table>
|
||||||
|
|
||||||
|
<cre-prompt-dialog title="Retirer un ordinateur" (continue)="delete()">
|
||||||
|
<cre-dialog-body *ngIf="removePromptToken">
|
||||||
|
Voulez-vous vraiment retirer l'ordinateur '{{removePromptToken.name}}' du système?<br/>
|
||||||
|
Ses utilisateurs ne seront plus connectés automatiquement.
|
||||||
|
</cre-dialog-body>
|
||||||
|
</cre-prompt-dialog>
|
|
@ -5,13 +5,23 @@ import {ListComponent} from './pages/list/list.component';
|
||||||
import {SharedModule} from "../shared/shared.module";
|
import {SharedModule} from "../shared/shared.module";
|
||||||
import {AddComponent} from './pages/add/add.component';
|
import {AddComponent} from './pages/add/add.component';
|
||||||
import {EditComponent} from './pages/edit/edit.component';
|
import {EditComponent} from './pages/edit/edit.component';
|
||||||
|
import {AccountsModule} from "../accounts/accounts.module";
|
||||||
|
import {CreActionBarModule} from "../shared/components/action-bar/action-bar.module";
|
||||||
|
import {CreButtonsModule} from "../shared/components/buttons/buttons.module";
|
||||||
|
import {CreTablesModule} from "../shared/components/tables/tables.module";
|
||||||
|
import {GroupTokensModule} from "../groupTokens/group-tokens.module";
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [ListComponent, AddComponent, EditComponent],
|
declarations: [ListComponent, AddComponent, EditComponent],
|
||||||
imports: [
|
imports: [
|
||||||
GroupRoutingModule,
|
GroupRoutingModule,
|
||||||
SharedModule
|
SharedModule,
|
||||||
]
|
AccountsModule,
|
||||||
|
CreActionBarModule,
|
||||||
|
CreButtonsModule,
|
||||||
|
CreTablesModule,
|
||||||
|
GroupTokensModule
|
||||||
|
]
|
||||||
})
|
})
|
||||||
export class GroupModule { }
|
export class GroupModule { }
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {ErrorHandlingComponent} from '../../../shared/components/subscribing.com
|
||||||
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
||||||
import {FormField} from '../../../shared/components/entity-add/entity-add.component'
|
import {FormField} from '../../../shared/components/entity-add/entity-add.component'
|
||||||
import {AppState} from '../../../shared/app-state'
|
import {AppState} from '../../../shared/app-state'
|
||||||
|
import {routes} from "../../../../routes";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-add',
|
selector: 'cre-add',
|
||||||
|
@ -60,7 +61,7 @@ export class AddComponent extends ErrorHandlingComponent {
|
||||||
if (permissionsField.valid()) {
|
if (permissionsField.valid()) {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.groupService.save(values.name, permissionsField.allEnabledPermissions),
|
this.groupService.save(values.name, permissionsField.allEnabledPermissions),
|
||||||
'/admin/group/list'
|
routes.administration.children.groups.route + '/list'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
import {Component, ViewChild} from '@angular/core'
|
import {Component, ViewChild} from '@angular/core'
|
||||||
import {ActivatedRoute, Router} from '@angular/router'
|
import {ActivatedRoute, Router} from '@angular/router'
|
||||||
import {Group} from '../../../shared/model/user'
|
import {Group} from '../../../shared/model/account.model'
|
||||||
import {GroupService} from '../../services/group.service'
|
import {GroupService} from '../../services/group.service'
|
||||||
import {Validators} from '@angular/forms'
|
import {Validators} from '@angular/forms'
|
||||||
import {currentPermissionsFieldComponent} from '../../../shared/components/permissions-field/permissions-field.component'
|
import {
|
||||||
|
currentPermissionsFieldComponent
|
||||||
|
} from '../../../shared/components/permissions-field/permissions-field.component'
|
||||||
import {AccountService} from '../../../accounts/services/account.service'
|
import {AccountService} from '../../../accounts/services/account.service'
|
||||||
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
|
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
|
||||||
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
||||||
import {FormField} from '../../../shared/components/entity-add/entity-add.component'
|
import {FormField} from '../../../shared/components/entity-add/entity-add.component'
|
||||||
import {AppState} from '../../../shared/app-state'
|
import {AppState} from '../../../shared/app-state'
|
||||||
|
import {routes} from "../../../../routes";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-edit',
|
selector: 'cre-edit',
|
||||||
|
@ -38,7 +41,7 @@ export class EditComponent extends ErrorHandlingComponent {
|
||||||
|
|
||||||
errorHandlers: ErrorHandler[] = [{
|
errorHandlers: ErrorHandler[] = [{
|
||||||
filter: error => error.type === 'notfound-group-id',
|
filter: error => error.type === 'notfound-group-id',
|
||||||
consumer: error => this.urlUtils.navigateTo('/admin/group/list')
|
consumer: _ => this.urlUtils.navigateTo(routes.administration.children.groups.route + '/list')
|
||||||
}, {
|
}, {
|
||||||
filter: error => error.type === 'exists-group-name',
|
filter: error => error.type === 'exists-group-name',
|
||||||
messageProducer: error => `Un groupe avec le nom '${error.name}' existe déjà`
|
messageProducer: error => `Un groupe avec le nom '${error.name}' existe déjà`
|
||||||
|
@ -74,7 +77,7 @@ export class EditComponent extends ErrorHandlingComponent {
|
||||||
if (permissionsField.valid()) {
|
if (permissionsField.valid()) {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.groupService.update(this.group.id, values.name, permissionsField.allEnabledPermissions),
|
this.groupService.update(this.group.id, values.name, permissionsField.allEnabledPermissions),
|
||||||
'/admin/group/list'
|
routes.administration.children.groups.route + '/list'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,7 +85,7 @@ export class EditComponent extends ErrorHandlingComponent {
|
||||||
delete() {
|
delete() {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.groupService.delete(this.group.id),
|
this.groupService.delete(this.group.id),
|
||||||
'/admin/group/list'
|
routes.administration.children.groups.route + '/list'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,49 @@
|
||||||
<cre-entity-list
|
<cre-action-bar [reverse]="true">
|
||||||
addLink="/admin/group/add"
|
<cre-action-group>
|
||||||
addPermission="EDIT_USERS"
|
<cre-accent-button *ngIf="hasEditPermission" routerLink="/admin/group/add">Ajouter</cre-accent-button>
|
||||||
[entities$]="groups$"
|
</cre-action-group>
|
||||||
[columns]="columns"
|
</cre-action-bar>
|
||||||
[buttons]="buttons"
|
|
||||||
[expandable]="true"
|
|
||||||
[rowDetailsTemplate]="groupDetailsTemplate">
|
|
||||||
</cre-entity-list>
|
|
||||||
|
|
||||||
<ng-template #groupDetailsTemplate let-group="entity">
|
<cre-warning-alert *ngIf="groupsEmpty">
|
||||||
<cre-permissions-list [group]="group"></cre-permissions-list>
|
<p>Il n'y a actuellement aucun groupe enregistré dans le système.</p>
|
||||||
</ng-template>
|
<p *ngIf="hasEditPermission">Vous pouvez en créer un <b><a routerLink="/admin/group/add">ici</a></b>.</p>
|
||||||
|
</cre-warning-alert>
|
||||||
|
|
||||||
|
<cre-table *ngIf="!groupsEmpty" class="mx-auto" [data]="groups$ | async" [columns]="columns">
|
||||||
|
<ng-container matColumnDef="name">
|
||||||
|
<th mat-header-cell *matHeaderCellDef>Nom</th>
|
||||||
|
<td mat-cell *matCellDef="let group">{{group.name}}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="permissionCount">
|
||||||
|
<th mat-header-cell *matHeaderCellDef>Nombre de permissions</th>
|
||||||
|
<td mat-cell *matCellDef="let group">{{group.permissions.length}}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="currentDefaultGroup">
|
||||||
|
<th mat-header-cell *matHeaderCellDef></th>
|
||||||
|
<td mat-cell *matCellDef="let group">
|
||||||
|
<ng-container *ngIf="isCurrentGroup(group)">Groupe par défaut</ng-container>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="setAsDefaultButton">
|
||||||
|
<th mat-header-cell *matHeaderCellDef></th>
|
||||||
|
<td mat-cell [class.disabled]="!hasAdminPermission" *matCellDef="let group; let i = index">
|
||||||
|
<cre-accent-button [creInteractiveCell]="i" (click)="setDefaultGroup(group)">
|
||||||
|
Définir par défaut
|
||||||
|
</cre-accent-button>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="editButton">
|
||||||
|
<th mat-header-cell *matHeaderCellDef></th>
|
||||||
|
<td mat-cell [class.disabled]="!hasEditPermission" *matCellDef="let group; let i = index">
|
||||||
|
<cre-accent-button [creInteractiveCell]="i" routerLink="/admin/group/edit/{{group.id}}">
|
||||||
|
Modifier
|
||||||
|
</cre-accent-button>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
</cre-table>
|
||||||
|
|
||||||
|
<cre-group-token-add (defaultGroupUpdate)="currentGroupToken = $event"></cre-group-token-add>
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
import {Component} from '@angular/core'
|
import {Component, ViewChild} from '@angular/core'
|
||||||
import {GroupService} from '../../services/group.service'
|
import {GroupService} from '../../services/group.service'
|
||||||
import {Group, Permission} from '../../../shared/model/user'
|
import {Group, GroupToken, Permission} from '../../../shared/model/account.model'
|
||||||
import {AccountService} from '../../../accounts/services/account.service'
|
import {AccountService} from '../../../accounts/services/account.service'
|
||||||
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
|
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
|
||||||
import {ActivatedRoute, Router} from '@angular/router'
|
import {ActivatedRoute, Router} from '@angular/router'
|
||||||
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
||||||
import {AlertService} from '../../../shared/service/alert.service'
|
import {AlertService} from '../../../shared/service/alert.service'
|
||||||
import {AppState} from '../../../shared/app-state'
|
import {AppState} from '../../../shared/app-state'
|
||||||
|
import {GroupTokenService} from "../../../accounts/services/group-token.service";
|
||||||
|
import {GroupTokenAdd} from "../../../groupTokens/group-tokens";
|
||||||
|
import {tap} from "rxjs/operators";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-groups',
|
selector: 'cre-groups',
|
||||||
|
@ -14,29 +17,27 @@ import {AppState} from '../../../shared/app-state'
|
||||||
styleUrls: ['./list.component.sass']
|
styleUrls: ['./list.component.sass']
|
||||||
})
|
})
|
||||||
export class ListComponent extends ErrorHandlingComponent {
|
export class ListComponent extends ErrorHandlingComponent {
|
||||||
groups$ = this.groupService.all
|
groups$ = this.groupService.all.pipe(tap(
|
||||||
defaultGroup: Group = null
|
groups => this.groupsEmpty = groups.length <= 0))
|
||||||
columns = [
|
groupsEmpty = false
|
||||||
{def: 'name', title: 'Nom', valueFn: g => g.name},
|
currentGroupToken: GroupToken | null
|
||||||
{def: 'permissionCount', title: 'Nombre de permissions', valueFn: g => g.permissions.length}
|
|
||||||
]
|
noDefaultGroupColumns = ['name', 'permissionCount', 'setAsDefaultButton', 'editButton']
|
||||||
buttons = [{
|
defaultGroupColumns = ['name', 'permissionCount', 'currentDefaultGroup', 'editButton']
|
||||||
text: 'Définir par défaut',
|
|
||||||
clickFn: group => this.setDefaultGroup(group),
|
|
||||||
disabledFn: group => this.isDefaultGroup(group)
|
|
||||||
}, {
|
|
||||||
text: 'Modifier',
|
|
||||||
linkFn: group => `/admin/group/edit/${group.id}`,
|
|
||||||
permission: Permission.EDIT_USERS
|
|
||||||
}]
|
|
||||||
|
|
||||||
errorHandlers: ErrorHandler[] = [{
|
errorHandlers: ErrorHandler[] = [{
|
||||||
filter: error => error.type === 'nodefaultgroup',
|
filter: error => error.type === 'nodefaultgroup',
|
||||||
consumer: () => this.alertService.pushWarning('Aucun groupe par défaut n\'a été défini sur cet ordinateur')
|
consumer: () => this.alertService.pushWarning('Aucun groupe par défaut n\'a été défini sur cet ordinateur')
|
||||||
|
}, {
|
||||||
|
filter: error => error.type === 'exists-grouptoken-name',
|
||||||
|
messageProducer: error => `Un ordinateur avec le nom '${error.name}' existe déjà`
|
||||||
}]
|
}]
|
||||||
|
|
||||||
|
@ViewChild(GroupTokenAdd) groupTokenDialog: GroupTokenAdd
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private groupService: GroupService,
|
private groupService: GroupService,
|
||||||
|
private groupTokenService: GroupTokenService,
|
||||||
private accountService: AccountService,
|
private accountService: AccountService,
|
||||||
private alertService: AlertService,
|
private alertService: AlertService,
|
||||||
private appState: AppState,
|
private appState: AppState,
|
||||||
|
@ -50,21 +51,28 @@ export class ListComponent extends ErrorHandlingComponent {
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.subscribe(
|
this.subscribe(
|
||||||
this.groupService.defaultGroup,
|
this.groupTokenService.current,
|
||||||
group => this.defaultGroup = group,
|
token => this.currentGroupToken = token
|
||||||
true
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
setDefaultGroup(group: Group) {
|
setDefaultGroup(group: Group) {
|
||||||
this.subscribe(
|
this.groupTokenDialog.show(group)
|
||||||
this.groupService.setDefaultGroup(group),
|
|
||||||
() => this.defaultGroup = group,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isDefaultGroup(group: Group): boolean {
|
isCurrentGroup(group: Group): boolean {
|
||||||
return this.defaultGroup && this.defaultGroup.id == group.id
|
return this.currentGroupToken && this.currentGroupToken.group.id == group.id
|
||||||
|
}
|
||||||
|
|
||||||
|
get columns(): string[] {
|
||||||
|
return this.currentGroupToken ? this.defaultGroupColumns : this.noDefaultGroupColumns
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasEditPermission(): boolean {
|
||||||
|
return this.accountService.hasPermission(Permission.EDIT_USERS)
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasAdminPermission(): boolean {
|
||||||
|
return this.accountService.hasPermission(Permission.ADMIN)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {Injectable} from '@angular/core'
|
import {Injectable} from '@angular/core'
|
||||||
import {ApiService} from '../../shared/service/api.service'
|
import {ApiService} from '../../shared/service/api.service'
|
||||||
import {Observable} from 'rxjs'
|
import {Observable} from 'rxjs'
|
||||||
import {User, Group, Permission} from '../../shared/model/user'
|
import {AccountModel, Group, Permission} from '../../shared/model/account.model'
|
||||||
import {tap} from 'rxjs/operators'
|
import {tap} from 'rxjs/operators'
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
|
@ -14,7 +14,7 @@ export class GroupService {
|
||||||
}
|
}
|
||||||
|
|
||||||
get all(): Observable<Group[]> {
|
get all(): Observable<Group[]> {
|
||||||
return this.api.get<Group[]>('/user/group')
|
return this.api.get<Group[]>('/account/group')
|
||||||
}
|
}
|
||||||
|
|
||||||
get allWithDefault(): Observable<Group[]> {
|
get allWithDefault(): Observable<Group[]> {
|
||||||
|
@ -27,40 +27,40 @@ export class GroupService {
|
||||||
}
|
}
|
||||||
|
|
||||||
getById(id: number): Observable<Group> {
|
getById(id: number): Observable<Group> {
|
||||||
return this.api.get<Group>(`/user/group/${id}`)
|
return this.api.get<Group>(`/account/group/${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
get defaultGroup(): Observable<Group> {
|
get defaultGroup(): Observable<Group> {
|
||||||
return this.api.get<Group>('/user/group/default')
|
return this.api.get<Group>('/account/group/default')
|
||||||
}
|
}
|
||||||
|
|
||||||
setDefaultGroup(value: Group): Observable<void> {
|
setDefaultGroup(value: Group): Observable<void> {
|
||||||
return this.api.post<void>(`/user/group/default/${value.id}`, {})
|
return this.api.post<void>(`/account/group/default/${value.id}`, {})
|
||||||
}
|
}
|
||||||
|
|
||||||
getUsersForGroup(id: number): Observable<User[]> {
|
getUsersForGroup(id: number): Observable<AccountModel[]> {
|
||||||
return this.api.get<User[]>(`/user/group/${id}/users`)
|
return this.api.get<AccountModel[]>(`/account/group/${id}/users`)
|
||||||
}
|
}
|
||||||
|
|
||||||
addUserToGroup(id: number, user: User): Observable<void> {
|
addUserToGroup(id: number, user: AccountModel): Observable<void> {
|
||||||
return this.api.put<void>(`/user/group/${id}/${user.id}`)
|
return this.api.put<void>(`/account/group/${id}/${user.id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
removeUserFromGroup(user: User): Observable<void> {
|
removeUserFromGroup(user: AccountModel): Observable<void> {
|
||||||
return this.api.delete<void>(`/user/group/${user.group.id}/${user.id}`)
|
return this.api.delete<void>(`/account/group/${user.group.id}/${user.id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
save(name: string, permissions: Permission[]): Observable<Group> {
|
save(name: string, permissions: Permission[]): Observable<Group> {
|
||||||
const group = {name, permissions}
|
const group = {name, permissions}
|
||||||
return this.api.post<Group>('/user/group', group)
|
return this.api.post<Group>('/account/group', group)
|
||||||
}
|
}
|
||||||
|
|
||||||
update(id: number, name: string, permissions: Permission[]): Observable<Group> {
|
update(id: number, name: string, permissions: Permission[]): Observable<Group> {
|
||||||
const group = {id, name, permissions}
|
const group = {id, name, permissions}
|
||||||
return this.api.put<Group>('/user/group', group)
|
return this.api.put<Group>('/account/group', group)
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(id: number): Observable<Group> {
|
delete(id: number): Observable<Group> {
|
||||||
return this.api.delete<Group>(`/user/group/${id}`)
|
return this.api.delete<Group>(`/account/group/${id}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {ErrorHandlingComponent} from '../../../shared/components/subscribing.com
|
||||||
import {ActivatedRoute, Router} from '@angular/router'
|
import {ActivatedRoute, Router} from '@angular/router'
|
||||||
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
||||||
import {AppState} from '../../../shared/app-state'
|
import {AppState} from '../../../shared/app-state'
|
||||||
|
import {routes} from "../../../../routes";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-add',
|
selector: 'cre-add',
|
||||||
|
@ -69,7 +70,7 @@ export class AddComponent extends ErrorHandlingComponent {
|
||||||
submit(values) {
|
submit(values) {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.materialTypeService.save(values.name, values.prefix, values.usePercentages),
|
this.materialTypeService.save(values.name, values.prefix, values.usePercentages),
|
||||||
'/catalog/materialtype/list'
|
routes.catalog.children.materialTypes.route + '/list'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {FormField} from '../../../shared/components/entity-add/entity-add.compon
|
||||||
import {Validators} from '@angular/forms'
|
import {Validators} from '@angular/forms'
|
||||||
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
||||||
import {AppState} from '../../../shared/app-state'
|
import {AppState} from '../../../shared/app-state'
|
||||||
|
import {routes} from "../../../../routes";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-edit',
|
selector: 'cre-edit',
|
||||||
|
@ -45,7 +46,7 @@ export class EditComponent extends ErrorHandlingComponent {
|
||||||
|
|
||||||
errorHandlers: ErrorHandler[] = [{
|
errorHandlers: ErrorHandler[] = [{
|
||||||
filter: error => error.type === 'notfound-materialtype-id',
|
filter: error => error.type === 'notfound-materialtype-id',
|
||||||
consumer: error => this.urlUtils.navigateTo('/catalog/materialtype/list')
|
consumer: _ => this.urlUtils.navigateTo(routes.catalog.children.materialTypes.route + '/list')
|
||||||
}, {
|
}, {
|
||||||
filter: error => error.type === 'exists-materialtype-name',
|
filter: error => error.type === 'exists-materialtype-name',
|
||||||
messageProducer: error => `Un type de produit avec le nom '${error.name}' existe déjà`
|
messageProducer: error => `Un type de produit avec le nom '${error.name}' existe déjà`
|
||||||
|
@ -84,14 +85,14 @@ export class EditComponent extends ErrorHandlingComponent {
|
||||||
submit(values) {
|
submit(values) {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.materialTypeService.update(this.materialType.id, values.name, values.prefix),
|
this.materialTypeService.update(this.materialType.id, values.name, values.prefix),
|
||||||
'/catalog/materialtype/list'
|
routes.catalog.children.materialTypes.route + '/list'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
delete() {
|
delete() {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.materialTypeService.delete(this.materialType.id),
|
this.materialTypeService.delete(this.materialType.id),
|
||||||
'/catalog/materialtype/list'
|
routes.catalog.children.materialTypes.route + '/list'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {Component} from '@angular/core'
|
import {Component} from '@angular/core'
|
||||||
import {MaterialTypeService} from '../../service/material-type.service'
|
import {MaterialTypeService} from '../../service/material-type.service'
|
||||||
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
|
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
|
||||||
import {Permission} from '../../../shared/model/user'
|
import {Permission} from '../../../shared/model/account.model'
|
||||||
import {ActivatedRoute, Router} from '@angular/router'
|
import {ActivatedRoute, Router} from '@angular/router'
|
||||||
import {ErrorService} from '../../../shared/service/error.service'
|
import {ErrorService} from '../../../shared/service/error.service'
|
||||||
import {AppState} from '../../../shared/app-state'
|
import {AppState} from '../../../shared/app-state'
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {ErrorHandlingComponent} from '../../../shared/components/subscribing.com
|
||||||
import {map} from 'rxjs/operators'
|
import {map} from 'rxjs/operators'
|
||||||
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
||||||
import {AppState} from '../../../shared/app-state'
|
import {AppState} from '../../../shared/app-state'
|
||||||
|
import {routes} from "../../../../routes";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-add',
|
selector: 'cre-add',
|
||||||
|
@ -81,7 +82,7 @@ export class AddComponent extends ErrorHandlingComponent {
|
||||||
submit(values) {
|
submit(values) {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.materialService.save(values.name, values.inventoryQuantity, values.materialType, values.simdutFile),
|
this.materialService.save(values.name, values.inventoryQuantity, values.materialType, values.simdutFile),
|
||||||
'/catalog/material/list'
|
routes.catalog.children.materials.route + '/list'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {ErrorHandlingComponent} from '../../../shared/components/subscribing.com
|
||||||
import {Material, openSimdut} from '../../../shared/model/material.model'
|
import {Material, openSimdut} from '../../../shared/model/material.model'
|
||||||
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
||||||
import {AppState} from '../../../shared/app-state'
|
import {AppState} from '../../../shared/app-state'
|
||||||
|
import {routes} from "../../../../routes";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-edit',
|
selector: 'cre-edit',
|
||||||
|
@ -69,7 +70,7 @@ export class EditComponent extends ErrorHandlingComponent {
|
||||||
|
|
||||||
errorHandlers: ErrorHandler[] = [{
|
errorHandlers: ErrorHandler[] = [{
|
||||||
filter: error => error.type === 'notfound-material-id',
|
filter: error => error.type === 'notfound-material-id',
|
||||||
consumer: error => this.urlUtils.navigateTo('/catalog/material/list')
|
consumer: _ => this.urlUtils.navigateTo(routes.catalog.children.materials.route + '/list')
|
||||||
}, {
|
}, {
|
||||||
filter: error => error.type === 'exists-material-name',
|
filter: error => error.type === 'exists-material-name',
|
||||||
messageProducer: error => `Un produit avec le nom '${error.name}' existe déjà`
|
messageProducer: error => `Un produit avec le nom '${error.name}' existe déjà`
|
||||||
|
@ -108,14 +109,14 @@ export class EditComponent extends ErrorHandlingComponent {
|
||||||
submit(values) {
|
submit(values) {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.materialService.update(this.material.id, values.name, values.inventoryQuantity, values.materialType, this.selectedSimdutFile),
|
this.materialService.update(this.material.id, values.name, values.inventoryQuantity, values.materialType, this.selectedSimdutFile),
|
||||||
'/catalog/material/list'
|
routes.catalog.children.materials.route + '/list'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
delete() {
|
delete() {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.materialService.delete(this.material.id),
|
this.materialService.delete(this.material.id),
|
||||||
'/catalog/material/list'
|
routes.catalog.children.materials.route + '/list'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {Component, ViewChild} from '@angular/core'
|
import {Component, ViewChild} from '@angular/core'
|
||||||
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
|
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
|
||||||
import {MaterialService} from '../../service/material.service'
|
import {MaterialService} from '../../service/material.service'
|
||||||
import {Permission} from '../../../shared/model/user'
|
import {Permission} from '../../../shared/model/account.model'
|
||||||
import {ActivatedRoute, Router} from '@angular/router'
|
import {ActivatedRoute, Router} from '@angular/router'
|
||||||
import {ErrorService} from '../../../shared/service/error.service'
|
import {ErrorService} from '../../../shared/service/error.service'
|
||||||
import {Material, materialFilterFieldSeparator, materialMatchesFilter, openSimdut} from '../../../shared/model/material.model'
|
import {Material, materialFilterFieldSeparator, materialMatchesFilter, openSimdut} from '../../../shared/model/material.model'
|
||||||
|
|
|
@ -15,7 +15,7 @@ import {ConfirmBoxComponent} from '../../../shared/components/confirm-box/confir
|
||||||
import {ErrorService} from '../../../shared/service/error.service'
|
import {ErrorService} from '../../../shared/service/error.service'
|
||||||
import {AlertService} from '../../../shared/service/alert.service'
|
import {AlertService} from '../../../shared/service/alert.service'
|
||||||
import {MaterialService} from '../../../material/service/material.service'
|
import {MaterialService} from '../../../material/service/material.service'
|
||||||
import {Permission} from '../../../shared/model/user'
|
import {Permission} from '../../../shared/model/account.model'
|
||||||
import {AccountService} from '../../../accounts/services/account.service'
|
import {AccountService} from '../../../accounts/services/account.service'
|
||||||
import {Material, openSimdut} from '../../../shared/model/material.model'
|
import {Material, openSimdut} from '../../../shared/model/material.model'
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import {Component, Input} from '@angular/core'
|
||||||
import {Recipe, RecipeStep, recipeStepsForGroupId, sortRecipeSteps} from '../../../shared/model/recipe.model'
|
import {Recipe, RecipeStep, recipeStepsForGroupId, sortRecipeSteps} from '../../../shared/model/recipe.model'
|
||||||
import {MatTable} from '@angular/material/table'
|
import {MatTable} from '@angular/material/table'
|
||||||
import {Observable} from 'rxjs'
|
import {Observable} from 'rxjs'
|
||||||
import {Group} from '../../../shared/model/user'
|
import {Group} from '../../../shared/model/account.model'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-step-table',
|
selector: 'cre-step-table',
|
||||||
|
|
|
@ -18,10 +18,11 @@ import {ConfirmBoxComponent} from '../shared/components/confirm-box/confirm-box.
|
||||||
import {GroupService} from '../groups/services/group.service'
|
import {GroupService} from '../groups/services/group.service'
|
||||||
import {AppState} from '../shared/app-state'
|
import {AppState} from '../shared/app-state'
|
||||||
import {AccountService} from '../accounts/services/account.service'
|
import {AccountService} from '../accounts/services/account.service'
|
||||||
import {Permission} from '../shared/model/user'
|
import {Permission} from '../shared/model/account.model'
|
||||||
import {FormControl} from '@angular/forms';
|
import {FormControl} from '@angular/forms';
|
||||||
import {map} from 'rxjs/operators';
|
import {map} from 'rxjs/operators';
|
||||||
import {CreInputEntry} from '../shared/components/inputs/inputs';
|
import {CreInputEntry} from '../shared/components/inputs/inputs';
|
||||||
|
import {routes} from "../../routes";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-recipe-explore',
|
selector: 'cre-recipe-explore',
|
||||||
|
@ -48,7 +49,7 @@ export class CreRecipeExplore extends ErrorHandlingComponent {
|
||||||
|
|
||||||
errorHandlers: ErrorHandler[] = [{
|
errorHandlers: ErrorHandler[] = [{
|
||||||
filter: error => error.type === 'notfound-recipe-id',
|
filter: error => error.type === 'notfound-recipe-id',
|
||||||
consumer: error => this.urlUtils.navigateTo('/color/list')
|
consumer: _ => this.urlUtils.navigateTo(routes.recipes.route + '/list')
|
||||||
}, {
|
}, {
|
||||||
filter: error => error.type === 'notenoughinventory-multiple',
|
filter: error => error.type === 'notenoughinventory-multiple',
|
||||||
consumer: error => this.deductErrorBody = {mix: this.deductedMixId, lowQuantities: error.lowQuantities},
|
consumer: error => this.deductErrorBody = {mix: this.deductedMixId, lowQuantities: error.lowQuantities},
|
||||||
|
@ -175,7 +176,7 @@ export class CreRecipeExplore extends ErrorHandlingComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
get loggedInUserGroupId(): number {
|
get loggedInUserGroupId(): number {
|
||||||
return this.appState.authenticatedUser.group?.id
|
return this.appState.authenticatedUser.groupId
|
||||||
}
|
}
|
||||||
|
|
||||||
get selectedGroupNote(): string {
|
get selectedGroupNote(): string {
|
||||||
|
|
|
@ -10,8 +10,9 @@ import {AppState} from '../shared/app-state'
|
||||||
import {ErrorService} from '../shared/service/error.service'
|
import {ErrorService} from '../shared/service/error.service'
|
||||||
import {ActivatedRoute, Router} from '@angular/router'
|
import {ActivatedRoute, Router} from '@angular/router'
|
||||||
import {Config} from '../shared/model/config.model'
|
import {Config} from '../shared/model/config.model'
|
||||||
import {Permission} from '../shared/model/user'
|
import {Permission} from '../shared/model/account.model'
|
||||||
import {FormControl} from '@angular/forms'
|
import {FormControl} from '@angular/forms'
|
||||||
|
import {routes} from "../../routes";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-recipe-list',
|
selector: 'cre-recipe-list',
|
||||||
|
@ -52,7 +53,7 @@ export class RecipeList extends ErrorHandlingComponent {
|
||||||
this.configService.get(Config.EMERGENCY_MODE),
|
this.configService.get(Config.EMERGENCY_MODE),
|
||||||
config => {
|
config => {
|
||||||
if (config.content == 'true') {
|
if (config.content == 'true') {
|
||||||
this.urlUtils.navigateTo('/admin/config/')
|
this.urlUtils.navigateTo(routes.administration.children.configurations.route)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -16,7 +16,7 @@ import {FormControl, Validators} from '@angular/forms'
|
||||||
import {takeUntil} from 'rxjs/operators'
|
import {takeUntil} from 'rxjs/operators'
|
||||||
import {CreComboBoxComponent, CreInputEntry} from '../../shared/components/inputs/inputs'
|
import {CreComboBoxComponent, CreInputEntry} from '../../shared/components/inputs/inputs'
|
||||||
import {AccountService} from '../../accounts/services/account.service'
|
import {AccountService} from '../../accounts/services/account.service'
|
||||||
import {Permission} from '../../shared/model/user'
|
import {Permission} from '../../shared/model/account.model'
|
||||||
import {UNIT_MILLILITER} from '../../shared/units'
|
import {UNIT_MILLILITER} from '../../shared/units'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|
|
@ -15,6 +15,7 @@ import {MaterialService} from '../../material/service/material.service'
|
||||||
import {CreForm} from '../../shared/components/forms/forms'
|
import {CreForm} from '../../shared/components/forms/forms'
|
||||||
import {MixMaterialsForm} from './materials-form'
|
import {MixMaterialsForm} from './materials-form'
|
||||||
import {MixSaveDto, MixService, MixUpdateDto} from '../services/mix.service'
|
import {MixSaveDto, MixService, MixUpdateDto} from '../services/mix.service'
|
||||||
|
import {routes} from "../../../routes";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
abstract class _BaseMixPage extends SubscribingComponent {
|
abstract class _BaseMixPage extends SubscribingComponent {
|
||||||
|
@ -74,7 +75,7 @@ export class MixAdd extends _BaseMixPage {
|
||||||
submit(dto: MixSaveDto) {
|
submit(dto: MixSaveDto) {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.mixService.saveDto(dto),
|
this.mixService.saveDto(dto),
|
||||||
`/color/edit/${this.recipe.id}`
|
`/${routes.recipes.route}/edit/${this.recipe.id}`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,14 +111,14 @@ export class MixEdit extends _BaseMixPage {
|
||||||
submit(dto: MixSaveDto) {
|
submit(dto: MixSaveDto) {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.mixService.updateDto({...dto, id: this.mix.id}),
|
this.mixService.updateDto({...dto, id: this.mix.id}),
|
||||||
`/color/edit/${this.recipe.id}`
|
`/${routes.recipes.route}/edit/${this.recipe.id}`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
delete() {
|
delete() {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.mixService.delete(this.mixId),
|
this.mixService.delete(this.mixId),
|
||||||
'/color/edit/' + this.recipe.id
|
`/${routes.recipes.route}/edit/` + this.recipe.id
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,12 +11,13 @@ import {FormControl, Validators} from '@angular/forms';
|
||||||
import {Component, EventEmitter, Input, Output, ViewChild, ViewEncapsulation} from '@angular/core';
|
import {Component, EventEmitter, Input, Output, ViewChild, ViewEncapsulation} from '@angular/core';
|
||||||
import {Recipe, recipeMixCount, RecipeStep, recipeStepCount} from '../shared/model/recipe.model';
|
import {Recipe, recipeMixCount, RecipeStep, recipeStepCount} from '../shared/model/recipe.model';
|
||||||
import {AccountService} from '../accounts/services/account.service';
|
import {AccountService} from '../accounts/services/account.service';
|
||||||
import {Permission} from '../shared/model/user';
|
import {Permission} from '../shared/model/account.model';
|
||||||
import {AlertService} from '../shared/service/alert.service';
|
import {AlertService} from '../shared/service/alert.service';
|
||||||
import {GroupService} from '../groups/services/group.service';
|
import {GroupService} from '../groups/services/group.service';
|
||||||
import {StepTableComponent} from './components/step-table/step-table.component';
|
import {StepTableComponent} from './components/step-table/step-table.component';
|
||||||
import {anyMap} from '../shared/utils/map.utils';
|
import {anyMap} from '../shared/utils/map.utils';
|
||||||
import {CreForm, ICreForm} from '../shared/components/forms/forms';
|
import {CreForm, ICreForm} from '../shared/components/forms/forms';
|
||||||
|
import {routes} from "../../routes";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'recipe-form',
|
selector: 'recipe-form',
|
||||||
|
@ -117,7 +118,7 @@ export class RecipeAdd extends ErrorHandlingComponent {
|
||||||
submit(recipe: Recipe) {
|
submit(recipe: Recipe) {
|
||||||
this.subscribe(
|
this.subscribe(
|
||||||
this.recipeService.save(recipe),
|
this.recipeService.save(recipe),
|
||||||
recipe => this.urlUtils.navigateTo(`/color/edit/${recipe.id}`)
|
recipe => this.urlUtils.navigateTo(routes.recipes.route + `/edit/${recipe.id}`)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,7 +138,7 @@ export class RecipeEdit extends ErrorHandlingComponent {
|
||||||
|
|
||||||
errorHandlers: ErrorHandler[] = [{
|
errorHandlers: ErrorHandler[] = [{
|
||||||
filter: error => error.type === 'notfound-recipe-id',
|
filter: error => error.type === 'notfound-recipe-id',
|
||||||
consumer: _ => this.urlUtils.navigateTo('/color/list')
|
consumer: _ => this.urlUtils.navigateTo(routes.recipes.route + '/list')
|
||||||
}]
|
}]
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -190,19 +191,19 @@ export class RecipeEdit extends ErrorHandlingComponent {
|
||||||
|
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.recipeService.update(recipe, steps),
|
this.recipeService.update(recipe, steps),
|
||||||
'/color/list'
|
routes.recipes.route + '/list'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
delete() {
|
delete() {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.recipeService.delete(this.recipe.id),
|
this.recipeService.delete(this.recipe.id),
|
||||||
'/color/list'
|
routes.recipes.route + '/list'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
get loggedInUserGroupId(): number {
|
get loggedInUserGroupId(): number {
|
||||||
return this.appState.authenticatedUser.group?.id
|
return this.appState.authenticatedUser.groupId
|
||||||
}
|
}
|
||||||
|
|
||||||
private stepsPositionsAreValid(steps: Map<number, RecipeStep[]>): boolean {
|
private stepsPositionsAreValid(steps: Map<number, RecipeStep[]>): boolean {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import {Injectable} from '@angular/core'
|
import {Injectable} from '@angular/core'
|
||||||
import {User} from './model/user'
|
import {LoginDto} from './model/account.model'
|
||||||
import {Subject} from 'rxjs'
|
import {Subject} from 'rxjs'
|
||||||
import {Title} from '@angular/platform-browser'
|
import {Title} from '@angular/platform-browser'
|
||||||
|
|
||||||
|
@ -7,11 +7,10 @@ import {Title} from '@angular/platform-browser'
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class AppState {
|
export class AppState {
|
||||||
private readonly KEY_AUTHENTICATED = 'authenticated'
|
private readonly KEY_AUTHENTICATED_USER = 'authenticated-user'
|
||||||
private readonly KEY_DEFAULT_GROUP_USER_AUTHENTICATED = 'default-group-user-authenticated'
|
private readonly KEY_GROUP_USER = 'authenticated-user-group'
|
||||||
private readonly KEY_LOGGED_IN_USER = 'logged-in-user'
|
|
||||||
|
|
||||||
authenticatedUser$ = new Subject<{ authenticated: boolean, authenticatedUser: User }>()
|
authenticatedUser$ = new Subject<AuthenticationEvent>()
|
||||||
serverOnline$ = new Subject<boolean>()
|
serverOnline$ = new Subject<boolean>()
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -19,67 +18,49 @@ export class AppState {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
authenticateUser(user: User) {
|
authenticateUser(user: LoginDto, isGroup: boolean) {
|
||||||
this.authenticatedUser = user
|
this.setAuthenticatedUser(user, isGroup)
|
||||||
this.isAuthenticated = true
|
|
||||||
}
|
|
||||||
|
|
||||||
authenticateGroupUser(user: User) {
|
|
||||||
this.authenticatedUser = user
|
|
||||||
this.isDefaultGroupUserAuthenticated = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resetAuthenticatedUser() {
|
resetAuthenticatedUser() {
|
||||||
this.isAuthenticated = false
|
this.removeAuthenticatedUser()
|
||||||
this.isDefaultGroupUserAuthenticated = false
|
|
||||||
this.authenticatedUser = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set isServerOnline(isOnline: boolean) {
|
set isServerOnline(isOnline: boolean) {
|
||||||
if (!isOnline) {
|
if (!isOnline) {
|
||||||
this.authenticatedUser = null
|
this.removeAuthenticatedUser()
|
||||||
}
|
}
|
||||||
this.serverOnline$.next(isOnline)
|
this.serverOnline$.next(isOnline)
|
||||||
}
|
}
|
||||||
|
|
||||||
get isAuthenticated(): boolean {
|
get isAuthenticated(): boolean {
|
||||||
return sessionStorage.getItem(this.KEY_AUTHENTICATED) === 'true'
|
return !!this.authenticatedUser
|
||||||
}
|
}
|
||||||
|
|
||||||
private set isAuthenticated(value: boolean) {
|
get authenticatedUser(): LoginDto {
|
||||||
sessionStorage.setItem(this.KEY_AUTHENTICATED, value.toString())
|
const userString = sessionStorage.getItem(this.KEY_AUTHENTICATED_USER)
|
||||||
this.authenticatedUser$.next({
|
|
||||||
authenticated: value,
|
|
||||||
authenticatedUser: this.authenticatedUser
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
get isDefaultGroupUserAuthenticated(): boolean {
|
|
||||||
return sessionStorage.getItem(this.KEY_DEFAULT_GROUP_USER_AUTHENTICATED) === 'true'
|
|
||||||
}
|
|
||||||
|
|
||||||
private set isDefaultGroupUserAuthenticated(value: boolean) {
|
|
||||||
sessionStorage.setItem(this.KEY_DEFAULT_GROUP_USER_AUTHENTICATED, value.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
get hasCredentials(): boolean {
|
|
||||||
return this.isAuthenticated || this.isDefaultGroupUserAuthenticated
|
|
||||||
}
|
|
||||||
|
|
||||||
get authenticatedUser(): User {
|
|
||||||
const userString = sessionStorage.getItem(this.KEY_LOGGED_IN_USER)
|
|
||||||
return userString ? JSON.parse(userString) : null
|
return userString ? JSON.parse(userString) : null
|
||||||
}
|
}
|
||||||
|
|
||||||
private set authenticatedUser(value: User) {
|
get isGroupUserAuthenticated(): boolean {
|
||||||
if (value === null) {
|
return sessionStorage.getItem(this.KEY_GROUP_USER) === 'true'
|
||||||
// sessionStorage.removeItem(this.KEY_LOGGED_IN_USER)
|
}
|
||||||
} else {
|
|
||||||
sessionStorage.setItem(this.KEY_LOGGED_IN_USER, JSON.stringify(value))
|
private setAuthenticatedUser(login: LoginDto, isGroup: boolean) {
|
||||||
}
|
sessionStorage.setItem(this.KEY_AUTHENTICATED_USER, JSON.stringify(login))
|
||||||
|
sessionStorage.setItem(this.KEY_GROUP_USER, JSON.stringify(isGroup))
|
||||||
this.authenticatedUser$.next({
|
this.authenticatedUser$.next({
|
||||||
authenticated: this.isAuthenticated,
|
authenticatedUser: login,
|
||||||
authenticatedUser: value
|
isGroup
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeAuthenticatedUser() {
|
||||||
|
sessionStorage.removeItem(this.KEY_AUTHENTICATED_USER)
|
||||||
|
sessionStorage.removeItem(this.KEY_GROUP_USER)
|
||||||
|
this.authenticatedUser$.next({
|
||||||
|
authenticatedUser: null,
|
||||||
|
isGroup: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,3 +68,8 @@ export class AppState {
|
||||||
this.titleService.setTitle(`CRE: ${value}`)
|
this.titleService.setTitle(`CRE: ${value}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AuthenticationEvent {
|
||||||
|
authenticatedUser: LoginDto | null
|
||||||
|
isGroup: boolean
|
||||||
|
}
|
||||||
|
|
|
@ -58,6 +58,7 @@ abstract class CreDialog<D = CreDialogData> {
|
||||||
})
|
})
|
||||||
export class CrePromptDialog extends CreDialog<CrePromptDialogData> {
|
export class CrePromptDialog extends CreDialog<CrePromptDialogData> {
|
||||||
@Input() title: string
|
@Input() title: string
|
||||||
|
@Input() continueButtonDisabled = false
|
||||||
|
|
||||||
protected get data(): CrePromptDialogData {
|
protected get data(): CrePromptDialogData {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -5,6 +5,6 @@
|
||||||
</div>
|
</div>
|
||||||
<div mat-dialog-actions>
|
<div mat-dialog-actions>
|
||||||
<cre-primary-button (click)="onCancel()">Annuler</cre-primary-button>
|
<cre-primary-button (click)="onCancel()">Annuler</cre-primary-button>
|
||||||
<cre-accent-button (click)="onContinue()">Continuer</cre-accent-button>
|
<cre-accent-button [disabled]="continueButtonDisabled" (click)="onContinue()">Continuer</cre-accent-button>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {Component, Input} from '@angular/core'
|
import {Component, Input} from '@angular/core'
|
||||||
import {Observable} from 'rxjs'
|
import {Observable} from 'rxjs'
|
||||||
import {AccountService} from '../../../accounts/services/account.service'
|
import {AccountService} from '../../../accounts/services/account.service'
|
||||||
import {Permission} from '../../model/user'
|
import {Permission} from '../../model/account.model'
|
||||||
import {animate, state, style, transition, trigger} from '@angular/animations'
|
import {animate, state, style, transition, trigger} from '@angular/animations'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {Component} from '@angular/core'
|
import {Component} from '@angular/core'
|
||||||
import {ActivatedRoute, ResolveEnd, Router} from '@angular/router'
|
import {ActivatedRoute, ResolveEnd, Router} from '@angular/router'
|
||||||
import {AppState} from '../../app-state'
|
import {AppState} from '../../app-state'
|
||||||
import {Permission} from '../../model/user'
|
import {Permission} from '../../model/account.model'
|
||||||
import {AccountService} from '../../../accounts/services/account.service'
|
import {AccountService} from '../../../accounts/services/account.service'
|
||||||
import {SubscribingComponent} from '../subscribing.component'
|
import {SubscribingComponent} from '../subscribing.component'
|
||||||
import {ErrorService} from '../../service/error.service'
|
import {ErrorService} from '../../service/error.service'
|
||||||
|
@ -35,7 +35,7 @@ export class HeaderComponent extends SubscribingComponent {
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
super.ngOnInit()
|
super.ngOnInit()
|
||||||
this.accountService.checkAuthenticationStatus()
|
this.accountService.loginAsGroupIfNotAuthenticated()
|
||||||
|
|
||||||
// Gets the current route
|
// Gets the current route
|
||||||
this.subscribe(
|
this.subscribe(
|
||||||
|
@ -58,10 +58,8 @@ export class HeaderComponent extends SubscribingComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.subscribe(
|
this.accountService.logout()
|
||||||
this.accountService.logout(),
|
console.info('Successfully logged out')
|
||||||
() => console.info('Successfully logged out')
|
|
||||||
)
|
|
||||||
|
|
||||||
super.ngOnDestroy()
|
super.ngOnDestroy()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<nav mat-tab-nav-bar backgroundColor="primary">
|
<nav mat-tab-nav-bar backgroundColor="primary">
|
||||||
<ng-container *ngFor="let link of links">
|
<ng-container *ngFor="let link of links">
|
||||||
<a
|
<a
|
||||||
*ngIf="link.enabled && hasPermission(link)"
|
*ngIf="isLinkEnabled(link)"
|
||||||
mat-tab-link
|
mat-tab-link
|
||||||
[active]="activeLink.startsWith(link.route)"
|
[active]="isLinkActive(link)"
|
||||||
(click)="activeLink = link.route">
|
(click)="activeLink = link.route">
|
||||||
{{ link.title }}
|
{{ link.title }}
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {Component, Input, OnDestroy, OnInit} from '@angular/core';
|
import {Component, Input, OnDestroy, OnInit} from '@angular/core';
|
||||||
import {User, Permission} from "../../model/user";
|
import {LoginDto, Permission} from "../../model/account.model";
|
||||||
import {AccountService} from "../../../accounts/services/account.service";
|
import {AccountService} from "../../../accounts/services/account.service";
|
||||||
import {ActivatedRoute, Router} from "@angular/router";
|
import {Router} from "@angular/router";
|
||||||
import {takeUntil} from "rxjs/operators";
|
import {takeUntil} from "rxjs/operators";
|
||||||
import {AppState} from "../../app-state";
|
import {AppState} from "../../app-state";
|
||||||
import {Subject} from "rxjs";
|
import {Subject} from "rxjs";
|
||||||
|
@ -47,14 +47,18 @@ export class NavComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
set activeLink(link: string) {
|
set activeLink(link: string) {
|
||||||
this._activeLink = link
|
this._activeLink = link
|
||||||
this.router.navigate([link])
|
this.router.navigate(['/' + link])
|
||||||
}
|
}
|
||||||
|
|
||||||
get activeLink() {
|
isLinkEnabled(link: NavLink): boolean {
|
||||||
return this._activeLink
|
return link.enabled && this.hasPermission(link)
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateEnabledLinks(user: User) {
|
isLinkActive(link: NavLink): boolean {
|
||||||
|
return this._activeLink.startsWith(link.route)
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateEnabledLinks(user: LoginDto) {
|
||||||
this.links.forEach(l => {
|
this.links.forEach(l => {
|
||||||
if (l.permission) {
|
if (l.permission) {
|
||||||
l.enabled = user && user.permissions.indexOf(l.permission) >= 0;
|
l.enabled = user && user.permissions.indexOf(l.permission) >= 0;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import {Component, Input, OnInit, ViewChild} from '@angular/core';
|
import {Component, Input, OnInit, ViewChild} from '@angular/core';
|
||||||
import {Permission, mapped_permissions} from "../../model/user";
|
import {Permission, mapped_permissions} from "../../model/account.model";
|
||||||
import {FormControl} from "@angular/forms";
|
import {FormControl} from "@angular/forms";
|
||||||
import {AccountService} from "../../../accounts/services/account.service";
|
import {AccountService} from "../../../accounts/services/account.service";
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import {Component, Input, OnInit} from '@angular/core'
|
import {Component, Input, OnInit} from '@angular/core'
|
||||||
import {User, Group, Permission, mapped_permissions} from '../../model/user'
|
import {AccountModel, Group, Permission, mapped_permissions} from '../../model/account.model'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-permissions-list',
|
selector: 'cre-permissions-list',
|
||||||
|
@ -7,7 +7,7 @@ import {User, Group, Permission, mapped_permissions} from '../../model/user'
|
||||||
styleUrls: ['./permissions-list.component.sass']
|
styleUrls: ['./permissions-list.component.sass']
|
||||||
})
|
})
|
||||||
export class PermissionsListComponent {
|
export class PermissionsListComponent {
|
||||||
@Input() user: User
|
@Input() user: AccountModel
|
||||||
@Input() group: Group
|
@Input() group: Group
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|
|
@ -35,7 +35,7 @@ export abstract class SubscribingComponent implements OnInit, OnDestroy {
|
||||||
this.hideLoadingWheel(showWheel)
|
this.hideLoadingWheel(showWheel)
|
||||||
},
|
},
|
||||||
error: err => {
|
error: err => {
|
||||||
this.errorService.handleError(err)
|
this.errorService.handleErrorResponse(err)
|
||||||
this.hideLoadingWheel(showWheel)
|
this.hideLoadingWheel(showWheel)
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
@ -61,7 +61,7 @@ export abstract class SubscribingComponent implements OnInit, OnDestroy {
|
||||||
},
|
},
|
||||||
error: err => {
|
error: err => {
|
||||||
this.hideLoadingWheel(showWheel)
|
this.hideLoadingWheel(showWheel)
|
||||||
this.errorService.handleError(err)
|
this.errorService.handleErrorResponse(err)
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +1,40 @@
|
||||||
<div class="user-menu-wrapper">
|
<div class="user-menu-wrapper">
|
||||||
<div *ngIf="user" class="user-info-wrapper d-flex flex-column" (click)="menuEnabled = !menuEnabled">
|
<div *ngIf="user" class="user-info-wrapper d-flex flex-column" (click)="showMenu = !showMenu">
|
||||||
<labeled-icon
|
<labeled-icon
|
||||||
*ngIf="authenticated"
|
|
||||||
icon="account"
|
icon="account"
|
||||||
label="{{user.firstName}} {{user.lastName}}">
|
label="{{user.fullName}}">
|
||||||
</labeled-icon>
|
</labeled-icon>
|
||||||
<div class="d-flex flex-row">
|
<div class="d-flex flex-row">
|
||||||
<labeled-icon
|
<labeled-icon
|
||||||
*ngIf="authenticated"
|
*ngIf="!groupUser"
|
||||||
icon="pound"
|
icon="pound"
|
||||||
[label]="user.id.toString()">
|
[label]="user.id.toString()">
|
||||||
</labeled-icon>
|
</labeled-icon>
|
||||||
<labeled-icon
|
<labeled-icon
|
||||||
*ngIf="userInGroup"
|
*ngIf="user.groupId"
|
||||||
class="user-info-group"
|
class="user-info-group"
|
||||||
icon="account-multiple"
|
icon="account-multiple"
|
||||||
[label]="user.group.name">
|
[label]="user.groupName">
|
||||||
</labeled-icon>
|
</labeled-icon>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
*ngIf="!authenticated && !userInGroup"
|
*ngIf="!user"
|
||||||
(click)="openLogout()">
|
(click)="openLogout()">
|
||||||
Connexion
|
Connexion
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<mat-action-list *ngIf="menuEnabled">
|
<mat-action-list *ngIf="showMenu">
|
||||||
<button
|
<button
|
||||||
*ngIf="!authenticated && userInGroup"
|
*ngIf="!user || groupUser"
|
||||||
mat-list-item
|
mat-list-item
|
||||||
class="user-menu-item-login"
|
class="user-menu-item-login"
|
||||||
(click)="openLogin()">
|
(click)="openLogin()">
|
||||||
Connexion
|
Connexion
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
*ngIf="authenticated"
|
*ngIf="user && !groupUser"
|
||||||
mat-list-item
|
mat-list-item
|
||||||
class="user-menu-item-logout"
|
class="user-menu-item-logout"
|
||||||
(click)="openLogout()">
|
(click)="openLogout()">
|
||||||
|
|
|
@ -11,7 +11,7 @@ p, labeled-icon
|
||||||
&:hover labeled-icon
|
&:hover labeled-icon
|
||||||
text-decoration: underline
|
text-decoration: underline
|
||||||
|
|
||||||
.user-info-group
|
.user-info-group:nth-child(2)
|
||||||
margin-left: 0.7rem
|
margin-left: 0.7rem
|
||||||
|
|
||||||
mat-action-list
|
mat-action-list
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import {Component, OnDestroy, OnInit} from '@angular/core'
|
import {Component, OnDestroy, OnInit} from '@angular/core'
|
||||||
import {AppState} from '../../app-state'
|
import {AppState, AuthenticationEvent} from '../../app-state'
|
||||||
import {User} from '../../model/user'
|
import {LoginDto} from '../../model/account.model'
|
||||||
import {Subject} from 'rxjs'
|
import {Subject} from 'rxjs'
|
||||||
import {takeUntil} from 'rxjs/operators'
|
import {takeUntil} from 'rxjs/operators'
|
||||||
import {UrlUtils} from '../../utils/url.utils'
|
import {UrlUtils} from '../../utils/url.utils'
|
||||||
import {ActivatedRoute, Router} from '@angular/router'
|
import {ActivatedRoute, Router} from '@angular/router'
|
||||||
|
import {routes} from "../../../../routes";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-user-menu',
|
selector: 'cre-user-menu',
|
||||||
|
@ -12,10 +13,10 @@ import {ActivatedRoute, Router} from '@angular/router'
|
||||||
styleUrls: ['./user-menu.component.sass']
|
styleUrls: ['./user-menu.component.sass']
|
||||||
})
|
})
|
||||||
export class UserMenuComponent implements OnInit, OnDestroy {
|
export class UserMenuComponent implements OnInit, OnDestroy {
|
||||||
authenticated = false
|
user: LoginDto = null
|
||||||
user: User = null
|
groupUser: boolean = false
|
||||||
userInGroup = false
|
|
||||||
menuEnabled = false
|
showMenu = false
|
||||||
|
|
||||||
private destroy$ = new Subject<boolean>()
|
private destroy$ = new Subject<boolean>()
|
||||||
private urlUtils: UrlUtils
|
private urlUtils: UrlUtils
|
||||||
|
@ -29,11 +30,12 @@ export class UserMenuComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.authenticationState(this.appState.isAuthenticated, this.appState.authenticatedUser)
|
this.setInitialAuthenticationState()
|
||||||
|
|
||||||
this.appState.authenticatedUser$
|
this.appState.authenticatedUser$
|
||||||
.pipe(takeUntil(this.destroy$))
|
.pipe(takeUntil(this.destroy$))
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: authentication => this.authenticationState(authentication.authenticated, authentication.authenticatedUser)
|
next: event => this.processAuthenticationEvent(event)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,20 +45,26 @@ export class UserMenuComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
openLogin() {
|
openLogin() {
|
||||||
this.urlUtils.navigateTo('/account/login')
|
this.urlUtils.navigateTo(routes.accounts.route + '/login')
|
||||||
this.menuEnabled = false
|
this.hideMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
openLogout() {
|
openLogout() {
|
||||||
this.urlUtils.navigateTo('/account/logout')
|
this.urlUtils.navigateTo(routes.accounts.route + '/logout')
|
||||||
this.menuEnabled = false
|
this.hideMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
private authenticationState(authenticated: boolean, user: User) {
|
private setInitialAuthenticationState() {
|
||||||
this.authenticated = authenticated
|
this.user = this.appState.authenticatedUser
|
||||||
this.user = user
|
this.groupUser = this.appState.isGroupUserAuthenticated
|
||||||
if (this.user != null) {
|
}
|
||||||
this.userInGroup = this.user.group != null
|
|
||||||
}
|
private processAuthenticationEvent(event: AuthenticationEvent) {
|
||||||
|
this.user = event.authenticatedUser
|
||||||
|
this.groupUser = event.isGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
private hideMenu() {
|
||||||
|
this.showMenu = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,12 @@
|
||||||
export class User {
|
export interface LoginDto {
|
||||||
|
id: string,
|
||||||
|
fullName: string,
|
||||||
|
permissions: string[],
|
||||||
|
groupId?: number,
|
||||||
|
groupName?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AccountModel {
|
||||||
constructor(
|
constructor(
|
||||||
public id: number,
|
public id: number,
|
||||||
public firstName: string,
|
public firstName: string,
|
||||||
|
@ -20,6 +28,13 @@ export class Group {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GroupToken {
|
||||||
|
id: string,
|
||||||
|
name: string,
|
||||||
|
enabled: boolean,
|
||||||
|
group: Group
|
||||||
|
}
|
||||||
|
|
||||||
export enum Permission {
|
export enum Permission {
|
||||||
VIEW_RECIPES = 'VIEW_RECIPES',
|
VIEW_RECIPES = 'VIEW_RECIPES',
|
||||||
VIEW_USERS = 'VIEW_USERS',
|
VIEW_USERS = 'VIEW_USERS',
|
|
@ -1,6 +1,6 @@
|
||||||
import {Material} from './material.model'
|
import {Material} from './material.model'
|
||||||
import {Company} from './company.model'
|
import {Company} from './company.model'
|
||||||
import {Group} from './user'
|
import {Group} from './account.model'
|
||||||
import {UNIT_MILLILITER} from "../units";
|
import {UNIT_MILLILITER} from "../units";
|
||||||
import {MaterialType} from "./materialtype.model";
|
import {MaterialType} from "./materialtype.model";
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import {Injectable, OnDestroy} from '@angular/core'
|
import {Injectable, OnDestroy} from '@angular/core'
|
||||||
import {HttpClient} from '@angular/common/http'
|
import {HttpClient} from '@angular/common/http'
|
||||||
import {Observable, Subject} from 'rxjs'
|
import {catchError, Observable, Subject} from 'rxjs'
|
||||||
import {environment} from '../../../../environments/environment'
|
import {environment} from '../../../../environments/environment'
|
||||||
import {AppState} from '../app-state'
|
import {AppState} from '../app-state'
|
||||||
import {Router} from '@angular/router'
|
import {Router} from '@angular/router'
|
||||||
import {map, share, takeUntil} from 'rxjs/operators'
|
import {map, share, takeUntil} from 'rxjs/operators'
|
||||||
import {valueOr} from '../utils/utils'
|
import {valueOr} from '../utils/utils'
|
||||||
import {ErrorService} from './error.service'
|
import {ErrorService} from './error.service'
|
||||||
|
import {routes} from "../../../routes";
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
|
@ -70,7 +71,7 @@ export class ApiService implements OnDestroy {
|
||||||
observe: 'response'
|
observe: 'response'
|
||||||
}
|
}
|
||||||
if (needAuthentication) {
|
if (needAuthentication) {
|
||||||
if (this.appState.hasCredentials) {
|
if (this.appState.isAuthenticated) {
|
||||||
if (httpOptions) {
|
if (httpOptions) {
|
||||||
httpOptions.withCredentials = true
|
httpOptions.withCredentials = true
|
||||||
} else {
|
} else {
|
||||||
|
@ -81,15 +82,26 @@ export class ApiService implements OnDestroy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return requestOptions.takeFullResponse
|
let request$ = requestFn(httpOptions)
|
||||||
? requestFn(httpOptions)
|
if (!requestOptions.takeFullResponse) {
|
||||||
.pipe(takeUntil(this._destroy$), share())
|
request$ = request$.pipe(map(r => r.body))
|
||||||
: requestFn(httpOptions)
|
}
|
||||||
.pipe(takeUntil(this._destroy$), map(r => r.body), share())
|
|
||||||
|
return request$.pipe(share(), takeUntil(this._destroy$),
|
||||||
|
catchError(err => this.navigateOnError(err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
private navigateOnError(error: any) {
|
||||||
|
if (error && error.status && error.status === 403) {
|
||||||
|
console.warn("Request was forbidden, redirecting to login")
|
||||||
|
this.navigateToLogin()
|
||||||
|
}
|
||||||
|
|
||||||
|
return error
|
||||||
}
|
}
|
||||||
|
|
||||||
private navigateToLogin() {
|
private navigateToLogin() {
|
||||||
this.router.navigate(['/account/login'])
|
this.router.navigate([routes.accounts.route + '/login'])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,19 +38,22 @@ export class ErrorService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleError(response: any) {
|
handleErrorResponse(response: any) {
|
||||||
let matchingModels
|
|
||||||
|
|
||||||
if (isServerOfflineError(response)) {
|
if (isServerOfflineError(response)) {
|
||||||
this.appState.isServerOnline = false
|
this.appState.isServerOnline = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const error = response.error
|
let error = response.error
|
||||||
if (!error || !error.type) {
|
if (!isHandledError(error)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.handleError({status: error.status, type: error.type, obj: error})
|
||||||
|
}
|
||||||
|
|
||||||
|
handleError(error: HandledError) {
|
||||||
|
let matchingModels
|
||||||
if (this.activeHandler) {
|
if (this.activeHandler) {
|
||||||
matchingModels = this.activeHandler.errorHandlers.filter(m => m.filter(error)) // Find error models whose filter matches the current error
|
matchingModels = this.activeHandler.errorHandlers.filter(m => m.filter(error)) // Find error models whose filter matches the current error
|
||||||
} else {
|
} else {
|
||||||
|
@ -71,10 +74,10 @@ export class ErrorService {
|
||||||
matchingModels.forEach(m => {
|
matchingModels.forEach(m => {
|
||||||
if (m.consumer || m.messageProducer) {
|
if (m.consumer || m.messageProducer) {
|
||||||
if (m.consumer) {
|
if (m.consumer) {
|
||||||
m.consumer(error)
|
m.consumer(error.obj)
|
||||||
}
|
}
|
||||||
if (m.messageProducer) {
|
if (m.messageProducer) {
|
||||||
this.alertService.pushError(m.messageProducer(error))
|
this.alertService.pushError(m.messageProducer(error.obj))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error('An error model has no consumer or message')
|
console.error('An error model has no consumer or message')
|
||||||
|
@ -106,20 +109,30 @@ export interface ErrorHandlerComponent {
|
||||||
/**
|
/**
|
||||||
* An error model define how errors matching its filter will be handled.
|
* An error model define how errors matching its filter will be handled.
|
||||||
*
|
*
|
||||||
* The consumer will consume matching errors when they occurs.
|
* The consumer will consume matching errors when they occur.
|
||||||
* The message producer returns a string that will be pushed to the alert system.
|
* The message producer returns a string that will be pushed to the alert system.
|
||||||
*
|
*
|
||||||
* To work correctly a model must define at least one handler (consumer or message producer).
|
* To work correctly a model must define at least one handler (consumer or message producer).
|
||||||
*/
|
*/
|
||||||
export class ErrorHandler {
|
export class ErrorHandler {
|
||||||
constructor(
|
constructor(
|
||||||
public filter: (error: any) => Boolean,
|
public filter: (error: HandledError) => Boolean,
|
||||||
public consumer?: (error: any) => void,
|
public consumer?: (error: any) => void,
|
||||||
public messageProducer?: (error: any) => String
|
public messageProducer?: (error: any) => String
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface HandledError {
|
||||||
|
status: number,
|
||||||
|
type: string,
|
||||||
|
obj: any // The original object, used to access data in the error
|
||||||
|
}
|
||||||
|
|
||||||
function isServerOfflineError(response: any): boolean {
|
function isServerOfflineError(response: any): boolean {
|
||||||
return response.status === 0 || response.status === 502
|
return response.status === 0 || response.status === 502
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isHandledError(error: any): error is HandledError {
|
||||||
|
return error && error.status && error.type
|
||||||
|
}
|
||||||
|
|
|
@ -6,13 +6,14 @@ import {TouchUpKitService} from '../service/touch-up-kit.service'
|
||||||
import {AccountService} from '../../accounts/services/account.service'
|
import {AccountService} from '../../accounts/services/account.service'
|
||||||
import {ErrorService} from '../../shared/service/error.service'
|
import {ErrorService} from '../../shared/service/error.service'
|
||||||
import {ActivatedRoute, Router} from '@angular/router'
|
import {ActivatedRoute, Router} from '@angular/router'
|
||||||
import {Permission} from '../../shared/model/user'
|
import {Permission} from '../../shared/model/account.model'
|
||||||
import {RecipeService} from '../../recipes/services/recipe.service'
|
import {RecipeService} from '../../recipes/services/recipe.service'
|
||||||
import {AppState} from '../../shared/app-state'
|
import {AppState} from '../../shared/app-state'
|
||||||
import {map} from 'rxjs/operators'
|
import {map} from 'rxjs/operators'
|
||||||
import {LocalDate, Period} from '@js-joda/core'
|
import {LocalDate, Period} from '@js-joda/core'
|
||||||
import {ConfigService} from '../../shared/service/config.service'
|
import {ConfigService} from '../../shared/service/config.service'
|
||||||
import {Config} from '../../shared/model/config.model'
|
import {Config} from '../../shared/model/config.model'
|
||||||
|
import {routes} from "../../../routes";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'touchupkit-banner',
|
selector: 'touchupkit-banner',
|
||||||
|
@ -138,14 +139,14 @@ export class TouchUpKitDetails extends ErrorHandlingComponent {
|
||||||
save() {
|
save() {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.touchUpKitService.update(this.touchUpKit),
|
this.touchUpKitService.update(this.touchUpKit),
|
||||||
`/misc/touch-up-kit/details/${this.touchUpKit.id}`
|
routes.misc.children.touchUpKits.route + `/details/${this.touchUpKit.id}`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
complete() {
|
complete() {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.touchUpKitService.complete(this.touchUpKit),
|
this.touchUpKitService.complete(this.touchUpKit),
|
||||||
'/misc/touch-up-kit'
|
routes.misc.children.touchUpKits.route
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,7 +174,7 @@ export class TouchUpKitAdd extends ErrorHandlingComponent {
|
||||||
submit(touchUpKit) {
|
submit(touchUpKit) {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.touchUpKitService.save(touchUpKit),
|
this.touchUpKitService.save(touchUpKit),
|
||||||
'/misc/touch-up-kit/list'
|
routes.misc.children.touchUpKits.route + '/list'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,14 +212,14 @@ export class TouchUpKitEdit extends ErrorHandlingComponent {
|
||||||
submit(touchUpKit) {
|
submit(touchUpKit) {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.touchUpKitService.update(touchUpKit),
|
this.touchUpKitService.update(touchUpKit),
|
||||||
'/misc/touch-up-kit/list'
|
routes.misc.children.touchUpKits.route + '/list'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
delete() {
|
delete() {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.touchUpKitService.delete(this.touchUpKit.id),
|
this.touchUpKitService.delete(this.touchUpKit.id),
|
||||||
'/misc/touch-up-kit/list'
|
routes.misc.children.touchUpKits.route + '/list'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
||||||
import {FormField} from '../../../shared/components/entity-add/entity-add.component'
|
import {FormField} from '../../../shared/components/entity-add/entity-add.component'
|
||||||
import {map} from 'rxjs/operators'
|
import {map} from 'rxjs/operators'
|
||||||
import {AppState} from '../../../shared/app-state'
|
import {AppState} from '../../../shared/app-state'
|
||||||
|
import {routes} from "../../../../routes";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-add',
|
selector: 'cre-add',
|
||||||
|
@ -111,7 +112,7 @@ export class AddComponent extends ErrorHandlingComponent {
|
||||||
values.groupId,
|
values.groupId,
|
||||||
permissionsField.allEnabledPermissions
|
permissionsField.allEnabledPermissions
|
||||||
),
|
),
|
||||||
'/admin/user/list'
|
routes.administration.children.users.route + '/list'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,14 @@ import {currentPermissionsFieldComponent} from '../../../shared/components/permi
|
||||||
import {UserService} from '../../services/user.service'
|
import {UserService} from '../../services/user.service'
|
||||||
import {GroupService} from '../../../groups/services/group.service'
|
import {GroupService} from '../../../groups/services/group.service'
|
||||||
import {ActivatedRoute, Router} from '@angular/router'
|
import {ActivatedRoute, Router} from '@angular/router'
|
||||||
import {User} from '../../../shared/model/user'
|
import {AccountModel} from '../../../shared/model/account.model'
|
||||||
import {AccountService} from '../../../accounts/services/account.service'
|
import {AccountService} from '../../../accounts/services/account.service'
|
||||||
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
|
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
|
||||||
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
||||||
import {FormField} from '../../../shared/components/entity-add/entity-add.component'
|
import {FormField} from '../../../shared/components/entity-add/entity-add.component'
|
||||||
import {map} from 'rxjs/operators'
|
import {map} from 'rxjs/operators'
|
||||||
import {AppState} from '../../../shared/app-state'
|
import {AppState} from '../../../shared/app-state'
|
||||||
|
import {routes} from "../../../../routes";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-edit',
|
selector: 'cre-edit',
|
||||||
|
@ -19,7 +20,7 @@ import {AppState} from '../../../shared/app-state'
|
||||||
export class EditComponent extends ErrorHandlingComponent {
|
export class EditComponent extends ErrorHandlingComponent {
|
||||||
@ViewChild('permissionsTemplateRef', {static: true}) permissionsTemplateRef
|
@ViewChild('permissionsTemplateRef', {static: true}) permissionsTemplateRef
|
||||||
|
|
||||||
user: User | null
|
user: AccountModel | null
|
||||||
formFields: FormField[] = [{
|
formFields: FormField[] = [{
|
||||||
name: 'id',
|
name: 'id',
|
||||||
label: 'Numéro d\'utilisateur',
|
label: 'Numéro d\'utilisateur',
|
||||||
|
@ -61,7 +62,7 @@ export class EditComponent extends ErrorHandlingComponent {
|
||||||
|
|
||||||
errorHandlers: ErrorHandler[] = [{
|
errorHandlers: ErrorHandler[] = [{
|
||||||
filter: error => error.type === 'notfound-user-id',
|
filter: error => error.type === 'notfound-user-id',
|
||||||
consumer: error => this.urlUtils.navigateTo('/admin/user/list')
|
consumer: _ => this.urlUtils.navigateTo(routes.administration.children.users.route + '/list')
|
||||||
}, {
|
}, {
|
||||||
filter: error => error.type === 'exists-user-fullName',
|
filter: error => error.type === 'exists-user-fullName',
|
||||||
messageProducer: error => `Un utilisateur nommé '${error.fullName}' existe déjà`
|
messageProducer: error => `Un utilisateur nommé '${error.fullName}' existe déjà`
|
||||||
|
@ -105,7 +106,7 @@ export class EditComponent extends ErrorHandlingComponent {
|
||||||
permissionsField.allEnabledPermissions
|
permissionsField.allEnabledPermissions
|
||||||
),
|
),
|
||||||
() => {
|
() => {
|
||||||
this.urlUtils.navigateTo('/admin/user/list')
|
this.urlUtils.navigateTo(routes.administration.children.users.route + '/list')
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -114,7 +115,7 @@ export class EditComponent extends ErrorHandlingComponent {
|
||||||
delete() {
|
delete() {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.userService.delete(this.user.id),
|
this.userService.delete(this.user.id),
|
||||||
'/admin/user/list'
|
routes.administration.children.users.route + '/list'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {Component} from '@angular/core'
|
import {Component} from '@angular/core'
|
||||||
import {Observable} from 'rxjs'
|
import {Observable} from 'rxjs'
|
||||||
import {UserService} from '../../services/user.service'
|
import {UserService} from '../../services/user.service'
|
||||||
import {User, Permission} from '../../../shared/model/user'
|
import {AccountModel, Permission} from '../../../shared/model/account.model'
|
||||||
import {takeUntil} from 'rxjs/operators'
|
import {takeUntil} from 'rxjs/operators'
|
||||||
import {AccountService} from '../../../accounts/services/account.service'
|
import {AccountService} from '../../../accounts/services/account.service'
|
||||||
import {animate, state, style, transition, trigger} from '@angular/animations'
|
import {animate, state, style, transition, trigger} from '@angular/animations'
|
||||||
|
@ -23,7 +23,7 @@ import {AppState} from '../../../shared/app-state'
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class ListComponent extends ErrorHandlingComponent {
|
export class ListComponent extends ErrorHandlingComponent {
|
||||||
users$: Observable<User[]>
|
users$: Observable<AccountModel[]>
|
||||||
columns = [
|
columns = [
|
||||||
{def: 'id', title: 'Numéro d\'utilisateur', valueFn: e => e.id},
|
{def: 'id', title: 'Numéro d\'utilisateur', valueFn: e => e.id},
|
||||||
{def: 'name', title: 'Nom', valueFn: e => `${e.firstName} ${e.lastName}`},
|
{def: 'name', title: 'Nom', valueFn: e => `${e.firstName} ${e.lastName}`},
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import {Component} from '@angular/core'
|
import {Component} from '@angular/core'
|
||||||
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
|
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
|
||||||
import {UserService} from '../../services/user.service'
|
import {UserService} from '../../services/user.service'
|
||||||
import {User} from '../../../shared/model/user'
|
import {AccountModel} from '../../../shared/model/account.model'
|
||||||
import {ActivatedRoute, Router} from '@angular/router'
|
import {ActivatedRoute, Router} from '@angular/router'
|
||||||
import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms'
|
import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms'
|
||||||
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
||||||
|
import {routes} from "../../../../routes";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-password-edit',
|
selector: 'cre-password-edit',
|
||||||
|
@ -12,14 +13,14 @@ import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
|
||||||
styleUrls: ['./password-edit.component.sass']
|
styleUrls: ['./password-edit.component.sass']
|
||||||
})
|
})
|
||||||
export class PasswordEditComponent extends ErrorHandlingComponent {
|
export class PasswordEditComponent extends ErrorHandlingComponent {
|
||||||
user: User | null
|
user: AccountModel | null
|
||||||
|
|
||||||
form: FormGroup
|
form: FormGroup
|
||||||
passwordControl = new FormControl(null, Validators.compose([Validators.required, Validators.minLength(8)]))
|
passwordControl = new FormControl(null, Validators.compose([Validators.required, Validators.minLength(8)]))
|
||||||
|
|
||||||
errorHandlers: ErrorHandler[] = [{
|
errorHandlers: ErrorHandler[] = [{
|
||||||
filter: error => error.type === 'notfound-user-id',
|
filter: error => error.type === 'notfound-user-id',
|
||||||
consumer: error => this.urlUtils.navigateTo('/admin/user/list')
|
consumer: _ => this.urlUtils.navigateTo(routes.administration.children.users.route + '/list')
|
||||||
}]
|
}]
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -49,7 +50,7 @@ export class PasswordEditComponent extends ErrorHandlingComponent {
|
||||||
if (this.form.valid) {
|
if (this.form.valid) {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.userService.updatePassword(this.user.id, this.passwordControl.value),
|
this.userService.updatePassword(this.user.id, this.passwordControl.value),
|
||||||
'/admin/user/list'
|
routes.administration.children.users.route + '/list'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {ApiService} from "../../shared/service/api.service";
|
import {ApiService} from "../../shared/service/api.service";
|
||||||
import {User, Permission} from "../../shared/model/user";
|
import {AccountModel, Permission} from "../../shared/model/account.model";
|
||||||
import {Observable} from "rxjs";
|
import {Observable} from "rxjs";
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
|
@ -12,29 +12,29 @@ export class UserService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
get all(): Observable<User[]> {
|
get all(): Observable<AccountModel[]> {
|
||||||
return this.api.get<User[]>('/user')
|
return this.api.get<AccountModel[]>('/account/user')
|
||||||
}
|
}
|
||||||
|
|
||||||
getById(id: number): Observable<User> {
|
getById(id: number): Observable<AccountModel> {
|
||||||
return this.api.get<User>(`/user/${id}`)
|
return this.api.get<AccountModel>(`/account/user/${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
save(id: number, firstName: string, lastName: string, password: string, group: number, permissions: Permission[]): Observable<User> {
|
save(id: number, firstName: string, lastName: string, password: string, group: number, permissions: Permission[]): Observable<AccountModel> {
|
||||||
const user = {id, firstName, lastName, password, groupId: group >= 0 ? group : null, permissions}
|
const user = {id, firstName, lastName, password, groupId: group >= 0 ? group : null, permissions}
|
||||||
return this.api.post<User>('/user', user)
|
return this.api.post<AccountModel>('/account/user', user)
|
||||||
}
|
}
|
||||||
|
|
||||||
update(id: number, firstName: string, lastName: string, group: number, permissions: Permission[]): Observable<void> {
|
update(id: number, firstName: string, lastName: string, group: number, permissions: Permission[]): Observable<void> {
|
||||||
const user = {id, firstName, lastName, groupId: group >= 0 ? group : null, permissions}
|
const user = {id, firstName, lastName, groupId: group >= 0 ? group : null, permissions}
|
||||||
return this.api.put<void>('/user', user)
|
return this.api.put<void>('/account/user', user)
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePassword(id: number, password: string): Observable<void> {
|
updatePassword(id: number, password: string): Observable<void> {
|
||||||
return this.api.put<void>(`/user/${id}/password`, password, true, {contentType: 'text/plain'})
|
return this.api.put<void>(`/account/user/${id}/password`, password, true, {contentType: 'text/plain'})
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(id: number): Observable<void> {
|
delete(id: number): Observable<void> {
|
||||||
return this.api.delete<void>(`/user/${id}`)
|
return this.api.delete<void>(`/account/user/${id}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {Component} from '@angular/core'
|
import {Component} from '@angular/core'
|
||||||
import {SubMenuComponent} from '../../modules/shared/components/sub-menu/sub-menu.component'
|
import {SubMenuComponent} from '../../modules/shared/components/sub-menu/sub-menu.component'
|
||||||
import {NavLink} from '../../modules/shared/components/nav/nav.component'
|
import {NavLink} from '../../modules/shared/components/nav/nav.component'
|
||||||
import {Permission} from '../../modules/shared/model/user'
|
import {routes} from "../../routes";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-administration',
|
selector: 'cre-administration',
|
||||||
|
@ -9,9 +9,5 @@ import {Permission} from '../../modules/shared/model/user'
|
||||||
styleUrls: ['./administration.component.sass']
|
styleUrls: ['./administration.component.sass']
|
||||||
})
|
})
|
||||||
export class AdministrationComponent extends SubMenuComponent {
|
export class AdministrationComponent extends SubMenuComponent {
|
||||||
links: NavLink[] = [
|
links: NavLink[] = Object.values(routes.administration.children)
|
||||||
{route: '/admin/user', title: 'Utilisateurs', permission: Permission.VIEW_USERS},
|
|
||||||
{route: '/admin/group', title: 'Groupes', permission: Permission.VIEW_USERS},
|
|
||||||
{route: '/admin/config', title: 'Configuration', permission: Permission.ADMIN}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {Component} from '@angular/core'
|
import {Component} from '@angular/core'
|
||||||
import {NavLink} from '../../modules/shared/components/nav/nav.component'
|
import {NavLink} from '../../modules/shared/components/nav/nav.component'
|
||||||
import {Permission} from '../../modules/shared/model/user'
|
|
||||||
import {SubMenuComponent} from '../../modules/shared/components/sub-menu/sub-menu.component'
|
import {SubMenuComponent} from '../../modules/shared/components/sub-menu/sub-menu.component'
|
||||||
|
import {routes} from "../../routes";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-inventory-page',
|
selector: 'cre-inventory-page',
|
||||||
|
@ -9,9 +9,5 @@ import {SubMenuComponent} from '../../modules/shared/components/sub-menu/sub-men
|
||||||
styleUrls: ['./catalog.component.sass']
|
styleUrls: ['./catalog.component.sass']
|
||||||
})
|
})
|
||||||
export class CatalogComponent extends SubMenuComponent {
|
export class CatalogComponent extends SubMenuComponent {
|
||||||
links: NavLink[] = [
|
links: NavLink[] = Object.values(routes.catalog.children)
|
||||||
{route: '/catalog/materialtype', title: 'Types de produit', permission: Permission.VIEW_CATALOG},
|
|
||||||
{route: '/catalog/material', title: 'Inventaire', permission: Permission.VIEW_CATALOG},
|
|
||||||
{route: '/catalog/company', title: 'Bannières', permission: Permission.VIEW_CATALOG}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {Component} from '@angular/core'
|
import {Component} from '@angular/core'
|
||||||
import {SubMenuComponent} from '../../modules/shared/components/sub-menu/sub-menu.component'
|
import {SubMenuComponent} from '../../modules/shared/components/sub-menu/sub-menu.component'
|
||||||
import {NavLink} from '../../modules/shared/components/nav/nav.component'
|
import {NavLink} from '../../modules/shared/components/nav/nav.component'
|
||||||
import {Permission} from '../../modules/shared/model/user'
|
import {routes} from "../../routes";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-others',
|
selector: 'cre-others',
|
||||||
|
@ -9,7 +9,5 @@ import {Permission} from '../../modules/shared/model/user'
|
||||||
styleUrls: ['./misc.component.sass']
|
styleUrls: ['./misc.component.sass']
|
||||||
})
|
})
|
||||||
export class MiscComponent extends SubMenuComponent{
|
export class MiscComponent extends SubMenuComponent{
|
||||||
links: NavLink[] = [
|
links: NavLink[] = Object.values(routes.misc.children)
|
||||||
{route: '/misc/touch-up-kit', title: 'Kits de retouche', permission: Permission.VIEW_TOUCH_UP_KITS}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
import {Permission} from "./modules/shared/model/account.model";
|
||||||
|
|
||||||
|
export const routes = {
|
||||||
|
recipes: {
|
||||||
|
route: 'color',
|
||||||
|
title: 'Couleurs',
|
||||||
|
requiredPermission: Permission.VIEW_RECIPES
|
||||||
|
},
|
||||||
|
catalog: {
|
||||||
|
route: 'catalog',
|
||||||
|
title: 'Catalogue',
|
||||||
|
requiredPermission: Permission.VIEW_CATALOG,
|
||||||
|
children: {
|
||||||
|
materialTypes: {
|
||||||
|
route: 'catalog/materialtype',
|
||||||
|
simpleRoute: 'materialtype',
|
||||||
|
title: 'Types de produit',
|
||||||
|
permission: Permission.VIEW_CATALOG
|
||||||
|
},
|
||||||
|
materials: {
|
||||||
|
route: 'catalog/inventory',
|
||||||
|
simpleRoute: 'inventory',
|
||||||
|
title: 'Inventaire',
|
||||||
|
permission: Permission.VIEW_CATALOG
|
||||||
|
},
|
||||||
|
companies: {
|
||||||
|
route: 'catalog/company',
|
||||||
|
simpleRoute: 'company',
|
||||||
|
title: 'Bannières',
|
||||||
|
permission: Permission.VIEW_CATALOG
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
misc: {
|
||||||
|
route: 'misc',
|
||||||
|
title: 'Autres',
|
||||||
|
enabled: true,
|
||||||
|
children: {
|
||||||
|
touchUpKits: {
|
||||||
|
route: 'misc/touch-up-kit',
|
||||||
|
simpleRoute: 'touch-up-kit',
|
||||||
|
title: 'Kits de retouche',
|
||||||
|
permission: Permission.VIEW_TOUCH_UP_KITS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
administration: {
|
||||||
|
route: 'admin',
|
||||||
|
title: 'Administration',
|
||||||
|
requiredPermission: Permission.VIEW_USERS,
|
||||||
|
children: {
|
||||||
|
users: {route: 'admin/user', simpleRoute: 'user', title: 'Utilisateurs', permission: Permission.VIEW_USERS},
|
||||||
|
groups: {route: 'admin/group', simpleRoute: 'group', title: 'Groupes', permission: Permission.VIEW_USERS},
|
||||||
|
groupTokens: {
|
||||||
|
route: 'admin/grp-tokens',
|
||||||
|
simpleRoute: 'grp-tokens',
|
||||||
|
title: 'Ordinateurs',
|
||||||
|
permission: Permission.ADMIN
|
||||||
|
}, // Not 'group-tokens' so the navbar doesn't detect 'group' as active
|
||||||
|
configurations: {
|
||||||
|
route: 'admin/config',
|
||||||
|
simpleRoute: 'config',
|
||||||
|
title: 'Configuration',
|
||||||
|
permission: Permission.ADMIN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
accounts: {
|
||||||
|
route: 'account'
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue