From 9deecb3cbda765b76e64b0da3c459dae159f16dd Mon Sep 17 00:00:00 2001 From: FyloZ Date: Fri, 3 Dec 2021 16:29:15 -0500 Subject: [PATCH 1/8] Update login page --- angular.json | 2 +- .../accounts/accounts-routing.module.ts | 20 +++++--- src/app/modules/accounts/accounts.module.ts | 23 ++++++---- src/app/modules/accounts/accounts.ts | 46 +++++++++++++++++++ src/app/modules/accounts/login.html | 27 +++++++++++ .../shared/components/forms/buttons.ts | 3 +- .../components/forms/submit-button.html | 2 +- 7 files changed, 106 insertions(+), 17 deletions(-) create mode 100644 src/app/modules/accounts/accounts.ts create mode 100644 src/app/modules/accounts/login.html diff --git a/angular.json b/angular.json index fb6d6d1..2fab785 100644 --- a/angular.json +++ b/angular.json @@ -40,7 +40,7 @@ "vendorChunk": true, "extractLicenses": false, "buildOptimizer": false, - "sourceMap": false, + "sourceMap": true, "optimization": false, "namedChunks": true }, diff --git a/src/app/modules/accounts/accounts-routing.module.ts b/src/app/modules/accounts/accounts-routing.module.ts index 843486b..006c93f 100644 --- a/src/app/modules/accounts/accounts-routing.module.ts +++ b/src/app/modules/accounts/accounts-routing.module.ts @@ -1,10 +1,18 @@ -import {NgModule} from '@angular/core'; -import {Routes, RouterModule} from '@angular/router'; +import {NgModule} from '@angular/core' +import {RouterModule, Routes} from '@angular/router' +import {LogoutComponent} from './pages/logout/logout.component' +import {Login} from './accounts' -import {LoginComponent} from './pages/login/login.component'; -import {LogoutComponent} from "./pages/logout/logout.component"; - -const routes: Routes = [{path: 'login', component: LoginComponent}, {path: 'logout', component: LogoutComponent}, {path: '', redirectTo: 'login'}]; +const routes: Routes = [{ + path: 'login', + component: Login +}, { + path: 'logout', + component: LogoutComponent +}, { + path: '', + redirectTo: 'login' +}] @NgModule({ imports: [RouterModule.forChild(routes)], diff --git a/src/app/modules/accounts/accounts.module.ts b/src/app/modules/accounts/accounts.module.ts index a935cd7..c8a05ec 100644 --- a/src/app/modules/accounts/accounts.module.ts +++ b/src/app/modules/accounts/accounts.module.ts @@ -1,18 +1,25 @@ -import {NgModule} from '@angular/core'; +import {NgModule} from '@angular/core' -import {AccountsRoutingModule} from './accounts-routing.module'; -import {LoginComponent} from './pages/login/login.component'; -import {SharedModule} from "../shared/shared.module"; -import {LogoutComponent} from './pages/logout/logout.component'; -import {CommonModule} from "@angular/common"; -import {BrowserModule} from "@angular/platform-browser"; +import {AccountsRoutingModule} from './accounts-routing.module' +import {LoginComponent} from './pages/login/login.component' +import {SharedModule} from '../shared/shared.module' +import {LogoutComponent} from './pages/logout/logout.component' +import {Login} from './accounts' +import {CreInputsModule} from '../shared/components/inputs/inputs.module' +import {CreButtonsModule} from '../shared/components/buttons/buttons.module' @NgModule({ - declarations: [LoginComponent, LogoutComponent], + declarations: [ + LoginComponent, + LogoutComponent, + Login + ], imports: [ SharedModule, AccountsRoutingModule, + CreInputsModule, + CreButtonsModule, ] }) export class AccountsModule { diff --git a/src/app/modules/accounts/accounts.ts b/src/app/modules/accounts/accounts.ts new file mode 100644 index 0000000..1629f85 --- /dev/null +++ b/src/app/modules/accounts/accounts.ts @@ -0,0 +1,46 @@ +import {Component} from '@angular/core' +import {FormBuilder, FormControl, Validators} from '@angular/forms' +import {SubscribingComponent} from '../shared/components/subscribing.component' +import {AccountService} from './services/account.service' +import {AppState} from '../shared/app-state' +import {ErrorService} from '../shared/service/error.service' +import {ActivatedRoute, Router} from '@angular/router' + +@Component({ + selector: 'cre-login', + templateUrl: 'login.html', + styles: [ + 'cre-form { min-width: 25rem; margin-top: 50vh; transform: translateY(-70%) }' + ] +}) +export class Login extends SubscribingComponent { + userIdControl = new FormControl(null, Validators.compose([Validators.required, Validators.pattern(new RegExp('^[0-9]+$'))])) + passwordControl = new FormControl(null, Validators.required) + + constructor( + private formBuilder: FormBuilder, + private accountService: AccountService, + private appState: AppState, + errorService: ErrorService, + router: Router, + activatedRoute: ActivatedRoute + ) { + super(errorService, activatedRoute, router) + this.appState.title = 'Connexion' + } + + submit() { + this.accountService.login( + this.userIdControl.value, + this.passwordControl.value, + () => this.urlUtils.navigateTo('/color') + ) + } + + get controls(): { userId: FormControl, password: FormControl } { + return { + userId: this.userIdControl, + password: this.passwordControl + } + } +} diff --git a/src/app/modules/accounts/login.html b/src/app/modules/accounts/login.html new file mode 100644 index 0000000..0521fdb --- /dev/null +++ b/src/app/modules/accounts/login.html @@ -0,0 +1,27 @@ + + Connexion au système + + + + Le numéro d'utilisateur doit être un nombre + + + + + + + + + + + diff --git a/src/app/modules/shared/components/forms/buttons.ts b/src/app/modules/shared/components/forms/buttons.ts index 0cebdc4..2c70ed1 100644 --- a/src/app/modules/shared/components/forms/buttons.ts +++ b/src/app/modules/shared/components/forms/buttons.ts @@ -1,4 +1,4 @@ -import {Component, EventEmitter, Input, Output} from '@angular/core'; +import {Component, ContentChild, EventEmitter, Input, Output} from '@angular/core' import {ICreForm} from './forms'; @Component({ @@ -8,6 +8,7 @@ import {ICreForm} from './forms'; export class CreSubmitButton { @Input() form: ICreForm @Input() valid: boolean | null + @Input() text = 'Enregistrer' @Output() submit = new EventEmitter() diff --git a/src/app/modules/shared/components/forms/submit-button.html b/src/app/modules/shared/components/forms/submit-button.html index 8e9289a..3d00a97 100644 --- a/src/app/modules/shared/components/forms/submit-button.html +++ b/src/app/modules/shared/components/forms/submit-button.html @@ -1 +1 @@ -Enregistrer +{{text}} From 019b20fd02be515d59d5b666921785e828deb74b Mon Sep 17 00:00:00 2001 From: FyloZ Date: Mon, 6 Dec 2021 23:33:41 -0500 Subject: [PATCH 2/8] #12 Handle login errors --- src/app/modules/accounts/accounts.ts | 47 ++++++++++++++----- src/app/modules/accounts/login.html | 11 +++-- .../accounts/pages/login/login.component.ts | 10 ++-- .../accounts/services/account.service.ts | 31 ++++++++++-- src/app/modules/recipes/add.html | 2 +- .../shared/components/forms/buttons.ts | 2 +- .../modules/shared/components/forms/form.html | 2 +- .../modules/shared/components/forms/forms.ts | 10 ++-- .../shared/components/inputs/inputs.ts | 5 +- 9 files changed, 87 insertions(+), 33 deletions(-) diff --git a/src/app/modules/accounts/accounts.ts b/src/app/modules/accounts/accounts.ts index 1629f85..917f130 100644 --- a/src/app/modules/accounts/accounts.ts +++ b/src/app/modules/accounts/accounts.ts @@ -1,10 +1,13 @@ -import {Component} from '@angular/core' -import {FormBuilder, FormControl, Validators} from '@angular/forms' -import {SubscribingComponent} from '../shared/components/subscribing.component' +import {Component, HostListener, ViewChild} from '@angular/core' +import {FormControl, Validators} from '@angular/forms' +import {ErrorHandlingComponent} from '../shared/components/subscribing.component' import {AccountService} from './services/account.service' import {AppState} from '../shared/app-state' -import {ErrorService} from '../shared/service/error.service' +import {ErrorHandler, ErrorService} from '../shared/service/error.service' import {ActivatedRoute, Router} from '@angular/router' +import {CreForm, ICreForm} from "../shared/components/forms/forms"; +import {take, takeUntil} from "rxjs/operators"; +import {AlertService} from "../shared/service/alert.service"; @Component({ selector: 'cre-login', @@ -13,13 +16,20 @@ import {ActivatedRoute, Router} from '@angular/router' 'cre-form { min-width: 25rem; margin-top: 50vh; transform: translateY(-70%) }' ] }) -export class Login extends SubscribingComponent { +export class Login extends ErrorHandlingComponent { + @ViewChild(CreForm) form: ICreForm + userIdControl = new FormControl(null, Validators.compose([Validators.required, Validators.pattern(new RegExp('^[0-9]+$'))])) passwordControl = new FormControl(null, Validators.required) + errorHandlers: ErrorHandler[] = [{ + filter: error => error.status === 403, + messageProducer: () => 'Les identifiants entrés sont invalides' + }] + constructor( - private formBuilder: FormBuilder, private accountService: AccountService, + private alertService: AlertService, private appState: AppState, errorService: ErrorService, router: Router, @@ -29,12 +39,27 @@ export class Login extends SubscribingComponent { this.appState.title = 'Connexion' } + // Allows to send the form by pressing Enter + @HostListener('window:keyup.enter', ['$event']) + onEnterKeyEvent() { + if (this.form.formGroup) { + this.submit() + } + } + submit() { - this.accountService.login( - this.userIdControl.value, - this.passwordControl.value, - () => this.urlUtils.navigateTo('/color') - ) + // Does not use SubscribingComponent shortcut because backend doesn't return expected error type + this.accountService.login(this.userIdControl.value, this.passwordControl.value) + .pipe(take(1), takeUntil(this.destroy$)) + .subscribe({ + error: error => this.handleLoginError(error) + }) + } + + private handleLoginError(error) { + if (error.status === 403) { + this.alertService.pushError('Les identifiants entrés sont invalides') + } } get controls(): { userId: FormControl, password: FormControl } { diff --git a/src/app/modules/accounts/login.html b/src/app/modules/accounts/login.html index 0521fdb..7ec17e8 100644 --- a/src/app/modules/accounts/login.html +++ b/src/app/modules/accounts/login.html @@ -18,10 +18,11 @@ - - + + Connexion + diff --git a/src/app/modules/accounts/pages/login/login.component.ts b/src/app/modules/accounts/pages/login/login.component.ts index 1802a7c..da31ab5 100644 --- a/src/app/modules/accounts/pages/login/login.component.ts +++ b/src/app/modules/accounts/pages/login/login.component.ts @@ -44,10 +44,12 @@ export class LoginComponent extends ErrorHandlingComponent implements OnInit { } submit() { - this.accountService.login( - this.idFormControl.value, - this.passwordFormControl.value, - () => this.router.navigate(['/color']) + this.subscribe( + this.accountService.login( + this.idFormControl.value, + this.passwordFormControl.value + ), + response => console.log(response) ) } } diff --git a/src/app/modules/accounts/services/account.service.ts b/src/app/modules/accounts/services/account.service.ts index dbf3362..22ad500 100644 --- a/src/app/modules/accounts/services/account.service.ts +++ b/src/app/modules/accounts/services/account.service.ts @@ -1,6 +1,6 @@ import {Injectable, OnDestroy} from '@angular/core' -import {Subject} from 'rxjs' -import {take, takeUntil} from 'rxjs/operators' +import {Observable, Subject} from 'rxjs' +import {take, takeUntil, tap} from 'rxjs/operators' import {AppState} from '../../shared/app-state' import {HttpClient, HttpResponse} from '@angular/common/http' import {environment} from '../../../../environments/environment' @@ -55,7 +55,32 @@ export class AccountService implements OnDestroy { } } - login(id: number, password: string, success: () => void) { + login(userId: number, password: string): Observable { + globalLoadingWheel.show() + const request$ = this.http.post(`${environment.apiUrl}/login`, {id: userId, password}, { + withCredentials: true, + observe: 'response' as 'body' + }).pipe( + take(1), + takeUntil(this.destroy$) + ) + + request$.subscribe({ + next: (response: HttpResponse) => { + globalLoadingWheel.hide() + + // TODO: Login user + }, + error: error => { + globalLoadingWheel.hide() + this.errorService.handleError(error) + } + }) + + return request$ + } + + loginOld(id: number, password: string, success: () => void) { const loginForm = {id, password} globalLoadingWheel.show() this.http.post(`${environment.apiUrl}/login`, loginForm, { diff --git a/src/app/modules/recipes/add.html b/src/app/modules/recipes/add.html index aa827e1..a4eec0d 100644 --- a/src/app/modules/recipes/add.html +++ b/src/app/modules/recipes/add.html @@ -3,7 +3,7 @@ Retour - + diff --git a/src/app/modules/shared/components/forms/buttons.ts b/src/app/modules/shared/components/forms/buttons.ts index 2c70ed1..ed1da16 100644 --- a/src/app/modules/shared/components/forms/buttons.ts +++ b/src/app/modules/shared/components/forms/buttons.ts @@ -2,7 +2,7 @@ import {Component, ContentChild, EventEmitter, Input, Output} from '@angular/cor import {ICreForm} from './forms'; @Component({ - selector: 'cre-submit-button', + selector: 'cre-form-submit-button', templateUrl: 'submit-button.html' }) export class CreSubmitButton { diff --git a/src/app/modules/shared/components/forms/form.html b/src/app/modules/shared/components/forms/form.html index 1d6e89b..4b966b8 100644 --- a/src/app/modules/shared/components/forms/form.html +++ b/src/app/modules/shared/components/forms/form.html @@ -5,7 +5,7 @@ -
+
diff --git a/src/app/modules/shared/components/forms/forms.ts b/src/app/modules/shared/components/forms/forms.ts index 7619f15..ae2f5d3 100644 --- a/src/app/modules/shared/components/forms/forms.ts +++ b/src/app/modules/shared/components/forms/forms.ts @@ -2,7 +2,7 @@ import {Component, ContentChild, Directive, Input, OnInit, ViewEncapsulation} fr import {FormBuilder, FormGroup} from '@angular/forms' export interface ICreForm { - form: FormGroup + formGroup: FormGroup valid: boolean invalid: boolean } @@ -35,7 +35,7 @@ export class CreForm implements ICreForm, OnInit { @ContentChild(CreFormActions) formActions: CreFormActions @Input() formControls: { [key: string]: any } - form: FormGroup + formGroup: FormGroup constructor( private formBuilder: FormBuilder @@ -43,7 +43,7 @@ export class CreForm implements ICreForm, OnInit { } ngOnInit(): void { - this.form = this.formBuilder.group(this.formControls) + this.formGroup = this.formBuilder.group(this.formControls) } get hasActions(): boolean { @@ -51,10 +51,10 @@ export class CreForm implements ICreForm, OnInit { } get valid(): boolean { - return this.form && this.form.valid + return this.formGroup && this.formGroup.valid } get invalid(): boolean { - return !this.form || this.form.invalid + return !this.formGroup || this.formGroup.invalid } } diff --git a/src/app/modules/shared/components/inputs/inputs.ts b/src/app/modules/shared/components/inputs/inputs.ts index cfca06f..7b53fef 100644 --- a/src/app/modules/shared/components/inputs/inputs.ts +++ b/src/app/modules/shared/components/inputs/inputs.ts @@ -1,5 +1,6 @@ import { - AfterViewInit, ChangeDetectorRef, + AfterViewInit, + ChangeDetectorRef, Component, ContentChild, Directive, @@ -16,7 +17,7 @@ import { import {AbstractControl, FormControl, ValidationErrors, ValidatorFn, Validators} from '@angular/forms' import {COMMA, ENTER} from '@angular/cdk/keycodes' import {isObservable, Observable, Subject} from 'rxjs' -import {map, startWith, takeUntil} from 'rxjs/operators' +import {map, takeUntil} from 'rxjs/operators' import {MatChipInputEvent} from '@angular/material/chips' import {MatAutocomplete, MatAutocompleteSelectedEvent} from '@angular/material/autocomplete' From 07b410d053b0efca66366f690dc755375580a93b Mon Sep 17 00:00:00 2001 From: William Date: Thu, 9 Dec 2021 18:53:16 -0500 Subject: [PATCH 3/8] Login --- package.json | 6 +- src/app/modules/accounts/accounts.ts | 21 ++-- .../accounts/services/account.service.ts | 99 +++++++++++-------- .../modules/accounts/services/jwt.service.ts | 25 +++++ src/app/modules/shared/app-state.ts | 3 + 5 files changed, 101 insertions(+), 53 deletions(-) create mode 100644 src/app/modules/accounts/services/jwt.service.ts diff --git a/package.json b/package.json index b93082c..fa2d08b 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,9 @@ "e2e": "ng e2e" }, "private": true, + "browser": { + "fs": false + }, "dependencies": { "@angular/animations": "~12.2.14", "@angular/cdk": "^12.2.13", @@ -21,10 +24,11 @@ "@angular/platform-browser": "~12.2.14", "@angular/platform-browser-dynamic": "~12.2.14", "@angular/router": "~12.2.14", + "@js-joda/core": "^4.3.1", "@mdi/angular-material": "^6.5.95", "bootstrap": "^4.5.2", "copy-webpack-plugin": "^10.0.0", - "@js-joda/core": "^4.3.1", + "jwt-decode": "^3.1.2", "material-design-icons": "^3.0.1", "ngx-material-file-input": "^2.1.1", "rxjs": "^7.4.0", diff --git a/src/app/modules/accounts/accounts.ts b/src/app/modules/accounts/accounts.ts index 917f130..2c42c84 100644 --- a/src/app/modules/accounts/accounts.ts +++ b/src/app/modules/accounts/accounts.ts @@ -48,18 +48,17 @@ export class Login extends ErrorHandlingComponent { } submit() { + this.subscribeAndNavigate( + this.accountService.login(this.userIdControl.value, this.passwordControl.value), + '/color' + ) // Does not use SubscribingComponent shortcut because backend doesn't return expected error type - this.accountService.login(this.userIdControl.value, this.passwordControl.value) - .pipe(take(1), takeUntil(this.destroy$)) - .subscribe({ - error: error => this.handleLoginError(error) - }) - } - - private handleLoginError(error) { - if (error.status === 403) { - this.alertService.pushError('Les identifiants entrés sont invalides') - } + // this.accountService.login(this.userIdControl.value, this.passwordControl.value) + // .pipe(take(1), takeUntil(this.destroy$)) + // .subscribe({ + // next: () => this.urlUtils.navigateTo('/color'), + // error: error => this.handleLoginError(error) + // }) } get controls(): { userId: FormControl, password: FormControl } { diff --git a/src/app/modules/accounts/services/account.service.ts b/src/app/modules/accounts/services/account.service.ts index 22ad500..7295c3d 100644 --- a/src/app/modules/accounts/services/account.service.ts +++ b/src/app/modules/accounts/services/account.service.ts @@ -1,14 +1,15 @@ import {Injectable, OnDestroy} from '@angular/core' import {Observable, Subject} from 'rxjs' -import {take, takeUntil, tap} from 'rxjs/operators' +import {take, takeUntil} from 'rxjs/operators' import {AppState} from '../../shared/app-state' import {HttpClient, HttpResponse} from '@angular/common/http' import {environment} from '../../../../environments/environment' import {ApiService} from '../../shared/service/api.service' -import {User, Permission} from '../../shared/model/user' +import {Permission} from '../../shared/model/user' import {ErrorService} from '../../shared/service/error.service' import {globalLoadingWheel} from '../../shared/components/loading-wheel/loading-wheel.component' import {AlertService} from '../../shared/service/alert.service' +import {JwtService} from "./jwt.service"; @Injectable({ providedIn: 'root' @@ -20,6 +21,7 @@ export class AccountService implements OnDestroy { private http: HttpClient, private api: ApiService, private appState: AppState, + private jwtService: JwtService, private errorService: ErrorService, private alertService: AlertService ) { @@ -37,47 +39,61 @@ export class AccountService implements OnDestroy { checkAuthenticationStatus() { if (!this.appState.authenticatedUser) { // Try to get current default group user - this.http.get(`${environment.apiUrl}/user/current`, {withCredentials: true}) - .pipe( - take(1), - takeUntil(this.destroy$), - ).subscribe( - { - next: user => this.appState.authenticatedUser = user, - error: err => { - if (err.status === 404 || err.status === 403) { - console.warn('No default user is defined on this computer') - } else { - this.errorService.handleError(err) - } - } - }) + // this.http.get(`${environment.apiUrl}/user/current`, {withCredentials: true}) + // .pipe( + // take(1), + // takeUntil(this.destroy$), + // ).subscribe( + // { + // next: user => this.appState.authenticatedUser = user, + // error: err => { + // if (err.status === 404 || err.status === 403) { + // console.warn('No default user is defined on this computer') + // } else { + // this.errorService.handleError(err) + // } + // } + // }) } } login(userId: number, password: string): Observable { - globalLoadingWheel.show() - const request$ = this.http.post(`${environment.apiUrl}/login`, {id: userId, password}, { + const subject = new Subject() + + this.http.post(`${environment.apiUrl}/login`, {id: userId, password}, { withCredentials: true, observe: 'response' as 'body' }).pipe( take(1), takeUntil(this.destroy$) - ) + ).subscribe({ + next: (response: HttpResponse) => { + this.loginUser(response) - request$.subscribe({ - next: (response: HttpResponse) => { - globalLoadingWheel.hide() - - // TODO: Login user + subject.next() + subject.complete() }, error: error => { - globalLoadingWheel.hide() - this.errorService.handleError(error) + if (error.status === 403) { + this.alertService.pushError('Les identifiants entrés sont invalides') + } else { + this.errorService.handleError(error) + } + + subject.next() + subject.complete() } }) - return request$ + return subject + } + + private loginUser(response: HttpResponse) { + const authorization = response.headers.get("Authorization") + const jwt = this.jwtService.parseJwt(authorization) + + this.appState.authenticatedUser = jwt.user + this.appState.authenticationExpiration = jwt.exp } loginOld(id: number, password: string, success: () => void) { @@ -129,18 +145,19 @@ export class AccountService implements OnDestroy { } private setLoggedInUserFromApi() { - this.api.get('/user/current', true) - .pipe( - take(1), - takeUntil(this.destroy$) - ) - .subscribe({ - next: user => { - this.appState.authenticatedUser = user - // At this point the loading wheel should be visible - globalLoadingWheel.hide() - }, - error: err => this.errorService.handleError(err) - }) + // this.api.get('/user/current', true) + // .pipe( + // take(1), + // takeUntil(this.destroy$) + // ) + // .subscribe({ + // next: user => { + // this.appState.authenticatedUser = user + // At this point the loading wheel should be visible + // globalLoadingWheel.hide() + // }, + // error: err => this.errorService.handleError(err) + // }) + console.warn("REMOVE THIS") } } diff --git a/src/app/modules/accounts/services/jwt.service.ts b/src/app/modules/accounts/services/jwt.service.ts new file mode 100644 index 0000000..d2a88f5 --- /dev/null +++ b/src/app/modules/accounts/services/jwt.service.ts @@ -0,0 +1,25 @@ +import {Injectable} from "@angular/core"; +import {User} from "../../shared/model/user"; +import jwtDecode from "jwt-decode"; +import {parseJson} from "@angular/cli/utilities/json-file"; + +@Injectable({ + providedIn: 'root' +}) +export class JwtService { + parseJwt(jwt: string): CreJwt { + const decoded = jwtDecode(jwt) as any + + return { + sub: decoded.sub, + exp: decoded.exp, + user: parseJson(decoded.user) + } + } +} + +interface CreJwt { + readonly sub: string + readonly exp: number, + readonly user: User +} diff --git a/src/app/modules/shared/app-state.ts b/src/app/modules/shared/app-state.ts index f850b3e..1504d28 100644 --- a/src/app/modules/shared/app-state.ts +++ b/src/app/modules/shared/app-state.ts @@ -2,6 +2,7 @@ import {Injectable} from '@angular/core' import {User} from './model/user' import {Subject} from 'rxjs' import {Title} from '@angular/platform-browser' +import jwtDecode from "jwt-decode"; @Injectable({ providedIn: 'root' @@ -59,8 +60,10 @@ export class AppState { set authenticatedUser(value: User) { if (value === null) { + console.log(1) sessionStorage.removeItem(this.KEY_LOGGED_IN_USER) } else { + console.log(2) sessionStorage.setItem(this.KEY_LOGGED_IN_USER, JSON.stringify(value)) } this.authenticatedUser$.next({ From cb7f38b46bfcd6d2a8b9e38fdcfb4707e8a64745 Mon Sep 17 00:00:00 2001 From: William Date: Tue, 14 Dec 2021 19:28:50 -0500 Subject: [PATCH 4/8] Improve AppState --- src/app/modules/accounts/accounts.ts | 4 +-- .../accounts/services/account.service.ts | 33 +------------------ .../modules/accounts/services/jwt.service.ts | 8 +---- src/app/modules/shared/app-state.ts | 23 +++++++++---- src/app/modules/shared/service/api.service.ts | 6 ++-- 5 files changed, 24 insertions(+), 50 deletions(-) diff --git a/src/app/modules/accounts/accounts.ts b/src/app/modules/accounts/accounts.ts index 2c42c84..0fcc07e 100644 --- a/src/app/modules/accounts/accounts.ts +++ b/src/app/modules/accounts/accounts.ts @@ -48,9 +48,9 @@ export class Login extends ErrorHandlingComponent { } submit() { - this.subscribeAndNavigate( + this.subscribe( this.accountService.login(this.userIdControl.value, this.passwordControl.value), - '/color' + () => {} ) // Does not use SubscribingComponent shortcut because backend doesn't return expected error type // this.accountService.login(this.userIdControl.value, this.passwordControl.value) diff --git a/src/app/modules/accounts/services/account.service.ts b/src/app/modules/accounts/services/account.service.ts index 7295c3d..9cee84e 100644 --- a/src/app/modules/accounts/services/account.service.ts +++ b/src/app/modules/accounts/services/account.service.ts @@ -7,7 +7,6 @@ import {environment} from '../../../../environments/environment' import {ApiService} from '../../shared/service/api.service' import {Permission} from '../../shared/model/user' import {ErrorService} from '../../shared/service/error.service' -import {globalLoadingWheel} from '../../shared/components/loading-wheel/loading-wheel.component' import {AlertService} from '../../shared/service/alert.service' import {JwtService} from "./jwt.service"; @@ -92,37 +91,7 @@ export class AccountService implements OnDestroy { const authorization = response.headers.get("Authorization") const jwt = this.jwtService.parseJwt(authorization) - this.appState.authenticatedUser = jwt.user - this.appState.authenticationExpiration = jwt.exp - } - - loginOld(id: number, password: string, success: () => void) { - const loginForm = {id, password} - globalLoadingWheel.show() - this.http.post(`${environment.apiUrl}/login`, loginForm, { - withCredentials: true, - observe: 'response' as 'body' - }) - .pipe( - take(1), - takeUntil(this.destroy$) - ) - .subscribe({ - next: (response: HttpResponse) => { - this.appState.authenticationExpiration = parseInt(response.headers.get('X-Authentication-Expiration')) - this.appState.isAuthenticated = true - this.setLoggedInUserFromApi() - success() - }, - error: err => { - globalLoadingWheel.hide() - if (err.status === 401 || err.status === 403) { - this.alertService.pushError('Les identifiants entrés sont invalides') - } else { - this.errorService.handleError(err) - } - } - }) + this.appState.authenticateUser(jwt) } logout(success: () => void) { diff --git a/src/app/modules/accounts/services/jwt.service.ts b/src/app/modules/accounts/services/jwt.service.ts index d2a88f5..6121290 100644 --- a/src/app/modules/accounts/services/jwt.service.ts +++ b/src/app/modules/accounts/services/jwt.service.ts @@ -1,7 +1,7 @@ import {Injectable} from "@angular/core"; -import {User} from "../../shared/model/user"; import jwtDecode from "jwt-decode"; import {parseJson} from "@angular/cli/utilities/json-file"; +import {CreJwt} from "../../shared/app-state"; @Injectable({ providedIn: 'root' @@ -17,9 +17,3 @@ export class JwtService { } } } - -interface CreJwt { - readonly sub: string - readonly exp: number, - readonly user: User -} diff --git a/src/app/modules/shared/app-state.ts b/src/app/modules/shared/app-state.ts index 1504d28..3ed0e23 100644 --- a/src/app/modules/shared/app-state.ts +++ b/src/app/modules/shared/app-state.ts @@ -20,6 +20,12 @@ export class AppState { ) { } + authenticateUser(jwt: CreJwt) { + this.authenticatedUser = jwt.user + this.authenticationExpiration = jwt.exp + this.isAuthenticated = true + } + resetAuthenticatedUser() { this.isAuthenticated = false this.authenticationExpiration = -1 @@ -37,7 +43,7 @@ export class AppState { return sessionStorage.getItem(this.KEY_AUTHENTICATED) === 'true' } - set isAuthenticated(value: boolean) { + private set isAuthenticated(value: boolean) { sessionStorage.setItem(this.KEY_AUTHENTICATED, value.toString()) this.authenticatedUser$.next({ authenticated: value, @@ -49,7 +55,8 @@ export class AppState { return parseInt(sessionStorage.getItem(this.KEY_AUTHENTICATION_EXPIRATION)) } - set authenticationExpiration(value: number) { + private set authenticationExpiration(value: number) { + console.error(value) sessionStorage.setItem(this.KEY_AUTHENTICATION_EXPIRATION, value.toString()) } @@ -58,12 +65,10 @@ export class AppState { return userString ? JSON.parse(userString) : null } - set authenticatedUser(value: User) { + private set authenticatedUser(value: User) { if (value === null) { - console.log(1) - sessionStorage.removeItem(this.KEY_LOGGED_IN_USER) + // sessionStorage.removeItem(this.KEY_LOGGED_IN_USER) } else { - console.log(2) sessionStorage.setItem(this.KEY_LOGGED_IN_USER, JSON.stringify(value)) } this.authenticatedUser$.next({ @@ -76,3 +81,9 @@ export class AppState { this.titleService.setTitle(`CRE: ${value}`) } } + +export interface CreJwt { + readonly sub: string + readonly exp: number, + readonly user: User +} diff --git a/src/app/modules/shared/service/api.service.ts b/src/app/modules/shared/service/api.service.ts index 7c39b28..1e4c269 100644 --- a/src/app/modules/shared/service/api.service.ts +++ b/src/app/modules/shared/service/api.service.ts @@ -4,10 +4,9 @@ import {Observable, Subject} from 'rxjs' import {environment} from '../../../../environments/environment' import {AppState} from '../app-state' import {Router} from '@angular/router' -import {map, share, takeUntil, tap} from 'rxjs/operators' +import {map, share, takeUntil} from 'rxjs/operators' import {valueOr} from '../utils/utils' import {ErrorService} from './error.service' -import {globalLoadingWheel} from '../components/loading-wheel/loading-wheel.component' @Injectable({ providedIn: 'root' @@ -78,7 +77,7 @@ export class ApiService implements OnDestroy { console.error('httpOptions need to be specified to use credentials in HTTP methods.') } } else { - this.appState.resetAuthenticatedUser() + // this.appState.resetAuthenticatedUser() this.navigateToLogin() } } @@ -91,6 +90,7 @@ export class ApiService implements OnDestroy { } private checkAuthenticated(): boolean { + console.log(Date.now() / 1000, this.appState.authenticationExpiration) return (this.appState.isAuthenticated && Date.now() <= this.appState.authenticationExpiration) || (this.appState.authenticatedUser && this.appState.authenticatedUser.group != null) } From be592a22f520786a5fa606e2c99120ac2cd587ae Mon Sep 17 00:00:00 2001 From: FyloZ Date: Tue, 14 Dec 2021 23:38:32 -0500 Subject: [PATCH 5/8] Fix login and group user login. Hides add buttons when the user doesn't have the required permission. --- package.json | 2 +- src/app/modules/accounts/accounts.ts | 11 +-- .../accounts/pages/login/login.component.ts | 2 +- .../accounts/pages/logout/logout.component.ts | 27 ++++-- .../accounts/services/account.service.ts | 95 +++++++++---------- .../modules/accounts/services/jwt.service.ts | 12 +-- .../company/pages/list/list.component.html | 2 +- .../pages/list/list.component.html | 2 +- src/app/modules/recipes/recipes.ts | 2 +- src/app/modules/shared/app-state.ts | 34 +++---- .../components/header/header.component.ts | 9 +- src/app/modules/shared/service/api.service.ts | 9 +- src/app/modules/touch-up-kit/pages/list.html | 2 +- 13 files changed, 95 insertions(+), 114 deletions(-) diff --git a/package.json b/package.json index fa2d08b..572b917 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "scripts": { "ng": "ng", - "start": "ng serve --proxy-config proxy.conf.json", + "start": "ng serve --host 0.0.0.0 --proxy-config proxy.conf.json", "build": "ng build", "test": "ng test", "lint": "ng lint", diff --git a/src/app/modules/accounts/accounts.ts b/src/app/modules/accounts/accounts.ts index 0fcc07e..10f850b 100644 --- a/src/app/modules/accounts/accounts.ts +++ b/src/app/modules/accounts/accounts.ts @@ -48,17 +48,10 @@ export class Login extends ErrorHandlingComponent { } submit() { - this.subscribe( + this.subscribeAndNavigate( this.accountService.login(this.userIdControl.value, this.passwordControl.value), - () => {} + '/color/list' ) - // Does not use SubscribingComponent shortcut because backend doesn't return expected error type - // this.accountService.login(this.userIdControl.value, this.passwordControl.value) - // .pipe(take(1), takeUntil(this.destroy$)) - // .subscribe({ - // next: () => this.urlUtils.navigateTo('/color'), - // error: error => this.handleLoginError(error) - // }) } get controls(): { userId: FormControl, password: FormControl } { diff --git a/src/app/modules/accounts/pages/login/login.component.ts b/src/app/modules/accounts/pages/login/login.component.ts index da31ab5..919bed0 100644 --- a/src/app/modules/accounts/pages/login/login.component.ts +++ b/src/app/modules/accounts/pages/login/login.component.ts @@ -31,7 +31,7 @@ export class LoginComponent extends ErrorHandlingComponent implements OnInit { ngOnInit(): void { this.errorService.activeErrorHandler = this - if (this.accountService.isLoggedIn()) { + if (this.appState.isAuthenticated) { this.router.navigate(['/color']) } diff --git a/src/app/modules/accounts/pages/logout/logout.component.ts b/src/app/modules/accounts/pages/logout/logout.component.ts index 8b180bd..a1433c1 100644 --- a/src/app/modules/accounts/pages/logout/logout.component.ts +++ b/src/app/modules/accounts/pages/logout/logout.component.ts @@ -1,28 +1,35 @@ -import {Component, OnInit} from '@angular/core'; +import {Component} from '@angular/core'; import {AccountService} from "../../services/account.service"; -import {Router} from "@angular/router"; +import {ActivatedRoute, Router} from "@angular/router"; +import {AppState} from "../../../shared/app-state"; +import {SubscribingComponent} from "../../../shared/components/subscribing.component"; +import {ErrorService} from "../../../shared/service/error.service"; @Component({ selector: 'cre-logout', templateUrl: './logout.component.html', styleUrls: ['./logout.component.sass'] }) -export class LogoutComponent implements OnInit { +export class LogoutComponent extends SubscribingComponent { constructor( private accountService: AccountService, - private router: Router + private appState: AppState, + errorService: ErrorService, + router: Router, + activatedRoute: ActivatedRoute ) { + super(errorService, activatedRoute, router) } ngOnInit(): void { - if (!this.accountService.isLoggedIn()) { - this.router.navigate(['/account/login']) + if (!this.appState.isAuthenticated) { + this.urlUtils.navigateTo('/account/login') } - this.accountService.logout(() => { - this.router.navigate(['/account/login']) - }) + this.subscribeAndNavigate( + this.accountService.logout(), + '/account/login' + ) } - } diff --git a/src/app/modules/accounts/services/account.service.ts b/src/app/modules/accounts/services/account.service.ts index 9cee84e..066973a 100644 --- a/src/app/modules/accounts/services/account.service.ts +++ b/src/app/modules/accounts/services/account.service.ts @@ -5,7 +5,7 @@ import {AppState} from '../../shared/app-state' import {HttpClient, HttpResponse} from '@angular/common/http' import {environment} from '../../../../environments/environment' import {ApiService} from '../../shared/service/api.service' -import {Permission} from '../../shared/model/user' +import {Permission, User} from '../../shared/model/user' import {ErrorService} from '../../shared/service/error.service' import {AlertService} from '../../shared/service/alert.service' import {JwtService} from "./jwt.service"; @@ -31,28 +31,24 @@ export class AccountService implements OnDestroy { this.destroy$.complete() } - isLoggedIn(): boolean { - return this.appState.isAuthenticated - } - checkAuthenticationStatus() { - if (!this.appState.authenticatedUser) { + if (!this.appState.isAuthenticated) { // Try to get current default group user - // this.http.get(`${environment.apiUrl}/user/current`, {withCredentials: true}) - // .pipe( - // take(1), - // takeUntil(this.destroy$), - // ).subscribe( - // { - // next: user => this.appState.authenticatedUser = user, - // error: err => { - // if (err.status === 404 || err.status === 403) { - // console.warn('No default user is defined on this computer') - // } else { - // this.errorService.handleError(err) - // } - // } - // }) + this.http.get(`${environment.apiUrl}/user/group/currentuser`, {withCredentials: true}) + .pipe( + take(1), + takeUntil(this.destroy$), + ).subscribe( + { + next: user => this.appState.authenticateGroupUser(user), + error: err => { + if (err.status === 404 || err.status === 403) { + console.warn('No default user is defined on this computer') + } else { + this.errorService.handleError(err) + } + } + }) } } @@ -89,44 +85,41 @@ export class AccountService implements OnDestroy { private loginUser(response: HttpResponse) { const authorization = response.headers.get("Authorization") - const jwt = this.jwtService.parseJwt(authorization) + const user = this.jwtService.parseUser(authorization) - this.appState.authenticateUser(jwt) + this.appState.authenticateUser(user) } - logout(success: () => void) { - this.api.get('/logout', true).pipe( + logout(): Observable { + const subject = new Subject() + + this.api.get('/logout').pipe( take(1), takeUntil(this.destroy$) - ) - .subscribe({ - next: () => { - this.appState.resetAuthenticatedUser() - this.checkAuthenticationStatus() - success() - }, - error: err => this.errorService.handleError(err) - }) + ).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.checkAuthenticationStatus() } hasPermission(permission: Permission): boolean { return this.appState.authenticatedUser && this.appState.authenticatedUser.permissions.indexOf(permission) >= 0 } - - private setLoggedInUserFromApi() { - // this.api.get('/user/current', true) - // .pipe( - // take(1), - // takeUntil(this.destroy$) - // ) - // .subscribe({ - // next: user => { - // this.appState.authenticatedUser = user - // At this point the loading wheel should be visible - // globalLoadingWheel.hide() - // }, - // error: err => this.errorService.handleError(err) - // }) - console.warn("REMOVE THIS") - } } diff --git a/src/app/modules/accounts/services/jwt.service.ts b/src/app/modules/accounts/services/jwt.service.ts index 6121290..6f67366 100644 --- a/src/app/modules/accounts/services/jwt.service.ts +++ b/src/app/modules/accounts/services/jwt.service.ts @@ -1,19 +1,13 @@ import {Injectable} from "@angular/core"; import jwtDecode from "jwt-decode"; -import {parseJson} from "@angular/cli/utilities/json-file"; -import {CreJwt} from "../../shared/app-state"; +import { User } from "../../shared/model/user"; @Injectable({ providedIn: 'root' }) export class JwtService { - parseJwt(jwt: string): CreJwt { + parseUser(jwt: string): User { const decoded = jwtDecode(jwt) as any - - return { - sub: decoded.sub, - exp: decoded.exp, - user: parseJson(decoded.user) - } + return JSON.parse(decoded.user) } } diff --git a/src/app/modules/company/pages/list/list.component.html b/src/app/modules/company/pages/list/list.component.html index 1fc8be5..944d7d2 100644 --- a/src/app/modules/company/pages/list/list.component.html +++ b/src/app/modules/company/pages/list/list.component.html @@ -1,6 +1,6 @@ - Ajouter + Ajouter diff --git a/src/app/modules/material-type/pages/list/list.component.html b/src/app/modules/material-type/pages/list/list.component.html index bf32816..6555e6a 100644 --- a/src/app/modules/material-type/pages/list/list.component.html +++ b/src/app/modules/material-type/pages/list/list.component.html @@ -1,6 +1,6 @@ - Ajouter + Ajouter diff --git a/src/app/modules/recipes/recipes.ts b/src/app/modules/recipes/recipes.ts index bdc619e..e1b6410 100644 --- a/src/app/modules/recipes/recipes.ts +++ b/src/app/modules/recipes/recipes.ts @@ -46,7 +46,7 @@ export class RecipeForm extends SubscribingComponent { } ngOnInit() { - super.ngOnInit(); + super.ngOnInit() this.fetchCompanies() diff --git a/src/app/modules/shared/app-state.ts b/src/app/modules/shared/app-state.ts index 3ed0e23..5b1c93e 100644 --- a/src/app/modules/shared/app-state.ts +++ b/src/app/modules/shared/app-state.ts @@ -2,14 +2,13 @@ import {Injectable} from '@angular/core' import {User} from './model/user' import {Subject} from 'rxjs' import {Title} from '@angular/platform-browser' -import jwtDecode from "jwt-decode"; @Injectable({ providedIn: 'root' }) export class AppState { private readonly KEY_AUTHENTICATED = 'authenticated' - private readonly KEY_AUTHENTICATION_EXPIRATION = 'authentication-expiration' + private readonly KEY_DEFAULT_GROUP_USER_AUTHENTICATED = 'default-group-user-authenticated' private readonly KEY_LOGGED_IN_USER = 'logged-in-user' authenticatedUser$ = new Subject<{ authenticated: boolean, authenticatedUser: User }>() @@ -20,15 +19,19 @@ export class AppState { ) { } - authenticateUser(jwt: CreJwt) { - this.authenticatedUser = jwt.user - this.authenticationExpiration = jwt.exp + authenticateUser(user: User) { + this.authenticatedUser = user this.isAuthenticated = true } + authenticateGroupUser(user: User) { + this.authenticatedUser = user + this.isDefaultGroupUserAuthenticated = true + } + resetAuthenticatedUser() { this.isAuthenticated = false - this.authenticationExpiration = -1 + this.isDefaultGroupUserAuthenticated = false this.authenticatedUser = null } @@ -51,13 +54,16 @@ export class AppState { }) } - get authenticationExpiration(): number { - return parseInt(sessionStorage.getItem(this.KEY_AUTHENTICATION_EXPIRATION)) + get isDefaultGroupUserAuthenticated(): boolean { + return sessionStorage.getItem(this.KEY_DEFAULT_GROUP_USER_AUTHENTICATED) === 'true' } - private set authenticationExpiration(value: number) { - console.error(value) - sessionStorage.setItem(this.KEY_AUTHENTICATION_EXPIRATION, value.toString()) + 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 { @@ -81,9 +87,3 @@ export class AppState { this.titleService.setTitle(`CRE: ${value}`) } } - -export interface CreJwt { - readonly sub: string - readonly exp: number, - readonly user: User -} diff --git a/src/app/modules/shared/components/header/header.component.ts b/src/app/modules/shared/components/header/header.component.ts index 6d113fd..abe4a17 100644 --- a/src/app/modules/shared/components/header/header.component.ts +++ b/src/app/modules/shared/components/header/header.component.ts @@ -58,9 +58,10 @@ export class HeaderComponent extends SubscribingComponent { } ngOnDestroy(): void { - this.accountService.logout(() => { - console.log('Successfully logged out') - }) + this.subscribe( + this.accountService.logout(), + () => console.info('Successfully logged out') + ) super.ngOnDestroy() } @@ -71,7 +72,7 @@ export class HeaderComponent extends SubscribingComponent { set activeLink(link: string) { this._activeLink = link - this.router.navigate([link]) + this.urlUtils.navigateTo(link) } get activeLink() { diff --git a/src/app/modules/shared/service/api.service.ts b/src/app/modules/shared/service/api.service.ts index 1e4c269..462531b 100644 --- a/src/app/modules/shared/service/api.service.ts +++ b/src/app/modules/shared/service/api.service.ts @@ -70,14 +70,13 @@ export class ApiService implements OnDestroy { observe: 'response' } if (needAuthentication) { - if (this.checkAuthenticated()) { + if (this.appState.hasCredentials) { if (httpOptions) { httpOptions.withCredentials = true } else { console.error('httpOptions need to be specified to use credentials in HTTP methods.') } } else { - // this.appState.resetAuthenticatedUser() this.navigateToLogin() } } @@ -89,12 +88,6 @@ export class ApiService implements OnDestroy { .pipe(takeUntil(this._destroy$), map(r => r.body), share()) } - private checkAuthenticated(): boolean { - console.log(Date.now() / 1000, this.appState.authenticationExpiration) - return (this.appState.isAuthenticated && Date.now() <= this.appState.authenticationExpiration) || - (this.appState.authenticatedUser && this.appState.authenticatedUser.group != null) - } - private navigateToLogin() { this.router.navigate(['/account/login']) } diff --git a/src/app/modules/touch-up-kit/pages/list.html b/src/app/modules/touch-up-kit/pages/list.html index 877aa6d..f5bacdf 100644 --- a/src/app/modules/touch-up-kit/pages/list.html +++ b/src/app/modules/touch-up-kit/pages/list.html @@ -1,7 +1,7 @@ - Ajouter + Ajouter From d239d37e662296bb945816975d80041ad05f191e Mon Sep 17 00:00:00 2001 From: FyloZ Date: Wed, 15 Dec 2021 22:25:22 -0500 Subject: [PATCH 6/8] Remote login/logout old components --- .../accounts/accounts-routing.module.ts | 5 +- src/app/modules/accounts/accounts.module.ts | 9 +-- src/app/modules/accounts/accounts.ts | 32 ++++++++++- .../accounts/pages/login/login.component.html | 36 ------------ .../accounts/pages/login/login.component.sass | 8 --- .../accounts/pages/login/login.component.ts | 55 ------------------- .../pages/logout/logout.component.html | 0 .../pages/logout/logout.component.sass | 0 .../accounts/pages/logout/logout.component.ts | 35 ------------ 9 files changed, 35 insertions(+), 145 deletions(-) delete mode 100644 src/app/modules/accounts/pages/login/login.component.html delete mode 100644 src/app/modules/accounts/pages/login/login.component.sass delete mode 100644 src/app/modules/accounts/pages/login/login.component.ts delete mode 100644 src/app/modules/accounts/pages/logout/logout.component.html delete mode 100644 src/app/modules/accounts/pages/logout/logout.component.sass delete mode 100644 src/app/modules/accounts/pages/logout/logout.component.ts diff --git a/src/app/modules/accounts/accounts-routing.module.ts b/src/app/modules/accounts/accounts-routing.module.ts index 006c93f..5615140 100644 --- a/src/app/modules/accounts/accounts-routing.module.ts +++ b/src/app/modules/accounts/accounts-routing.module.ts @@ -1,14 +1,13 @@ import {NgModule} from '@angular/core' import {RouterModule, Routes} from '@angular/router' -import {LogoutComponent} from './pages/logout/logout.component' -import {Login} from './accounts' +import {Login, Logout} from './accounts' const routes: Routes = [{ path: 'login', component: Login }, { path: 'logout', - component: LogoutComponent + component: Logout }, { path: '', redirectTo: 'login' diff --git a/src/app/modules/accounts/accounts.module.ts b/src/app/modules/accounts/accounts.module.ts index c8a05ec..353042f 100644 --- a/src/app/modules/accounts/accounts.module.ts +++ b/src/app/modules/accounts/accounts.module.ts @@ -1,19 +1,16 @@ import {NgModule} from '@angular/core' import {AccountsRoutingModule} from './accounts-routing.module' -import {LoginComponent} from './pages/login/login.component' import {SharedModule} from '../shared/shared.module' -import {LogoutComponent} from './pages/logout/logout.component' -import {Login} from './accounts' +import {Login, Logout} from './accounts' import {CreInputsModule} from '../shared/components/inputs/inputs.module' import {CreButtonsModule} from '../shared/components/buttons/buttons.module' @NgModule({ declarations: [ - LoginComponent, - LogoutComponent, - Login + Login, + Logout ], imports: [ SharedModule, diff --git a/src/app/modules/accounts/accounts.ts b/src/app/modules/accounts/accounts.ts index 10f850b..81b477f 100644 --- a/src/app/modules/accounts/accounts.ts +++ b/src/app/modules/accounts/accounts.ts @@ -1,12 +1,11 @@ import {Component, HostListener, ViewChild} from '@angular/core' import {FormControl, Validators} from '@angular/forms' -import {ErrorHandlingComponent} from '../shared/components/subscribing.component' +import {ErrorHandlingComponent, SubscribingComponent} from '../shared/components/subscribing.component' import {AccountService} from './services/account.service' import {AppState} from '../shared/app-state' import {ErrorHandler, ErrorService} from '../shared/service/error.service' import {ActivatedRoute, Router} from '@angular/router' import {CreForm, ICreForm} from "../shared/components/forms/forms"; -import {take, takeUntil} from "rxjs/operators"; import {AlertService} from "../shared/service/alert.service"; @Component({ @@ -61,3 +60,32 @@ export class Login extends ErrorHandlingComponent { } } } + +@Component({ + selector: 'cre-logout', + template: '' +}) +export class Logout extends SubscribingComponent { + constructor( + private accountService: AccountService, + private alertService: AlertService, + private appState: AppState, + errorService: ErrorService, + router: Router, + activatedRoute: ActivatedRoute + ) { + super(errorService, activatedRoute, router) + this.appState.title = 'Connexion' + } + + ngOnInit(): void { + if (!this.appState.isAuthenticated) { + this.urlUtils.navigateTo('/account/login') + } + + this.subscribeAndNavigate( + this.accountService.logout(), + '/account/login' + ) + } +} diff --git a/src/app/modules/accounts/pages/login/login.component.html b/src/app/modules/accounts/pages/login/login.component.html deleted file mode 100644 index 28aa77c..0000000 --- a/src/app/modules/accounts/pages/login/login.component.html +++ /dev/null @@ -1,36 +0,0 @@ -
- - - Connexion au système - - - - Numéro d'utilisateur - - person - - Un numéro d'utilisateur est requis - Le numéro d'utilisateur doit être un nombre - - - - Mot de passe - - lock - - Un mot de passe est requis - - - - - - - -
diff --git a/src/app/modules/accounts/pages/login/login.component.sass b/src/app/modules/accounts/pages/login/login.component.sass deleted file mode 100644 index afd1937..0000000 --- a/src/app/modules/accounts/pages/login/login.component.sass +++ /dev/null @@ -1,8 +0,0 @@ -mat-card - width: 25rem - - .alert p - margin: 0 - - mat-form-field - width: 100% diff --git a/src/app/modules/accounts/pages/login/login.component.ts b/src/app/modules/accounts/pages/login/login.component.ts deleted file mode 100644 index 919bed0..0000000 --- a/src/app/modules/accounts/pages/login/login.component.ts +++ /dev/null @@ -1,55 +0,0 @@ -import {Component, OnInit} from '@angular/core' -import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms' -import {AccountService} from '../../services/account.service' -import {ActivatedRoute, Router} from '@angular/router' -import {ErrorService} from '../../../shared/service/error.service' -import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component' -import {AppState} from '../../../shared/app-state' - -@Component({ - selector: 'cre-login', - templateUrl: './login.component.html', - styleUrls: ['./login.component.sass'] -}) -export class LoginComponent extends ErrorHandlingComponent implements OnInit { - form: FormGroup - idFormControl: FormControl - passwordFormControl: FormControl - - constructor( - private formBuilder: FormBuilder, - private accountService: AccountService, - private appState: AppState, - errorService: ErrorService, - router: Router, - activatedRoute: ActivatedRoute - ) { - super(errorService, activatedRoute, router) - this.appState.title = 'Connexion' - } - - ngOnInit(): void { - this.errorService.activeErrorHandler = this - - if (this.appState.isAuthenticated) { - this.router.navigate(['/color']) - } - - this.idFormControl = this.formBuilder.control(null, Validators.compose([Validators.required, Validators.pattern(new RegExp('^[0-9]+$'))])) - this.passwordFormControl = this.formBuilder.control(null, Validators.required) - this.form = this.formBuilder.group({ - id: this.idFormControl, - password: this.passwordFormControl - }) - } - - submit() { - this.subscribe( - this.accountService.login( - this.idFormControl.value, - this.passwordFormControl.value - ), - response => console.log(response) - ) - } -} diff --git a/src/app/modules/accounts/pages/logout/logout.component.html b/src/app/modules/accounts/pages/logout/logout.component.html deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/modules/accounts/pages/logout/logout.component.sass b/src/app/modules/accounts/pages/logout/logout.component.sass deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/modules/accounts/pages/logout/logout.component.ts b/src/app/modules/accounts/pages/logout/logout.component.ts deleted file mode 100644 index a1433c1..0000000 --- a/src/app/modules/accounts/pages/logout/logout.component.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {Component} from '@angular/core'; -import {AccountService} from "../../services/account.service"; -import {ActivatedRoute, Router} from "@angular/router"; -import {AppState} from "../../../shared/app-state"; -import {SubscribingComponent} from "../../../shared/components/subscribing.component"; -import {ErrorService} from "../../../shared/service/error.service"; - -@Component({ - selector: 'cre-logout', - templateUrl: './logout.component.html', - styleUrls: ['./logout.component.sass'] -}) -export class LogoutComponent extends SubscribingComponent { - - constructor( - private accountService: AccountService, - private appState: AppState, - errorService: ErrorService, - router: Router, - activatedRoute: ActivatedRoute - ) { - super(errorService, activatedRoute, router) - } - - ngOnInit(): void { - if (!this.appState.isAuthenticated) { - this.urlUtils.navigateTo('/account/login') - } - - this.subscribeAndNavigate( - this.accountService.logout(), - '/account/login' - ) - } -} From 82cb974d270871be2f1e24bfcfca2e5fad1136cd Mon Sep 17 00:00:00 2001 From: FyloZ Date: Wed, 15 Dec 2021 22:32:40 -0500 Subject: [PATCH 7/8] CI/CD --- .drone.yml | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/.drone.yml b/.drone.yml index 11396c2..d44383a 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,6 +1,6 @@ --- global-variables: - release: &release ${DRONE_BRANCH##**/} + release: &release ${DRONE_TAG} environment: &environment CRE_REGISTRY_IMAGE: registry.fyloz.dev:5443/colorrecipesexplorer/frontend CRE_PORT: 9102 @@ -21,6 +21,9 @@ steps: - echo -n "latest" > .tags when: branch: develop + event: + exclude: + - pull_request - name: set-docker-tags-release image: *alpine-image @@ -29,9 +32,10 @@ steps: commands: - echo -n "latest-release,$CRE_RELEASE" > .tags when: - branch: release/** + event: + - tag - - name: containerize + - name: containerize-dev image: plugins/docker environment: <<: *environment @@ -40,7 +44,16 @@ steps: when: branch: - develop - - release/** + + - name: containerize-release + image: plugins/docker + environment: + <<: *environment + settings: + repo: *docker-registry-repo + when: + event: + - tag - name: deploy image: alpine:latest @@ -70,10 +83,11 @@ steps: - ssh -p $DEPLOY_SERVER_SSH_PORT $DEPLOY_SERVER_USERNAME@$DEPLOY_SERVER "docker pull $CRE_REGISTRY_IMAGE:$CRE_RELEASE" - ssh -p $DEPLOY_SERVER_SSH_PORT $DEPLOY_SERVER_USERNAME@$DEPLOY_SERVER "docker run -d -p $CRE_PORT:80 --name=$DEPLOY_CONTAINER_NAME $CRE_REGISTRY_IMAGE:$CRE_RELEASE" when: - branch: release/** + event: + - tag trigger: branch: - develop - - release/** - - master + event: + - tag From f04a3c7ba32a3f751f88aab72a2b111ea34507f0 Mon Sep 17 00:00:00 2001 From: FyloZ Date: Mon, 20 Dec 2021 19:20:01 -0500 Subject: [PATCH 8/8] Fix mix editor did not get the materials from the correct location in update mode --- src/app/modules/recipes/mix/mix.ts | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/app/modules/recipes/mix/mix.ts b/src/app/modules/recipes/mix/mix.ts index a91833f..7257668 100644 --- a/src/app/modules/recipes/mix/mix.ts +++ b/src/app/modules/recipes/mix/mix.ts @@ -27,7 +27,7 @@ abstract class _BaseMixPage extends SubscribingComponent { protected mixService: MixService, private recipeService: RecipeService, private materialTypeService: MaterialTypeService, - private materialService: MaterialService, + protected materialService: MaterialService, errorService: ErrorService, router: Router, activatedRoute: ActivatedRoute @@ -50,13 +50,15 @@ abstract class _BaseMixPage extends SubscribingComponent { set recipe(recipe: Recipe) { this._recipe = recipe - this.materials$ = this.materialService.getAllForMixCreation(recipe.id) + this.materials$ = this.fetchMaterials(recipe.id) } get recipe(): Recipe { return this._recipe } + protected abstract fetchMaterials(recipeId: number): Observable + abstract submit(dto: MixSaveDto) } @@ -65,6 +67,10 @@ abstract class _BaseMixPage extends SubscribingComponent { templateUrl: 'add.html' }) export class MixAdd extends _BaseMixPage { + protected fetchMaterials(recipeId: number): Observable { + return this.materialService.getAllForMixCreation(recipeId) + } + submit(dto: MixSaveDto) { this.subscribeAndNavigate( this.mixService.saveDto(dto), @@ -80,21 +86,27 @@ export class MixAdd extends _BaseMixPage { export class MixEdit extends _BaseMixPage { mix: Mix + private mixId: number + ngOnInit() { super.ngOnInit() + this.mixId = this.urlUtils.parseIntUrlParam('id') + this.fetchMix() } private fetchMix() { - const mixId = this.urlUtils.parseIntUrlParam('id') - this.subscribe( - this.mixService.getById(mixId), + this.mixService.getById(this.mixId), mix => this.mix = mix ) } + protected fetchMaterials(recipeId: number): Observable { + return this.materialService.getAllForMixUpdate(this.mixId) + } + submit(dto: MixSaveDto) { this.subscribeAndNavigate( this.mixService.updateDto({...dto, id: this.mix.id}),