From 62f5c9435e32c100ad113661d670bd1c3c766683 Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Fri, 26 Nov 2021 11:51:34 +0100 Subject: [PATCH] cleanup nad featuring fdp authentication --- src/app/accessapi/accessapi.component.html | 69 ----- src/app/accessapi/accessapi.component.scss | 0 src/app/accessapi/accessapi.component.spec.ts | 25 -- src/app/accessapi/accessapi.component.ts | 136 --------- src/app/api.service.spec.ts | 16 - src/app/api.service.ts | 9 - src/app/app-routing.module.ts | 16 +- src/app/app.module.ts | 9 +- .../authentication/authentication.module.ts | 7 +- .../authentication/services/auth.service.ts | 28 ++ .../authentication/services/fdp.guard.spec.ts | 16 + src/app/authentication/services/fdp.guard.ts | 24 ++ .../signout/signout.component.html | 1 - .../signout/signout.component.scss | 0 .../signout/signout.component.spec.ts | 25 -- .../signout/signout.component.ts | 17 -- .../signup/signup.component.html | 282 ++++++++++++------ .../signup/signup.component.scss | 3 + .../authentication/signup/signup.component.ts | 103 ++++++- .../confirm-validator.directive.spec.ts | 8 + .../validators/confirm-validator.directive.ts | 39 +++ src/app/dashboard/dashboard.component.html | 2 +- src/app/dashboard/dashboard.component.ts | 18 +- .../settingsmartapi.component.html | 15 - .../settingsmartapi.component.scss | 0 .../settingsmartapi.component.spec.ts | 25 -- .../settingsmartapi.component.ts | 49 --- 27 files changed, 422 insertions(+), 520 deletions(-) delete mode 100644 src/app/accessapi/accessapi.component.html delete mode 100644 src/app/accessapi/accessapi.component.scss delete mode 100644 src/app/accessapi/accessapi.component.spec.ts delete mode 100644 src/app/accessapi/accessapi.component.ts delete mode 100644 src/app/api.service.spec.ts delete mode 100644 src/app/api.service.ts create mode 100644 src/app/authentication/services/fdp.guard.spec.ts create mode 100644 src/app/authentication/services/fdp.guard.ts delete mode 100644 src/app/authentication/signout/signout.component.html delete mode 100644 src/app/authentication/signout/signout.component.scss delete mode 100644 src/app/authentication/signout/signout.component.spec.ts delete mode 100644 src/app/authentication/signout/signout.component.ts create mode 100644 src/app/authentication/validators/confirm-validator.directive.spec.ts create mode 100644 src/app/authentication/validators/confirm-validator.directive.ts delete mode 100644 src/app/settingsmartapi/settingsmartapi.component.html delete mode 100644 src/app/settingsmartapi/settingsmartapi.component.scss delete mode 100644 src/app/settingsmartapi/settingsmartapi.component.spec.ts delete mode 100644 src/app/settingsmartapi/settingsmartapi.component.ts diff --git a/src/app/accessapi/accessapi.component.html b/src/app/accessapi/accessapi.component.html deleted file mode 100644 index d3568432e..000000000 --- a/src/app/accessapi/accessapi.component.html +++ /dev/null @@ -1,69 +0,0 @@ - -<form [formGroup]="Form" > - - <label>Upload and fill form width repository description file: </label><br> - <input type="file" id="repofile" name="repofile " class="btn btn-primary" (change)="swaggertoyaml('fill')" ><br> - <label>Or describe your repository and save a new file for publishing in the FDP database:</label><br> - - <div class="form-group"> - <label>title</label> - <input type="text" class="form-control" formControlName="title" required> - </div> - <div class="form-group"> - <label>Description</label> - <textarea class="form-control" formControlName="description"></textarea> - </div> - <div class="form-group"> - <label>version</label> - <input type="text" class="form-control" formControlName="version"> - </div> - <div class="form-group"> - <label>url</label> - <input type="text" class="form-control" formControlName="url"> - </div> - <div class="form-group"> - <label>Description</label> - <textarea class="form-control" formControlName="urldescription"></textarea> - </div> - <div class="form-group"> - <label>paths</label> - <input type="text" class="form-control" formControlName="paths"> - </div> <div class="form-group"> - <label>verb</label> - <input type="text" class="form-control" formControlName="verb"> -</div> <div class="form-group"> - <label>summary</label> - <input type="text" class="form-control" formControlName="summary"> -</div> - <div class="form-group"> - <label>description</label> - <textarea class="form-control" formControlName="verbdescription"></textarea> - </div> - <div class="form-group"> - <label>responses</label> - <input type="text" class="form-control" formControlName="responses"> - </div> - <div class="form-group"> - <label>description</label> - <textarea class="form-control" formControlName="responsedescription"></textarea> - </div> - <div class="form-group"> - <label>content</label> - <input type="text" class="form-control" formControlName="content"> - </div> - <div class="form-group"> - <label>schema</label> - <input type="text" class="form-control" formControlName="schema"> - </div> - <div class="form-group"> - <label>items</label> - <input type="text" class="form-control" formControlName="items"> - </div> - - <div> - <br> - <button type="submit" (click)="swaggertoyaml('submit')" class="btn btn-primary">Save swagger api description file</button> - </div> -</form> - - diff --git a/src/app/accessapi/accessapi.component.scss b/src/app/accessapi/accessapi.component.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/app/accessapi/accessapi.component.spec.ts b/src/app/accessapi/accessapi.component.spec.ts deleted file mode 100644 index c57085f14..000000000 --- a/src/app/accessapi/accessapi.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { AccessapiComponent } from './accessapi.component'; - -describe('AccessapiComponent', () => { - let component: AccessapiComponent; - let fixture: ComponentFixture<AccessapiComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ AccessapiComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(AccessapiComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/accessapi/accessapi.component.ts b/src/app/accessapi/accessapi.component.ts deleted file mode 100644 index 5e2f37b81..000000000 --- a/src/app/accessapi/accessapi.component.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { Validators } from '@angular/forms'; -import { FormArray } from '@angular/forms'; -import { HttpClient } from '@angular/common/http'; -import { FileSaverService } from 'ngx-filesaver'; -import { FormControl} from '@angular/forms'; -import { FormGroup} from '@angular/forms'; - - -@Component({ - selector: 'app-accessapi', - templateUrl: './accessapi.component.html', - styleUrls: ['./accessapi.component.scss'] -}) -export class AccessapiComponent implements OnInit { - - - public fileName: string; - public importFile: File; - - Form = new FormGroup({ - title: new FormControl('', Validators.required), - description: new FormControl(''), - version: new FormControl(''), - url: new FormControl(''), - urldescription: new FormControl(''), - paths: new FormControl(''), - verb: new FormControl(''), - summary: new FormControl(''), - verbdescription: new FormControl(''), - responses: new FormControl(''), - responsedescription: new FormControl(''), - content: new FormControl(''), - schema: new FormControl(''), - items: new FormControl(''), - filetofill: new FormControl(), - }); - - - constructor( - private _httpClient: HttpClient, - private _FileSaverService: FileSaverService, - ) { } - - ngOnInit() { - } - - swaggertoyaml(buttonType) { -if (buttonType == 'submit') { -let data: string; - -data ='openapi: 3.0.0 \n\ -info: \n\ - title: '+ this.Form.value.title +' \n\ - description: '+ this.Form.value.description +' \n\ - version: '+ this.Form.value.version +' \n\ -server: \n\ - - url: '+ this.Form.value.url +' \n\ - description: '+ this.Form.value.urldescription +' \n\ -paths: \n\ - '+this.Form.value.paths+': \n\ - '+ this.Form.value.verb +': \n\ - summary: '+ this.Form.value.summary +' \n\ - description: '+ this.Form.value.verbdescription +' \n\ - responses: \n\ - '+ this.Form.value.responses +': \n\ - description: '+ this.Form.value.responsedescription +' \n\ - content: \n\ - '+ this.Form.value.content +': \n\ - schema: \n\ - type: '+ this.Form.value.schema +' \n\ - items: \n\ - type: '+ this.Form.value.items +' \n\ -' - - const fileName = `swagger.yaml`; - const fileType = this._FileSaverService.genType(fileName); - const txtBlob = new Blob([data], { type: fileType }); - - this._FileSaverService.save(txtBlob, fileName); - } - - if (buttonType == 'fill') { - const files = (event.target as HTMLInputElement).files; - this.importFile = files[0]; - - let text = ""; - let lines = []; - let line = ""; - let map = new Map(); - let fileReader = new FileReader(); - fileReader.onload = (event) => { - text = fileReader.result as string; - - lines = text.split("\n"); - let j = 1; - for ( let i = 0; i < lines.length; i++) { - line = lines[i].split(": "); - if (line[0].trim() == "description") { - map.set("description"+j,line[1]); - j++; - } else { - map.set(line[0].trim(),line[1]); - } - console.log(line); - } - -console.log(map); - - this.Form.setValue({ - title: map.get('title'), - description: map.get('description1'), - version: map.get('version'), - url: map.get('- url'), - urldescription: map.get('description2'), - paths: '', - verb: '', - summary: map.get('summary'), - verbdescription: map.get('description3'), - responses: '', - responsedescription: map.get('description4'), - content: '', - schema: map.get('schema'), - items: map.get('items'), - filetofill: '' - }); - - } - fileReader.readAsText(this.importFile); - - - } - - } - -} diff --git a/src/app/api.service.spec.ts b/src/app/api.service.spec.ts deleted file mode 100644 index c0310ae68..000000000 --- a/src/app/api.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { ApiService } from './api.service'; - -describe('ApiService', () => { - let service: ApiService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(ApiService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/api.service.ts b/src/app/api.service.ts deleted file mode 100644 index 776566e11..000000000 --- a/src/app/api.service.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Injectable } from '@angular/core'; - -@Injectable({ - providedIn: 'root' -}) -export class ApiService { - - constructor() { } -} diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 649b04d31..79dd92633 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -1,21 +1,16 @@ import { NgModule } from '@angular/core'; import { RouterModule, Route } from '@angular/router'; -import { UserComponent } from './user/user.component'; import { RepositoryComponent } from './repository/repository.component'; -import { AccessapiComponent } from './accessapi/accessapi.component'; -import { SettingfdpComponent } from './settingfdp/settingfdp.component'; -import { SettingsmartapiComponent } from './settingsmartapi/settingsmartapi.component'; -import { RepositoryinfoComponent } from './repositoryinfo/repositoryinfo.component'; -import { PublishApiComponent } from './publishapi/publishapi.component' import { SearchComponent } from './search/search.component'; -import { AuthenticationComponent } from './authentication/authentication.component'; import { SigninComponent } from './authentication/signin/signin.component'; import { SignupComponent } from './authentication/signup/signup.component'; import { DashboardComponent } from './dashboard/dashboard.component'; import { AuthGuardService } from './authentication/services/auth.guard'; import { StatsComponent } from './stats/stats.component'; import { CallbackComponent } from './callback/callback.component'; -import { AppComponent } from './app.component'; +import { FdpGuard } from './authentication/services/fdp.guard'; +import { RepositoryinfoComponent } from './repositoryinfo/repositoryinfo.component'; +import { PublishApiComponent } from './publishapi/publishapi.component'; export interface ICustomRoute extends Route { name?: string; @@ -25,17 +20,16 @@ export interface ICustomRoute extends Route { const routes: ICustomRoute[] = [ { path: '', redirectTo: '/dashboard', pathMatch: 'full' }, {path: 'callback', component: CallbackComponent}, - { path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuardService], + { path: 'dashboard', component: DashboardComponent, canActivate: [ FdpGuard], children: [ { path: 'simplesearch', component: SearchComponent }, { path: 'repository', component: RepositoryComponent }, { path: 'repositoryinfo', component: RepositoryinfoComponent }, - { path: 'accessapi', component: AccessapiComponent }, { path: 'stats', component: StatsComponent }, { path: 'publishapi', component: PublishApiComponent }, - ] }, + {path: 'fdpsignin', component: SignupComponent, canActivate: [AuthGuardService]}, { path: 'login', component: SigninComponent} ] diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 03f97eaed..c95b7f81c 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -13,10 +13,8 @@ import { MatSelectModule } from '@angular/material/select'; import { MatSidenavModule } from '@angular/material/sidenav'; import { RepositoryComponent } from './repository/repository.component'; -import { AccessapiComponent } from './accessapi/accessapi.component'; import { DatasetsComponent } from './datasets/datasets.component'; import { SettingfdpComponent } from './settingfdp/settingfdp.component'; -import { SettingsmartapiComponent } from './settingsmartapi/settingsmartapi.component'; import { UserComponent } from './user/user.component'; import { ReactiveFormsModule } from '@angular/forms'; @@ -24,7 +22,7 @@ import { FormsModule } from '@angular/forms'; import { RepositoryinfoComponent } from './repositoryinfo/repositoryinfo.component'; -import { HttpClientModule, HttpClient, HTTP_INTERCEPTORS } from '@angular/common/http'; +import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { FileSaverModule } from 'ngx-filesaver'; import { AppConfiguration } from './AppConfiguration'; import { PublishApiComponent } from './publishapi/publishapi.component'; @@ -49,16 +47,12 @@ import { CallbackComponent } from './callback/callback.component'; - - @NgModule({ declarations: [ AppComponent, RepositoryComponent, - AccessapiComponent, DatasetsComponent, SettingfdpComponent, - SettingsmartapiComponent, UserComponent, RepositoryinfoComponent, PublishApiComponent, @@ -69,6 +63,7 @@ import { CallbackComponent } from './callback/callback.component'; FeedbackDialogComponent, DatasetsDialogComponent, CallbackComponent, + ], imports: [ BrowserModule, diff --git a/src/app/authentication/authentication.module.ts b/src/app/authentication/authentication.module.ts index 217ccf29a..c2fc23238 100644 --- a/src/app/authentication/authentication.module.ts +++ b/src/app/authentication/authentication.module.ts @@ -6,15 +6,15 @@ import { BrowserModule } from '@angular/platform-browser'; import { AuthenticationComponent } from './authentication.component'; import { RouterModule } from '@angular/router'; import { SigninComponent } from './signin/signin.component'; -import { SignoutComponent } from './signout/signout.component'; import { SignupComponent } from './signup/signup.component'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { AccountAdminComponent } from './admin/account.admin.component'; +import { ConfirmValidatorDirective } from './validators/confirm-validator.directive'; @NgModule({ - declarations: [SigninComponent,AuthenticationComponent, SigninComponent, SignoutComponent, SignupComponent, AccountAdminComponent], + declarations: [SigninComponent,AuthenticationComponent, SigninComponent, SignupComponent, AccountAdminComponent, ConfirmValidatorDirective], imports: [ CommonModule, FormsModule, @@ -25,7 +25,8 @@ import { AccountAdminComponent } from './admin/account.admin.component'; NebularModule ], exports:[ - SigninComponent + SigninComponent, + ConfirmValidatorDirective ] }) export class AuthenticationModule { diff --git a/src/app/authentication/services/auth.service.ts b/src/app/authentication/services/auth.service.ts index 4b29c553f..b9e8c5d01 100644 --- a/src/app/authentication/services/auth.service.ts +++ b/src/app/authentication/services/auth.service.ts @@ -25,6 +25,7 @@ export class AuthService { private authorizationEndpoint = '/oauth2/authorization/oidc'; private tokenEndpoint = '/login/oauth2/code/oidc'; private baseUrl = environment.smartharvesterUrl; + private FdpBaseUrl = environment.fdpUrl; private tokenKey = 'auth-token;' @@ -39,6 +40,28 @@ export class AuthService { constructor(private http: HttpClient, private tokenService: TokenStorageService, private appConfig: AppConfiguration, private router: Router) { } + FdpSignUp(user: SmartHarvesterUser): Observable<any> { + const httpOptions = { + headers: new HttpHeaders({ 'Content-Type': 'application/json', 'Authorization' : `Baerer ${this.getToken()}` }) + }; + + return this.http.post(`${this.baseUrl}/harvester/auth/signup`, { + firstName: user.firstName, + lastName: user.lastName, + email: user.email, + password: user.password + }, httpOptions); + } + + getFdpToken(email: string, password: string): Observable<any> { + const httpOptions = { + headers: new HttpHeaders({ 'Content-Type': 'application/json'}) + }; + return this.http.post(`${this.FdpBaseUrl}/tokens`, { + email: email, + password: password + }, httpOptions) + } login() { @@ -63,6 +86,11 @@ export class AuthService { return (token !== null); } + isFdpLoggedIn(): boolean { + const fdpToken = this.tokenService.getFDPToken(); + return fdpToken !== null; + } + logout() { diff --git a/src/app/authentication/services/fdp.guard.spec.ts b/src/app/authentication/services/fdp.guard.spec.ts new file mode 100644 index 000000000..dddae70d5 --- /dev/null +++ b/src/app/authentication/services/fdp.guard.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { FdpGuard } from './fdp.guard'; + +describe('FdpGuard', () => { + let guard: FdpGuard; + + beforeEach(() => { + TestBed.configureTestingModule({}); + guard = TestBed.inject(FdpGuard); + }); + + it('should be created', () => { + expect(guard).toBeTruthy(); + }); +}); diff --git a/src/app/authentication/services/fdp.guard.ts b/src/app/authentication/services/fdp.guard.ts new file mode 100644 index 000000000..11770c65a --- /dev/null +++ b/src/app/authentication/services/fdp.guard.ts @@ -0,0 +1,24 @@ + +import { Injectable } from '@angular/core'; +import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router } from '@angular/router'; +import { Observable } from 'rxjs'; +import { AuthService } from './auth.service'; + +@Injectable({ + providedIn: 'root' +}) +export class FdpGuard implements CanActivate { + constructor(private authService: AuthService, private router: Router) { + } + canActivate( + _next: ActivatedRouteSnapshot, + _state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree { + if (this.authService.isFdpLoggedIn()) { + + return true; + } + this.router.navigate(['/fdpsignin']) + return false; + } + +} diff --git a/src/app/authentication/signout/signout.component.html b/src/app/authentication/signout/signout.component.html deleted file mode 100644 index 9e1beb8d7..000000000 --- a/src/app/authentication/signout/signout.component.html +++ /dev/null @@ -1 +0,0 @@ -<p>signout works!</p> diff --git a/src/app/authentication/signout/signout.component.scss b/src/app/authentication/signout/signout.component.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/app/authentication/signout/signout.component.spec.ts b/src/app/authentication/signout/signout.component.spec.ts deleted file mode 100644 index 600423eae..000000000 --- a/src/app/authentication/signout/signout.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { SignoutComponent } from './signout.component'; - -describe('SignoutComponent', () => { - let component: SignoutComponent; - let fixture: ComponentFixture<SignoutComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ SignoutComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(SignoutComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/authentication/signout/signout.component.ts b/src/app/authentication/signout/signout.component.ts deleted file mode 100644 index 4b44c0ad8..000000000 --- a/src/app/authentication/signout/signout.component.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -@Component({ - selector: 'app-signout', - templateUrl: './signout.component.html', - styleUrls: ['./signout.component.scss'] -}) -export class SignoutComponent implements OnInit { - - constructor() { } - - ngOnInit(): void { - } - - - -} diff --git a/src/app/authentication/signup/signup.component.html b/src/app/authentication/signup/signup.component.html index 5db272cfe..976b3937b 100644 --- a/src/app/authentication/signup/signup.component.html +++ b/src/app/authentication/signup/signup.component.html @@ -1,91 +1,197 @@ - <div style="display: flex;justify-content: center;"> - <nb-card status="success" size="small" style="width: 24em;height: auto;"> - <nb-card-header style="text-align: center;">Create an account to F2DS API register</nb-card-header> - <nb-card-body class="example-items-col" style="overflow: hidden;"> +<nb-layout> + <nb-layout-header fixed> + <img width="80" alt="Angular Logo" src="assets/images/logo.png" /> + <h3 style="width: 100%;text-align: center;"> <strong></strong></h3> + <!--User badge--> - <div class="col-md-12"> - <div class="card card-container"> - <form *ngIf="!isLoggedIn" name="formGroup" (ngSubmit)="f.form.valid " #f="ngForm" - novalidate> - <div class="form-group"> - <label for="firstName">First Name</label> - <nb-form-field> - <input nbInput fullWidth type="text" class="form-control" name="firstName" - [(ngModel)]="user.firstName" required #email="ngModel" /> - </nb-form-field> - <!-- Email error--> - <div class="alert alert-danger" role="alert" *ngIf="f.submitted && email.invalid"> - First name is required! - </div> - </div> - <!--Last name--> - <div class="form-group"> - <label for="firstName">Last Name</label> - <nb-form-field> - <input nbInput fullWidth type="text" class="form-control" name="lastName" - [(ngModel)]="user.lastName" required #email="ngModel" /> - </nb-form-field> - <!-- Email error--> - <div class="alert alert-danger" role="alert" *ngIf="f.submitted && email.invalid"> - Last name is required! - </div> - </div> - <!--Email --> - <div class="form-group"> - <label for="email">Email</label> - <nb-form-field> - <nb-icon nbPrefix icon="at-outline" pack="eva"></nb-icon> - <input nbInput fullWidth type="text" class="form-control" name="email" - [(ngModel)]="user.email" required #email="ngModel" /> - </nb-form-field> - <!-- Email error--> - <div class="alert alert-danger" role="alert" *ngIf="f.submitted && email.invalid"> - Email is required! - </div> - </div> - <!--Password--> - <div class="form-group"> - <label for="password">Password</label> - <nb-form-field> - <input nbInput fullWidth type="password" class="form-control" name="password" - [(ngModel)]="user.password" required minlength="6" #password="ngModel" /> - - </nb-form-field> - <label for="password">Confirm password</label> - <nb-form-field> - <input nbInput fullWidth type="password" class="form-control" name="passwordConfirm" - [(ngModel)]="user.passwordConfirm" required minlength="6" #password="ngModel" /> - - </nb-form-field> - <!-- Password error--> - <div class="alert alert-danger" role="alert" *ngIf="f.submitted && password.invalid"> - <div *ngIf="password.errors.required">Password is required</div> - <div *ngIf="password.errors.minlength"> - Password must be at least 6 characters - </div> - </div> - </div> - <br> - <div class="form-group" style="text-align: center;"> - <button nbButton status="success" class="btn btn-primary btn-block"> - Sign Up - </button> - </div> - <div class="form-group"> - <div class="alert alert-danger" role="alert" *ngIf="f.submitted && isLoginFailed"> - Login failed: {{ errorMessage }} - </div> - </div> - </form> - <section class="another-action" aria-label="Register" style="text-align: center; margin-top: 20px;"> - Already have an account ? <a class="text-link" routerLink="../signin">Sign In</a> - </section> - <!----> - <div class="alert alert-success" *ngIf="isLoggedIn"> - Logged in as - </div> - </div> + <nb-user style="margin-right: 10px;" name="{{user.firstName}}" title="{{user.lastName}}" + nbContextMenuTag="my-context-menu" badgePosition="right"> + </nb-user> + <div style="float: right;"> + <button (click)="logout()" status="danger" nbButton>logout</button> + </div> + </nb-layout-header> + <nb-layout-column> + <div style="display: flex;justify-content: center;"> + <nb-card status="success" size="small" style="width: 24em;height: auto;"> + <nb-card-header style="text-align: center;">Welcome to F2DS {{user.firstName}} {{user.lastName}}. + </nb-card-header> + <ng-container *ngIf="isRegistred; then registred; else notRegistred"> + + </ng-container> + </nb-card> + </div> + </nb-layout-column> + + + <nb-layout-footer>Contact us</nb-layout-footer> + +</nb-layout> + +<!-- block create account--> +<ng-template #notRegistred> + <nb-card-body class="example-items-col" style="overflow: hidden;"> + You are not yet registred on Fair Data Point. Please enter a password to register an account on the FDP. + <div class="card card-container"> + <form name="formGroup" (ngSubmit)="f.form.valid && onSubmit()" #f="ngForm" novalidate> + <div class="form-group"> + <label for="firstName">First Name</label> + <nb-form-field> + <input nbInput fullWidth type="text" class="form-control" name="firstName" + [(ngModel)]="userFDP.firstName" required #firstName="ngModel" + [disabled]="userFDP.firstName !== null" /> + </nb-form-field> + <!-- Email error--> + <div class="alert alert-danger" role="alert" *ngIf="f.submitted && email.invalid"> + First name is required! + </div> + </div> + <!--Last name--> + <div class="form-group"> + <label for="firstName">Last Name</label> + <nb-form-field> + <input nbInput fullWidth type="text" class="form-control" name="lastName" + [(ngModel)]="userFDP.lastName" required #lastname="ngModel" + [disabled]="userFDP.lastName !== null" /> + </nb-form-field> + <!-- Email error--> + <div class="alert alert-danger" role="alert" *ngIf="f.submitted && email.invalid"> + Last name is required! + </div> + </div> + <!--Email --> + <div class="form-group"> + <label for="email">Email</label> + <nb-form-field> + <nb-icon nbPrefix icon="at-outline" pack="eva"></nb-icon> + <input nbInput fullWidth type="text" class="form-control" name="email" [(ngModel)]="userFDP.email" + required #email="ngModel" [disabled]="userFDP.email !== null" /> + </nb-form-field> + <!-- Email error--> + <div class="alert alert-danger" role="alert" *ngIf="f.submitted && email.invalid"> + Email is required! + </div> + </div> + <!--Password--> + <div class="form-group"> + <label for="password">Password</label> + <nb-form-field> + <input nbInput fullWidth [type]="getInputType()" class="form-control" name="password" + [(ngModel)]="userFDP.password" required minlength="6" #password="ngModel" compare-password="passwordConfirm"/> + <button type="button" nbSuffix nbButton ghost (click)="toggleShowPassword()"> + <nb-icon [icon]="showPassword ? 'eye-outline' : 'eye-off-2-outline'" pack="eva" + [attr.aria-label]="showPassword ? 'hide password' : 'show password'"> + </nb-icon> + </button> + </nb-form-field> + <!-- Password error--> + <div class="alert alert-danger" role="alert" *ngIf="f.submitted && password.invalid"> + <div *ngIf="password.errors.required">Password is required</div> + <div *ngIf="password.errors.minlength"> + Password must be at least 6 characters + </div> + </div> + </div> + <!--Password confirm--> + <div class="form-group"> + <label for="passwordConfirm">Confirm Password</label> + <nb-form-field> + <input nbInput fullWidth [type]="getInputType()" class="form-control" name="passwordConfirm" + [(ngModel)]="userFDP.passwordConfirm" required minlength="6" #passwordConfirm="ngModel" compare-password="password" /> + <button type="button" nbSuffix nbButton ghost (click)="toggleShowPassword()"> + <nb-icon [icon]="showPassword ? 'eye-outline' : 'eye-off-2-outline'" pack="eva" + [attr.aria-label]="showPassword ? 'hide password' : 'show password'"> + </nb-icon> + </button> + </nb-form-field> + <!-- Password confirm error--> + <div class="alert alert-danger" role="alert" *ngIf="f.submitted && passwordConfirm.invalid"> + <div *ngIf="passwordConfirm.errors.required">Password is required</div> + <div *ngIf="passwordConfirm.errors.minlength"> + Password must be at least 6 characters </div> - </nb-card-body> - </nb-card> + <div *ngIf="passwordConfirm.errors.compare">Password Doesn't match</div> + </div> + </div> + + <br> + <div class="form-group" style="text-align: center;"> + <button nbButton status="success" class="btn btn-primary btn-block"> + Sign Up + </button> + </div> + <div class="form-group"> + <div class="alert alert-danger" role="alert" *ngIf="f.submitted && isLoginFailed"> + Login failed: {{ errorMessage }} + </div> + </div> + </form> + </div> + <div class="col-md-12"> + <div class="card card-container"> + + </div> + </div> + </nb-card-body> +</ng-template> + +<!-- block registred--> +<ng-template #registred> + <nb-card-body class="example-items-col" style="overflow: hidden;"> + You are already registred on Fair Data Point. Please enter your password to login to your FDP account. + <div class="card card-container"> + <form name="formGroup" (ngSubmit)="f.form.valid && onSubmitResgistred()" #f="ngForm" novalidate> + + <!--Email --> + <div class="form-group"> + <label for="email">Email</label> + <nb-form-field> + <nb-icon nbPrefix icon="at-outline" pack="eva"></nb-icon> + <input nbInput fullWidth type="text" class="form-control" name="email" [(ngModel)]="userFDP.email" + required #email="ngModel" [disabled]="userFDP.email !== null" /> + </nb-form-field> + <!-- Email error--> + <div class="alert alert-danger" role="alert" *ngIf="f.submitted && email.invalid"> + Email is required! + </div> + </div> + <!--Password--> + <div class="form-group"> + <label for="password">Password</label> + <nb-form-field> + <input nbInput fullWidth [type]="getInputType()" class="form-control" name="password" + [(ngModel)]="userFDP.password" required minlength="6" #password="ngModel" compare-password="passwordConfirm"/> + <button type="button" nbSuffix nbButton ghost (click)="toggleShowPassword()"> + <nb-icon [icon]="showPassword ? 'eye-outline' : 'eye-off-2-outline'" pack="eva" + [attr.aria-label]="showPassword ? 'hide password' : 'show password'"> + </nb-icon> + </button> + </nb-form-field> + <!-- Password error--> + <div class="alert alert-danger" role="alert" *ngIf="f.submitted && password.invalid"> + <div *ngIf="password.errors.required">Password is required</div> + <div *ngIf="password.errors.minlength"> + Password must be at least 6 characters + </div> + </div> + </div> + <br> + <div class="form-group" style="text-align: center;"> + <button nbButton status="success" class="btn btn-primary btn-block"> + Sign In + </button> + </div> + <div class="form-group"> + <div class="alert alert-danger" role="alert" *ngIf="f.submitted && errorMessage"> + Login failed: {{ errorMessage }} + </div> + </div> + </form> + </div> + <div class="col-md-12"> + <div class="card card-container"> + </div> + </div> + </nb-card-body> +</ng-template> \ No newline at end of file diff --git a/src/app/authentication/signup/signup.component.scss b/src/app/authentication/signup/signup.component.scss index e69de29bb..f21864571 100644 --- a/src/app/authentication/signup/signup.component.scss +++ b/src/app/authentication/signup/signup.component.scss @@ -0,0 +1,3 @@ +.alert-danger{ + color: red; +} \ No newline at end of file diff --git a/src/app/authentication/signup/signup.component.ts b/src/app/authentication/signup/signup.component.ts index 9a53727ad..c2ce4d1e8 100644 --- a/src/app/authentication/signup/signup.component.ts +++ b/src/app/authentication/signup/signup.component.ts @@ -1,34 +1,119 @@ -import { Component, OnInit } from '@angular/core'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { FormGroup, FormControl } from '@angular/forms'; import { Router } from '@angular/router'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; import { SmartHarvesterUser } from 'src/app/user/model/user'; +import { environment } from 'src/environments/environment'; import { AuthService } from '../services/auth.service'; +import { TokenStorageService } from '../services/token-storage.service'; +import { F2DSResponse } from '../signin/signin.component'; @Component({ selector: 'app-signup', templateUrl: './signup.component.html', styleUrls: ['./signup.component.scss'] }) -export class SignupComponent implements OnInit { +export class SignupComponent implements OnInit, OnDestroy { - isSubmitted = false; - isLoggedIn = false; + isSubmitted = false; + isRegistred = false; isLoginFailed = false; errorMessage = ''; showPassword = false; user: SmartHarvesterUser = new SmartHarvesterUser(); + userFDP: SmartHarvesterUser = new SmartHarvesterUser();$ + private _isDead = new Subject(); + + + constructor(private authService: AuthService, private router: Router, private storageService: TokenStorageService, private http: HttpClient) { + + } - - constructor(private authService: AuthService, private router: Router) { } ngOnInit(): void { + const httpOptions = { + headers: new HttpHeaders({ + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + this.authService.getToken() + }) + }; + this.http.get(environment.smartharvesterUrl + '/harvester/api/username', httpOptions) + .pipe(takeUntil(this._isDead)) + .subscribe( + data => { + this.user.email = data['principal']['userInfo']['email']; + this.user.lastName = data['principal']['userInfo']['familyName']; + this.user.firstName = data['principal']['userInfo']['givenName']; + this.storageService.saveUser(this.user); + this.userFDP = this.user; + }, + err => console.log(err.error.message), + () => { + this.http.get(`${environment.smartharvesterUrl}/harvester/api/user/${this.user.email}`, httpOptions) + .pipe(takeUntil(this._isDead)) + .subscribe( + (resp) => { + console.log(resp) + if (resp) { + this.isRegistred = true; + } + }) + }); } - - + onSubmit() { + this.authService.FdpSignUp(this.userFDP) + .pipe(takeUntil(this._isDead)) + .subscribe( + data => {console.log(data) }, + err => { this.errorMessage = err.error.message }, + () => { + this.authService.getFdpToken(this.userFDP.email, this.userFDP.password) + .pipe(takeUntil(this._isDead)) + .subscribe( + (resp: F2DSResponse) => { this.storageService.saveTokenFDP(resp.token) }, + err => this.errorMessage = err.error.message, + () => { this.router.navigate(['/dashboard']) } + ); + }); + } - + onSubmitResgistred() { + this.authService.getFdpToken(this.userFDP.email, this.userFDP.password) + .pipe(takeUntil(this._isDead)) + .subscribe( + (resp: F2DSResponse) => { this.storageService.saveTokenFDP(resp.token) }, + err => this.errorMessage = err.error.message, + () => { this.router.navigate(['/dashboard']) } + ); + } + + logout() { + this.authService.logout().subscribe( + value => this.router.navigateByUrl('/login') + ); + } + + getInputType() { + if (this.showPassword) { + return 'text'; + } + return 'password'; + } + + toggleShowPassword() { + this.showPassword = !this.showPassword; + } + + + + ngOnDestroy(): void { + this._isDead.next(); + } } diff --git a/src/app/authentication/validators/confirm-validator.directive.spec.ts b/src/app/authentication/validators/confirm-validator.directive.spec.ts new file mode 100644 index 000000000..445b99cbc --- /dev/null +++ b/src/app/authentication/validators/confirm-validator.directive.spec.ts @@ -0,0 +1,8 @@ +import { ConfirmValidatorDirective } from './confirm-validator.directive'; + +describe('ConfirmValidatorDirective', () => { + it('should create an instance', () => { + const directive = new ConfirmValidatorDirective(); + expect(directive).toBeTruthy(); + }); +}); diff --git a/src/app/authentication/validators/confirm-validator.directive.ts b/src/app/authentication/validators/confirm-validator.directive.ts new file mode 100644 index 000000000..ebf84d5cd --- /dev/null +++ b/src/app/authentication/validators/confirm-validator.directive.ts @@ -0,0 +1,39 @@ +import { Attribute, Directive } from '@angular/core'; +import { AbstractControl, NG_VALIDATORS, ValidationErrors, Validator } from '@angular/forms'; + +@Directive({ + selector: '[compare-password]', + providers: [{provide: NG_VALIDATORS, useExisting: ConfirmValidatorDirective, multi: true}] +}) +export class ConfirmValidatorDirective implements Validator{ + + constructor(@Attribute('compare-password') public comparer: string, + @Attribute('parent') public parent: string) { } + validate(control: AbstractControl): ValidationErrors { + const e = control.root.get(this.comparer); + + if (e && control.value !== e.value && !this.isParent) { + return {compare: true}; + } + + if (e && control.value === e.value && this.isParent) { + delete e.errors['compare']; + if (!Object.keys(e.errors).length) { + e.setErrors(null); + } + } + + if (e && control.value !== e.value && this.isParent) { + e.setErrors({compare: true}); + } + } + + private get isParent() { + if (!this.parent) { + return false; + } + return this.parent === 'true' ? true : false; + } + + +} diff --git a/src/app/dashboard/dashboard.component.html b/src/app/dashboard/dashboard.component.html index 4f41768c3..0b462b964 100644 --- a/src/app/dashboard/dashboard.component.html +++ b/src/app/dashboard/dashboard.component.html @@ -8,7 +8,7 @@ <!--User badge--> - <nb-user style="white-space: pre;" + <nb-user style="margin-right: 10px;" name="{{user.firstName}}" title="{{user.lastName}}" [nbContextMenu]="menuItems" diff --git a/src/app/dashboard/dashboard.component.ts b/src/app/dashboard/dashboard.component.ts index 120b602e2..84e9f9080 100644 --- a/src/app/dashboard/dashboard.component.ts +++ b/src/app/dashboard/dashboard.component.ts @@ -75,26 +75,16 @@ export class DashboardComponent implements OnInit { constructor(private readonly sidebarService: NbSidebarService, private authService: AuthService, private tokeService: TokenStorageService, private route: Router, private http: HttpClient) { } + ngOnInit(): void { - const httpOptions = { - headers: new HttpHeaders({ - 'Accept': 'application/json', - 'Content-Type': 'application/json', - 'Authorization': 'Bearer ' + this.authService.getToken() - }) - }; - this.http.get(environment.smartharvesterUrl + '/harvester/api/username', httpOptions).subscribe(data => { - this.user.email = data['principal']['userInfo']['email']; - this.user.lastName = data['principal']['userInfo']['familyName']; - this.user.firstName = data['principal']['userInfo']['givenName']; - }) + this.routerUrl = this.route.url; this.route.events.subscribe(event => { if (event instanceof NavigationStart) { this.routerUrl = event.url; } }); - + this.user = this.tokeService.getUser(); } @@ -107,6 +97,6 @@ export class DashboardComponent implements OnInit { this.authService.logout().subscribe( value => this.route.navigateByUrl('/login') ); - + this.tokeService.removeToken(); } } diff --git a/src/app/settingsmartapi/settingsmartapi.component.html b/src/app/settingsmartapi/settingsmartapi.component.html deleted file mode 100644 index 29fd9f652..000000000 --- a/src/app/settingsmartapi/settingsmartapi.component.html +++ /dev/null @@ -1,15 +0,0 @@ - -<form [formGroup]="Form" (ngSubmit)="SaveSmartapiSetting()"> - - <div class="form-group"> - <label>SmartApi Url - <input matInput placeholder="url http://" type="text" class="form-control" formControlName="smartapiurl" required> - </label> - </div> - - <div> - <br> - <button type="submit" class="btn btn-primary">Save SmartHarvester setting</button> - </div> - </form> - \ No newline at end of file diff --git a/src/app/settingsmartapi/settingsmartapi.component.scss b/src/app/settingsmartapi/settingsmartapi.component.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/app/settingsmartapi/settingsmartapi.component.spec.ts b/src/app/settingsmartapi/settingsmartapi.component.spec.ts deleted file mode 100644 index 3008aca1b..000000000 --- a/src/app/settingsmartapi/settingsmartapi.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { SettingsmartapiComponent } from './settingsmartapi.component'; - -describe('SettingsmartapiComponent', () => { - let component: SettingsmartapiComponent; - let fixture: ComponentFixture<SettingsmartapiComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ SettingsmartapiComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(SettingsmartapiComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/settingsmartapi/settingsmartapi.component.ts b/src/app/settingsmartapi/settingsmartapi.component.ts deleted file mode 100644 index 7d5430d55..000000000 --- a/src/app/settingsmartapi/settingsmartapi.component.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { AppConfiguration } from '../AppConfiguration'; -import { HttpClient } from '@angular/common/http'; -import { FileSaverService } from 'ngx-filesaver'; -import { FormControl} from '@angular/forms'; -import { FormGroup} from '@angular/forms'; -import { Observable } from 'rxjs'; -import { environment } from 'src/environments/environment.prod'; - -@Component({ - selector: 'app-settingsmartapi', - templateUrl: './settingsmartapi.component.html', - styleUrls: ['./settingsmartapi.component.scss'] -}) -export class SettingsmartapiComponent implements OnInit { - - - Form = new FormGroup({ - smartapiurl: new FormControl(), -}); - - constructor( - private appConfig: AppConfiguration, - private http: HttpClient, - private _FileSaverService: FileSaverService - ) {} - - ngOnInit() { - this.Form.setValue({ - smartapiurl: this.appConfig.smartapiurl - }); - } - - - SaveSmartapiSetting() { - let data: string; - data ='\ - {\n\ - "fdpurl": "'+ this.appConfig.fdpurl +'", \n\ - "fdpemail": "'+ this.appConfig.fdpemail +'", \n\ - "fdppassword": "'+ this.appConfig.fdppassword +'", \n\ - "elasticurl": "'+ this.appConfig.elasticurl +'", \n\ - "smartapiurl": "'+ this.Form.value.smartapiurl +'" \n\ - }' - console.log(data); - return this.http.post(environment.fdpUrl+"/setting", data,{responseType: 'text'}).subscribe( (r)=>{console.log(r)}) ; - }; - -} -- GitLab