From fefbff8a722c83d6704001e90083bb45d0b9e2b3 Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Thu, 25 Nov 2021 17:07:38 +0100 Subject: [PATCH 1/8] wip --- src/app/AppConfiguration.ts | 22 +++-- src/app/app-routing.module.ts | 17 ++-- src/app/app.module.ts | 15 ++-- .../admin/account.admin.component.ts | 4 +- .../interceptor/auth.interceptor.ts | 26 ------ .../interceptor/authHeader.interceptor.ts | 19 +++++ src/app/authentication/services/auth.guard.ts | 17 ++-- .../authentication/services/auth.service.ts | 67 +++++++--------- .../services/token-storage.service.ts | 14 +++- .../signin/signin.component.html | 80 ++++--------------- .../authentication/signin/signin.component.ts | 52 +----------- .../signup/signup.component.html | 2 +- .../authentication/signup/signup.component.ts | 20 +---- src/app/callback/callback.component.html | 1 + src/app/callback/callback.component.scss | 0 src/app/callback/callback.component.spec.ts | 25 ++++++ src/app/callback/callback.component.ts | 23 ++++++ src/app/dashboard/dashboard.component.html | 6 +- src/app/dashboard/dashboard.component.ts | 25 ++++-- .../services/publish-repository.service.ts | 3 +- src/app/services/catalog.service.ts | 3 +- src/app/stats/stats.component.html | 21 ++--- src/app/user/model/user.ts | 13 +-- 23 files changed, 214 insertions(+), 261 deletions(-) delete mode 100644 src/app/authentication/interceptor/auth.interceptor.ts create mode 100644 src/app/authentication/interceptor/authHeader.interceptor.ts create mode 100644 src/app/callback/callback.component.html create mode 100644 src/app/callback/callback.component.scss create mode 100644 src/app/callback/callback.component.spec.ts create mode 100644 src/app/callback/callback.component.ts diff --git a/src/app/AppConfiguration.ts b/src/app/AppConfiguration.ts index 6c31cb6ca..5750c0352 100644 --- a/src/app/AppConfiguration.ts +++ b/src/app/AppConfiguration.ts @@ -1,6 +1,7 @@ import { Injectable } from "@angular/core"; import { HttpClient } from '@angular/common/http'; import { environment } from 'src/environments/environment.prod'; +import { TokenStorageService } from "./authentication/services/token-storage.service"; @Injectable() export class AppConfiguration { @@ -10,14 +11,19 @@ export class AppConfiguration { fdppassword: string; elasticurl: string; smartapiurl: string; - - constructor(private httpClient: HttpClient){}; -public ensureInit(): Promise<any> { - return new Promise((r, e) => { - this.httpClient.get(environment.fdpUrl+"/setting/load").subscribe((content: AppConfiguration) => {Object.assign(this, content);r(this);}, reason => e(reason)); - }); - }; + constructor(private httpClient: HttpClient, private storageService: TokenStorageService) { }; + + public ensureInit(): Promise<any> { + const email = (this.storageService.getUser()).email; + return this.httpClient.get(environment.smartharvesterUrl + "/harvester/api/user/" + email).toPromise().then((resp:Response) => { + if (resp.status === 200 ) { + return true; + } else { + return false; + } + }) + } -} +} diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index a78e3ca46..649b04d31 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -14,6 +14,8 @@ 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'; export interface ICustomRoute extends Route { name?: string; @@ -21,27 +23,20 @@ export interface ICustomRoute extends Route { const routes: ICustomRoute[] = [ - { path: '', redirectTo: '/auth/signin', pathMatch: 'full' }, + { path: '', redirectTo: '/dashboard', pathMatch: 'full' }, + {path: 'callback', component: CallbackComponent}, { path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuardService], children: [ { path: 'simplesearch', component: SearchComponent }, - { path: 'user', component: UserComponent }, { path: 'repository', component: RepositoryComponent }, { path: 'repositoryinfo', component: RepositoryinfoComponent }, { path: 'accessapi', component: AccessapiComponent }, { path: 'stats', component: StatsComponent }, - /* { path: 'settingfdp', component: SettingfdpComponent }, - { path: 'settingsmartharvester', component: SettingsmartapiComponent },*/ { path: 'publishapi', component: PublishApiComponent }, - { path: 'advancedsearch', component: SearchComponent }, + ] }, - { path: 'auth', component: AuthenticationComponent,name:'', - children: [ - { path: 'signup', component: SignupComponent, data: { animation: 'SignUp'} }, - { path: 'signin', component: SigninComponent, data: { animation: 'SignIn'} }, - ] - } + { path: 'login', component: SigninComponent} ] @NgModule({ diff --git a/src/app/app.module.ts b/src/app/app.module.ts index d1e31af8c..03f97eaed 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -24,7 +24,7 @@ import { FormsModule } from '@angular/forms'; import { RepositoryinfoComponent } from './repositoryinfo/repositoryinfo.component'; -import { HttpClientModule, HttpClient } from '@angular/common/http'; +import { HttpClientModule, HttpClient, HTTP_INTERCEPTORS } from '@angular/common/http'; import { FileSaverModule } from 'ngx-filesaver'; import { AppConfiguration } from './AppConfiguration'; import { PublishApiComponent } from './publishapi/publishapi.component'; @@ -44,6 +44,8 @@ import { NbToastrModule } from '@nebular/theme'; import { DatasetsDialogComponent } from './datasets/datasets-dialog/datasets-dialog.component'; import { NgProgressModule } from 'ngx-progressbar'; import { NgProgressHttpModule } from 'ngx-progressbar/http'; +import { AuthHeaderInterceptor } from './authentication/interceptor/authHeader.interceptor'; +import { CallbackComponent } from './callback/callback.component'; @@ -66,6 +68,7 @@ import { NgProgressHttpModule } from 'ngx-progressbar/http'; MappingComponent, FeedbackDialogComponent, DatasetsDialogComponent, + CallbackComponent, ], imports: [ BrowserModule, @@ -110,11 +113,11 @@ import { NgProgressHttpModule } from 'ngx-progressbar/http'; providers: [ AppConfiguration, ParseXmlService, - /*{ - provide: APP_INITIALIZER, - useFactory: AppConfigurationFactory, - deps: [AppConfiguration, HttpClient], multi: true - },*/ + { + provide: HTTP_INTERCEPTORS, + useClass: AuthHeaderInterceptor, + multi: true + } ], bootstrap: [AppComponent] }) diff --git a/src/app/authentication/admin/account.admin.component.ts b/src/app/authentication/admin/account.admin.component.ts index dc713762d..77a838e9f 100644 --- a/src/app/authentication/admin/account.admin.component.ts +++ b/src/app/authentication/admin/account.admin.component.ts @@ -72,8 +72,8 @@ export class AccountAdminComponent implements OnInit { } logout(){ - this.authService.logout(); - this.router.navigateByUrl('/auth/login'); + //this.authService.logout(); + this.router.navigateByUrl('/login'); } toggleSidebar(): boolean { this.sidebarService.toggle(true); diff --git a/src/app/authentication/interceptor/auth.interceptor.ts b/src/app/authentication/interceptor/auth.interceptor.ts deleted file mode 100644 index e1aaa168e..000000000 --- a/src/app/authentication/interceptor/auth.interceptor.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { HTTP_INTERCEPTORS, HttpEvent } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http'; - -import { TokenStorageService } from '../services/token-storage.service'; -import { Observable } from 'rxjs'; - -const TOKEN_HEADER_KEY = 'x-access-token'; - -@Injectable() -export class AuthInterceptor implements HttpInterceptor { - constructor(private token: TokenStorageService) { } - - intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { - let authReq = req; - const token = this.token.getToken(); - if (token != null) { - authReq = req.clone({ headers: req.headers.set(TOKEN_HEADER_KEY, token) }); - } - return next.handle(authReq); - } -} - -export const authInterceptorProviders = [ - { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true } -]; \ No newline at end of file diff --git a/src/app/authentication/interceptor/authHeader.interceptor.ts b/src/app/authentication/interceptor/authHeader.interceptor.ts new file mode 100644 index 000000000..40cf012c5 --- /dev/null +++ b/src/app/authentication/interceptor/authHeader.interceptor.ts @@ -0,0 +1,19 @@ +import { HTTP_INTERCEPTORS, HttpEvent } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http'; + +import { Observable } from 'rxjs'; + +const TOKEN_HEADER_KEY = 'x-access-token'; + +@Injectable() +export class AuthHeaderInterceptor implements HttpInterceptor { + constructor() { } + + intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { + let authReq = req + + return next.handle(authReq); + } +} + diff --git a/src/app/authentication/services/auth.guard.ts b/src/app/authentication/services/auth.guard.ts index f75eb5220..107be570c 100644 --- a/src/app/authentication/services/auth.guard.ts +++ b/src/app/authentication/services/auth.guard.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router'; +import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router } from '@angular/router'; import { Observable } from 'rxjs'; import { AuthService } from './auth.service'; @@ -7,12 +7,19 @@ import { AuthService } from './auth.service'; providedIn: 'root' }) export class AuthGuardService implements CanActivate { - constructor(private authService: AuthService){} - + constructor(private authService: AuthService, private router: Router) { } + canActivate( _next: ActivatedRouteSnapshot, _state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree { - return this.authService.isLoggedIn(); + + if (this.authService.isLoggedIn()) { + return true; + } + this.router.navigate(['/login']); + return false; + + } - + } diff --git a/src/app/authentication/services/auth.service.ts b/src/app/authentication/services/auth.service.ts index a4ee7ca60..4b29c553f 100644 --- a/src/app/authentication/services/auth.service.ts +++ b/src/app/authentication/services/auth.service.ts @@ -4,6 +4,8 @@ import { Observable } from 'rxjs'; import { TokenStorageService } from './token-storage.service'; import { AppConfiguration } from 'src/app/AppConfiguration'; import { environment } from 'src/environments/environment'; +import { SmartHarvesterUser } from 'src/app/user/model/user'; +import { Router } from '@angular/router'; @@ -20,57 +22,50 @@ const httpOptions = { }) export class AuthService { + private authorizationEndpoint = '/oauth2/authorization/oidc'; + private tokenEndpoint = '/login/oauth2/code/oidc'; + private baseUrl = environment.smartharvesterUrl; + private tokenKey = 'auth-token;' - constructor(private http: HttpClient, private tokenService: TokenStorageService, private appConfig: AppConfiguration) { } + httpOptions = { + headers: new HttpHeaders({ + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Authorization': 'Bearer ' + this.getToken() + }) + }; + constructor(private http: HttpClient, private tokenService: TokenStorageService, private appConfig: AppConfiguration, private router: Router) { } - login(credentials): Observable<any> { - let data: any - data = this.http.post(AUTH_API + '/signin', { - email: credentials.email, - password: credentials.password - }, httpOptions); - return data; - } - register(user): Observable<any> { - return this.http.post(AUTH_API + '/signup', { - firstName: user.firstName, - lastName: user.lastName, - email: user.email, - password: user.password - }, httpOptions); + login() { + + window.location.href = this.baseUrl + this.authorizationEndpoint; } - - update(user): Observable<any> { - return this.http.post(AUTH_API + '/user', { - catalog_id: user.cat_id - }, httpOptions); + updateToken(token) { + this.tokenService.saveTokenSmartHarveser(token) } + fetchToken(code: string, state: string): Observable<any> { + return this.http.get(`${this.baseUrl}${this.tokenEndpoint}?code=${code}&state=${state}`); + } - getF2DSAuthToken(credentials): Observable<any> { - return this.http.post(FDP_URL + '/tokens', { - email: credentials.email, - password: credentials.password - }, httpOptions); + getToken() { + return this.tokenService.getToken(); } - public isLoggedIn() { - return this.tokenService.getToken() !== null; + isLoggedIn(): boolean { + const token = this.getToken(); + return (token !== null); } - public logout() { - const config = { - headers: new HttpHeaders({ - 'Content-Type': 'application/x-www-form-urlencoded' - }) - }; - this.tokenService.signOut(); - return this.http.post(`${AUTH_API}/logout`, null, config); + + + logout() { + return this.http.post(this.baseUrl + '/logout', this.getToken(), this.httpOptions); } } diff --git a/src/app/authentication/services/token-storage.service.ts b/src/app/authentication/services/token-storage.service.ts index 00b7d5f52..e496c4843 100644 --- a/src/app/authentication/services/token-storage.service.ts +++ b/src/app/authentication/services/token-storage.service.ts @@ -15,11 +15,16 @@ export class TokenStorageService { window.sessionStorage.clear(); } - public saveToken(token: string,f2dsToken:string): void { + public saveTokenSmartHarveser(SmartHarvesterToken: string): void { window.sessionStorage.removeItem(TOKEN_KEY); + + window.sessionStorage.setItem(TOKEN_KEY, SmartHarvesterToken); + + } + + public saveTokenFDP(FdpToken: string): void { window.sessionStorage.removeItem(FDP_TOKEN_KEY); - window.sessionStorage.setItem(TOKEN_KEY, token); - window.sessionStorage.setItem(FDP_TOKEN_KEY, f2dsToken); + window.sessionStorage.setItem(FDP_TOKEN_KEY, FdpToken); } public getToken(): string { @@ -38,8 +43,9 @@ export class TokenStorageService { return JSON.parse(sessionStorage.getItem(USER_KEY)); } public removeToken(){ - window.localStorage.removeItem(TOKEN_KEY); + window.sessionStorage.removeItem(TOKEN_KEY); window.sessionStorage.removeItem(FDP_TOKEN_KEY); + window.sessionStorage.removeItem(USER_KEY); } diff --git a/src/app/authentication/signin/signin.component.html b/src/app/authentication/signin/signin.component.html index da87c7586..ac675e9a9 100644 --- a/src/app/authentication/signin/signin.component.html +++ b/src/app/authentication/signin/signin.component.html @@ -1,65 +1,17 @@ - <div style="display: flex;justify-content: center;"> - <nb-card status="info" size="small" style="width: 24em;"> - <nb-card-header style="text-align: center;">Welcome to the F2DS API register</nb-card-header> - <nb-card-body class="example-items-col" style="overflow: hidden;"> - - <div class="col-md-12"> - <div class="card card-container"> - <form *ngIf="!isLoggedIn" name="formGroup" (ngSubmit)="f.form.valid && onSubmit()" #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)]="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]="getInputType()" class="form-control" name="password" - [(ngModel)]="user.password" required minlength="6" #password="ngModel" /> - <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="info" class="btn btn-primary btn-block"> - Login - </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;"> - Don't have an account ? <a class="text-link" routerLink="../signup">Register</a> - </section> - <!----> - <div class="alert alert-success" *ngIf="isLoggedIn"> - Logged in as - </div> - </div> - </div> - </nb-card-body> - </nb-card> +<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> + <div style="float: right;"> + <button (click)="login()" status="primary" nbButton>login</button> </div> + + + </nb-layout-header> + + + + <nb-layout-footer>Contact us</nb-layout-footer> + +</nb-layout> + diff --git a/src/app/authentication/signin/signin.component.ts b/src/app/authentication/signin/signin.component.ts index 63f28e0f3..806e82e10 100644 --- a/src/app/authentication/signin/signin.component.ts +++ b/src/app/authentication/signin/signin.component.ts @@ -21,63 +21,19 @@ export class SigninComponent implements OnInit { isLoginFailed = false; errorMessage = ''; showPassword = false; - user: SmartHarvesterUser = new SmartHarvesterUser({}); + user: SmartHarvesterUser = new SmartHarvesterUser(); constructor(private authService: AuthService, private router: Router, private tokenStorage: TokenStorageService) { } ngOnInit(): void { - if (this.tokenStorage.getToken()) { - // Uncomment line to avoid re-authentication if token is still valid - //this.isLoggedIn = true; - } } - //get formControls() { return this.formGroup.controls; } - - onSubmit(): void { - - - - this.authService.login(this.user).subscribe( - data => { - this.authService.getF2DSAuthToken(this.user).subscribe((response:F2DSResponse) => { - if (response) this.f2dsToken = response.token; - console.log("F2ds token is : ", this.f2dsToken); - this.tokenStorage.saveToken(data.accessToken, this.f2dsToken); - this.tokenStorage.saveUser(data); - - this.isLoginFailed = false; - this.isLoggedIn = true; - console.log("User data : ", data) - this.router.navigateByUrl('/dashboard'); - }) - - //this.reloadPage(); - }, - err => { - this.errorMessage = err.error.message; - console.error("Error : ", this.errorMessage) - this.isLoginFailed = true; - } - ); - } - - reloadPage(): void { - window.location.reload(); - } - - - getInputType() { - if (this.showPassword) { - return 'text'; - } - return 'password'; + login() { + this.authService.login(); } - toggleShowPassword() { - this.showPassword = !this.showPassword; - } + } diff --git a/src/app/authentication/signup/signup.component.html b/src/app/authentication/signup/signup.component.html index 5b59546cf..5db272cfe 100644 --- a/src/app/authentication/signup/signup.component.html +++ b/src/app/authentication/signup/signup.component.html @@ -5,7 +5,7 @@ <div class="col-md-12"> <div class="card card-container"> - <form *ngIf="!isLoggedIn" name="formGroup" (ngSubmit)="f.form.valid && onSubmit()" #f="ngForm" + <form *ngIf="!isLoggedIn" name="formGroup" (ngSubmit)="f.form.valid " #f="ngForm" novalidate> <div class="form-group"> <label for="firstName">First Name</label> diff --git a/src/app/authentication/signup/signup.component.ts b/src/app/authentication/signup/signup.component.ts index 8a757692f..9a53727ad 100644 --- a/src/app/authentication/signup/signup.component.ts +++ b/src/app/authentication/signup/signup.component.ts @@ -16,7 +16,7 @@ export class SignupComponent implements OnInit { isLoginFailed = false; errorMessage = ''; showPassword = false; - user: SmartHarvesterUser = new SmartHarvesterUser({}); + user: SmartHarvesterUser = new SmartHarvesterUser(); constructor(private authService: AuthService, private router: Router) { } @@ -24,24 +24,10 @@ export class SignupComponent implements OnInit { ngOnInit(): void { } - onSubmit(): void { + - this.authService.register(this.user).subscribe( - data => { - console.log("Response : ", data); - }, - err => { - this.errorMessage = err.error.message; - this.isLoginFailed = true; - }, - () => this.router.navigateByUrl('/auth/signin') - ); - } - - reloadPage(): void { - window.location.reload(); - } + diff --git a/src/app/callback/callback.component.html b/src/app/callback/callback.component.html new file mode 100644 index 000000000..000c31f82 --- /dev/null +++ b/src/app/callback/callback.component.html @@ -0,0 +1 @@ +Redirecting... diff --git a/src/app/callback/callback.component.scss b/src/app/callback/callback.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/callback/callback.component.spec.ts b/src/app/callback/callback.component.spec.ts new file mode 100644 index 000000000..848b5e3ad --- /dev/null +++ b/src/app/callback/callback.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CallbackComponent } from './callback.component'; + +describe('CallbackComponent', () => { + let component: CallbackComponent; + let fixture: ComponentFixture<CallbackComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CallbackComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CallbackComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/callback/callback.component.ts b/src/app/callback/callback.component.ts new file mode 100644 index 000000000..072e023da --- /dev/null +++ b/src/app/callback/callback.component.ts @@ -0,0 +1,23 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { AuthService } from '../authentication/services/auth.service'; + +@Component({ + selector: 'app-callback', + templateUrl: './callback.component.html', + styleUrls: ['./callback.component.scss'] +}) +export class CallbackComponent implements OnInit { + + constructor(private route: ActivatedRoute, private router: Router, private authService: AuthService) { } + + ngOnInit(): void { + this.route.queryParams.subscribe(p => { + this.authService.fetchToken(p.code, p.state).subscribe(data => { + this.authService.updateToken(data.accessToken); + this.router.navigate(['/dashboard']); + }) + }) + } + +} diff --git a/src/app/dashboard/dashboard.component.html b/src/app/dashboard/dashboard.component.html index 57e29c2f9..4f41768c3 100644 --- a/src/app/dashboard/dashboard.component.html +++ b/src/app/dashboard/dashboard.component.html @@ -9,13 +9,13 @@ <!--User badge--> <nb-user style="white-space: pre;" - name="{{userData.firstName}}" - title="{{userData.lastName}}" + name="{{user.firstName}}" + title="{{user.lastName}}" [nbContextMenu]="menuItems" nbContextMenuTag="my-context-menu" badgePosition="right"> </nb-user> - <button (click)="logout()" nbContextMenuPlacement="right" outline nbButton>Logout</button> + <button (click)="logout()" nbContextMenuPlacement="right" status="danger" outline nbButton>Logout</button> </nb-layout-header> diff --git a/src/app/dashboard/dashboard.component.ts b/src/app/dashboard/dashboard.component.ts index 2dab938b9..120b602e2 100644 --- a/src/app/dashboard/dashboard.component.ts +++ b/src/app/dashboard/dashboard.component.ts @@ -1,6 +1,8 @@ +import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, NavigationStart, Router } from '@angular/router'; import { NbMenuItem, NbSidebarService } from '@nebular/theme'; +import { environment } from 'src/environments/environment'; import { AuthService } from '../authentication/services/auth.service'; import { TokenStorageService } from '../authentication/services/token-storage.service'; import { SmartHarvesterUser } from '../user/model/user'; @@ -12,7 +14,7 @@ import { SmartHarvesterUser } from '../user/model/user'; }) export class DashboardComponent implements OnInit { - userData: SmartHarvesterUser; + user: SmartHarvesterUser = new SmartHarvesterUser(); routerUrl: string; menuItems: NbMenuItem[] = [ { @@ -72,18 +74,27 @@ export class DashboardComponent implements OnInit { constructor(private readonly sidebarService: NbSidebarService, private authService: AuthService, - private tokeService: TokenStorageService, private route: Router) { } + 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; } }); - let loggedIn = this.authService.isLoggedIn; - if (loggedIn) { - this.userData = this.tokeService.getUser(); - } + } @@ -94,7 +105,7 @@ export class DashboardComponent implements OnInit { logout() { this.authService.logout().subscribe( - value => this.route.navigateByUrl('/auth/signin') + value => this.route.navigateByUrl('/login') ); } diff --git a/src/app/repository/services/publish-repository.service.ts b/src/app/repository/services/publish-repository.service.ts index f562c25da..ad49bad81 100644 --- a/src/app/repository/services/publish-repository.service.ts +++ b/src/app/repository/services/publish-repository.service.ts @@ -5,6 +5,7 @@ import { AppConfiguration } from 'src/app/AppConfiguration'; import { AuthService } from 'src/app/authentication/services/auth.service'; import { environment } from 'src/environments/environment'; import { TokenStorageService } from 'src/app/authentication/services/token-storage.service'; +import { SmartHarvesterUser } from 'src/app/user/model/user'; interface PersistentUrlResponse { persistentUrl: string; @@ -57,7 +58,7 @@ export class PublishRepositoryService { async addUserCatalog(catId: string): Promise<any> { const tokenResponse = this.tokenService.getToken(); - const user = this.tokenService.getUser(); + const user: SmartHarvesterUser = this.tokenService.getUser(); return this.http.post(this.smartApiUrl + '/user/' + user.email + '/catalogs', catId, { headers: { Authorization: 'Bearer ' + tokenResponse } }) diff --git a/src/app/services/catalog.service.ts b/src/app/services/catalog.service.ts index 6c90a711a..2f0d632cb 100644 --- a/src/app/services/catalog.service.ts +++ b/src/app/services/catalog.service.ts @@ -2,6 +2,7 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { environment } from 'src/environments/environment'; import { TokenStorageService } from '../authentication/services/token-storage.service'; +import { SmartHarvesterUser } from '../user/model/user'; export interface FdpApiResponseItem { subject: { @@ -44,7 +45,7 @@ export class CatalogService { } getAllCatalogId() { - const user = this.tokenService.getUser(); + const user: SmartHarvesterUser = this.tokenService.getUser(); return this.http.get<{ catId: string, uuid: string }[]>(this.smartApiUrl + '/user/' + user.email + '/catalogs', this.httpOptionsSmartHarvester); } diff --git a/src/app/stats/stats.component.html b/src/app/stats/stats.component.html index b745aa639..77e578ad5 100644 --- a/src/app/stats/stats.component.html +++ b/src/app/stats/stats.component.html @@ -1,12 +1,13 @@ - <div class="w3-container"> - <table class="w3-table-all w3-card-4"> - <thead style="background-color: #3366ff"> - <th style="text-align: center;">Number of Catalogs</th> - <th style="text-align: center;">Number of Datasets</th> - </thead> - <tbody > - <tr><td *ngFor="let stat of stats" style="text-align: center;"><strong>{{stat}}</strong></td></tr> + <table class="w3-table-all w3-card-4"> + <thead style="background-color: #3366ff"> + <th style="text-align: center;">Number of Catalogs</th> + <th style="text-align: center;">Number of Datasets</th> + </thead> + <tbody> + <tr> + <td *ngFor="let stat of stats" style="text-align: center;"><strong>{{stat}}</strong></td> + </tr> </tbody> - </table> - </div> \ No newline at end of file + </table> +</div> \ No newline at end of file diff --git a/src/app/user/model/user.ts b/src/app/user/model/user.ts index fbd9c6fd1..28db83f6d 100644 --- a/src/app/user/model/user.ts +++ b/src/app/user/model/user.ts @@ -1,18 +1,9 @@ export class SmartHarvesterUser { public email: string; - public password: string; + public password?: string; public firstName?: string; public lastName?: string; public passwordConfirm?: string; - public id?: "5fbfb86b688c8577c7b8aeff" - public token?: "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZXN0QGNpbmVzLmZyIiwiaWF0IjoxNjA2ODQzNjkwLCJleHAiOjE2MDY5MzAwOTB9.UcmKMRmIEyNLW_kCEEI83uMuDG3Lgf5BKeAHvOhhjiFsV-8keKXxy5VLyHR4LvX_7vZL9WN_H_49-sLxGFTJyQ" - public tokenType?: "Bearer"; + - constructor(params: any) { - Object.assign(this, params); - } - - isAnonyme(): boolean { - return this.email === undefined; - } } -- GitLab 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 2/8] 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 From 58ece61a398ea87352933a2336fd30cf2478be94 Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Fri, 26 Nov 2021 15:35:23 +0100 Subject: [PATCH 3/8] bug fix --- .../signup/signup.component.html | 7 ++-- .../authentication/signup/signup.component.ts | 8 +++-- src/app/callback/callback.component.html | 7 +++- src/app/dashboard/dashboard.component.ts | 34 ++++++++++++++++--- .../datasets/services/dataset-crud.service.ts | 6 ++-- src/app/mapping/mapping.component.ts | 13 +++---- src/app/mapping/service/mapping.service.ts | 11 ++++-- src/app/publishapi/publishapi.component.html | 2 +- src/app/publishapi/publishapi.component.ts | 1 + .../publishapi/services/openapi-service.ts | 6 ++-- 10 files changed, 66 insertions(+), 29 deletions(-) diff --git a/src/app/authentication/signup/signup.component.html b/src/app/authentication/signup/signup.component.html index 976b3937b..c5729560a 100644 --- a/src/app/authentication/signup/signup.component.html +++ b/src/app/authentication/signup/signup.component.html @@ -77,7 +77,7 @@ <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"/> + [(ngModel)]="userFDP.password" required minlength="6" #password="ngModel" compare-password="passwordConfirm" parent="true"/> <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'"> @@ -86,6 +86,7 @@ </nb-form-field> <!-- Password error--> <div class="alert alert-danger" role="alert" *ngIf="f.submitted && password.invalid"> + fdfdf <div *ngIf="password.errors.required">Password is required</div> <div *ngIf="password.errors.minlength"> Password must be at least 6 characters @@ -116,7 +117,7 @@ <br> <div class="form-group" style="text-align: center;"> - <button nbButton status="success" class="btn btn-primary btn-block"> + <button nbButton status="success" class="btn btn-primary btn-block" > Sign Up </button> </div> @@ -177,7 +178,7 @@ </div> <br> <div class="form-group" style="text-align: center;"> - <button nbButton status="success" class="btn btn-primary btn-block"> + <button nbButton status="success" class="btn btn-primary btn-block" > Sign In </button> </div> diff --git a/src/app/authentication/signup/signup.component.ts b/src/app/authentication/signup/signup.component.ts index c2ce4d1e8..3955dc577 100644 --- a/src/app/authentication/signup/signup.component.ts +++ b/src/app/authentication/signup/signup.component.ts @@ -56,7 +56,6 @@ export class SignupComponent implements OnInit, OnDestroy { .pipe(takeUntil(this._isDead)) .subscribe( (resp) => { - console.log(resp) if (resp) { this.isRegistred = true; } @@ -82,6 +81,7 @@ export class SignupComponent implements OnInit, OnDestroy { } onSubmitResgistred() { + console.log('submit') this.authService.getFdpToken(this.userFDP.email, this.userFDP.password) .pipe(takeUntil(this._isDead)) .subscribe( @@ -93,9 +93,11 @@ export class SignupComponent implements OnInit, OnDestroy { logout() { this.authService.logout().subscribe( - value => this.router.navigateByUrl('/login') + value => this.router.navigateByUrl('/login'), + err => console.log(err), + () => this.storageService.removeToken() ); - + } getInputType() { diff --git a/src/app/callback/callback.component.html b/src/app/callback/callback.component.html index 000c31f82..abaef7bf0 100644 --- a/src/app/callback/callback.component.html +++ b/src/app/callback/callback.component.html @@ -1 +1,6 @@ -Redirecting... + +<nb-card [nbSpinner]="true" nbSpinnerSize="giant" nbSpinnerStatus="primary" size="large"> + <nb-card-body> + Redirecting... + </nb-card-body> + </nb-card> diff --git a/src/app/dashboard/dashboard.component.ts b/src/app/dashboard/dashboard.component.ts index 84e9f9080..abde7a53c 100644 --- a/src/app/dashboard/dashboard.component.ts +++ b/src/app/dashboard/dashboard.component.ts @@ -2,6 +2,8 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, NavigationStart, Router } from '@angular/router'; import { NbMenuItem, NbSidebarService } from '@nebular/theme'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; import { environment } from 'src/environments/environment'; import { AuthService } from '../authentication/services/auth.service'; import { TokenStorageService } from '../authentication/services/token-storage.service'; @@ -16,6 +18,7 @@ export class DashboardComponent implements OnInit { user: SmartHarvesterUser = new SmartHarvesterUser(); routerUrl: string; + private _isDead = new Subject(); menuItems: NbMenuItem[] = [ { title: 'Home', @@ -77,15 +80,34 @@ export class DashboardComponent implements OnInit { private tokeService: TokenStorageService, private route: Router, private http: HttpClient) { } ngOnInit(): void { - this.routerUrl = this.route.url; this.route.events.subscribe(event => { if (event instanceof NavigationStart) { this.routerUrl = event.url; } }); - this.user = this.tokeService.getUser(); - + if (this.tokeService.getUser() === null) { + 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.tokeService.saveUser(this.user); + }, + err => console.log(err.error.message), + () => {}); + } else { + this.user = this.tokeService.getUser(); + } } toggleSidebar(): boolean { @@ -95,8 +117,10 @@ export class DashboardComponent implements OnInit { logout() { this.authService.logout().subscribe( - value => this.route.navigateByUrl('/login') + value => this.route.navigateByUrl('/login'), + err => console.log(err), + () => this.tokeService.removeToken() ); - this.tokeService.removeToken(); + } } diff --git a/src/app/datasets/services/dataset-crud.service.ts b/src/app/datasets/services/dataset-crud.service.ts index 838406e5e..b2b96b616 100644 --- a/src/app/datasets/services/dataset-crud.service.ts +++ b/src/app/datasets/services/dataset-crud.service.ts @@ -34,7 +34,7 @@ export class DatasetCrudService { get tokenHarvesterHeader() { return { headers: new HttpHeaders({ - Authorization: 'Bearer ' + this.sessionStorage.getUser().token + Authorization: 'Bearer ' + this.sessionStorage.getToken() }) }; } @@ -170,7 +170,7 @@ export class DatasetCrudService { } getRequestHistorical(catId: string) { - if (this.sessionStorage.getUser().token == null) { + if (this.sessionStorage.getToken() == null) { return of([]); } @@ -179,7 +179,7 @@ export class DatasetCrudService { } createRequestHistorical(catId: string, request: string) { - if (this.sessionStorage.getUser().token == null) { + if (this.sessionStorage.getToken() == null) { return of(); } diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts index 2116435c6..cccf2822d 100644 --- a/src/app/mapping/mapping.component.ts +++ b/src/app/mapping/mapping.component.ts @@ -1,7 +1,7 @@ import { HttpResponse } from '@angular/common/http'; -import { ChangeDetectorRef, Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { ChangeDetectorRef, Component, Input, OnInit, ViewChild } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { Router } from '@angular/router'; @@ -23,7 +23,7 @@ import { MappingService } from './service/mapping.service'; templateUrl: './mapping.component.html', styleUrls: ['./mapping.component.scss'] }) -export class MappingComponent implements OnInit, OnDestroy { +export class MappingComponent implements OnInit { addDistribution = false check = false; @@ -220,7 +220,7 @@ export class MappingComponent implements OnInit, OnDestroy { const requestPromises: Promise<any>[] = []; for (let i = 0; i < this.urls.length; i++) { - let requestPromise = this.dataSetService.createDatasetXml(this.urls[i]).then((resp: HttpResponse<any>) => { + let requestPromise = this.dataSetService.createDatasetXml(this.itemsdataset[i]).then((resp: HttpResponse<any>) => { if (resp.status.toString().startsWith('2')) { postedDatastes.push(this.ids[i]); } else { @@ -473,6 +473,7 @@ export class MappingComponent implements OnInit, OnDestroy { this.mappingService.downloadFile(datasetPathArray); + this.mappingService.postFile(datasetPathArray, this.catalogId).subscribe(); } openFileInputDialog(): void { @@ -507,7 +508,7 @@ export class MappingComponent implements OnInit, OnDestroy { let distributionPath: ResponseFileTsv[] = []; console.table(paths) paths.forEach(path => { - (path.object_category.includes('dataset')) ? datasetPath.push(path) : distributionPath.push(path); + (path.object_category.includes('dcat:dataset')) ? datasetPath.push(path) : distributionPath.push(path); }) console.log(datasetPath) @@ -612,10 +613,6 @@ export class MappingComponent implements OnInit, OnDestroy { return this.vocabularies.find((vocabulary: Property) => vocabulary.uri === uri).card; } - ngOnDestroy(): void { - let datasetPathArray = this.createObjectToExport(); - this.mappingService.postFile(datasetPathArray, this.catalogId).subscribe(); - } private getDistributionEmpty(properties: string, datasetId: string): string { return `@prefix dcat: <http://www.w3.org/ns/dcat#>. @prefix dct: <http://purl.org/dc/terms/>. diff --git a/src/app/mapping/service/mapping.service.ts b/src/app/mapping/service/mapping.service.ts index e1c82833a..83213dc93 100644 --- a/src/app/mapping/service/mapping.service.ts +++ b/src/app/mapping/service/mapping.service.ts @@ -81,7 +81,7 @@ export class MappingService { let date = new Date(); let user: SmartHarvesterUser = this.storageService.getUser(); let array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray; - let str = `#mapping_date: ${date.getDate()}/${date.getMonth()}/${date.getFullYear()}\n#creator_label: ${user.firstName} ${user.lastName}\n#curie_map:\n# dcat: "http://www.w3.org/ns/dcat#"\n# dct: "http://purl.org/dc/terms/"\n# adms: "http://www.w3.org/ns/adms#\n# dqv: "http://www.w3.org/ns/dqv#"\n# geodcat: "http://data.europa.eu/930/"\n# prov: "http://www.w3.org/ns/prov#"\n# rdfs: "http://www.w3.org/2000/01/rdf-schema#"`; + let str = `#mapping_date: ${date.getDate()}/${date.getMonth()}/${date.getFullYear()}\n#creator_label: ${user.firstName} ${user.lastName}\n#curie_map:\n# dcat: "http://www.w3.org/ns/dcat#"\n# dct: "http://purl.org/dc/terms/"\n# adms: "http://www.w3.org/ns/adms#\n# dqv: "http://www.w3.org/ns/dqv#"\n# geodcat: "http://data.europa.eu/930/"\n# prov: "http://www.w3.org/ns/prov#"\n# rdfs: "http://www.w3.org/2000/01/rdf-schema#"\n`; let row = ''; for (let index in headerList) { @@ -130,7 +130,14 @@ export class MappingService { } console.table(lines) - let headers = lines[0].split('\t'); + let headers = [ + 'subject_label', + 'predicate_id', + 'object_id', + 'match_type', + 'object_category' + ] + lines.shift() for (let i = 0; i < lines.length; i++) { diff --git a/src/app/publishapi/publishapi.component.html b/src/app/publishapi/publishapi.component.html index a4ac40674..5e99df591 100644 --- a/src/app/publishapi/publishapi.component.html +++ b/src/app/publishapi/publishapi.component.html @@ -315,7 +315,7 @@ <p class="lorem"> Map your metadata schema with DCAT schema </p> - <app-mapping *ngIf="initLabelThree && datasets.ready" [catalogId]="openApi.info['x-catalog-id']" [type]="type"> + <app-mapping *ngIf="initLabelThree && datasets.ready" [catalogId]="openApi.info['x-catalog-id']" [type]="openApi.info['x-format']"> </app-mapping> <button class="prev-button" nbButton nbStepperPrevious (click)="initLabelThree=false; resetDataset(); datasets.ready = false">prev</button> diff --git a/src/app/publishapi/publishapi.component.ts b/src/app/publishapi/publishapi.component.ts index f3d443b0f..5caf7af56 100644 --- a/src/app/publishapi/publishapi.component.ts +++ b/src/app/publishapi/publishapi.component.ts @@ -330,6 +330,7 @@ export class PublishApiComponent implements OnInit { this.openApi = this.openApiService.getFromString(reader.result as string); this.openApi.cleanServers(servers[0].url); this.openApi.info['x-catalog-id'] = catId; + }; reader.readAsText(jsonFile); diff --git a/src/app/publishapi/services/openapi-service.ts b/src/app/publishapi/services/openapi-service.ts index c111bd0b9..4cfa0bcb7 100644 --- a/src/app/publishapi/services/openapi-service.ts +++ b/src/app/publishapi/services/openapi-service.ts @@ -25,7 +25,7 @@ export class OpenApiService { get tokenHarvesterHeader() { return { headers: new HttpHeaders({ - Authorization: 'Bearer ' + this.sessionStorage.getUser().token + Authorization: 'Bearer ' + this.sessionStorage.getToken() }) }; } @@ -66,7 +66,7 @@ export class OpenApiService { } getByCatalogId(catId: string): Observable<OpenApiDTO> { - if (this.sessionStorage.getUser().token == null) { + if (this.sessionStorage.getToken() == null) { return of(); } @@ -74,7 +74,7 @@ export class OpenApiService { } publishOpenApi(openApi: OpenApi) { - if (this.sessionStorage.getUser().token == null) { + if (this.sessionStorage.getToken() == null) { return of(); } -- GitLab From 96f0baddc627d71777c7370c9cd924b611396522 Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Mon, 29 Nov 2021 09:52:35 +0100 Subject: [PATCH 4/8] bug fix --- src/app/authentication/signup/signup.component.html | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/authentication/signup/signup.component.html b/src/app/authentication/signup/signup.component.html index c5729560a..4b6780240 100644 --- a/src/app/authentication/signup/signup.component.html +++ b/src/app/authentication/signup/signup.component.html @@ -86,7 +86,6 @@ </nb-form-field> <!-- Password error--> <div class="alert alert-danger" role="alert" *ngIf="f.submitted && password.invalid"> - fdfdf <div *ngIf="password.errors.required">Password is required</div> <div *ngIf="password.errors.minlength"> Password must be at least 6 characters -- GitLab From ae530108198afd76b6a4fd127a22fd6f5143aae9 Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Thu, 2 Dec 2021 10:28:45 +0100 Subject: [PATCH 5/8] create cookie with fdp token --- src/app/authentication/services/auth.service.ts | 4 ++-- src/app/authentication/services/fdp.guard.ts | 2 +- src/app/authentication/services/token-storage.service.ts | 9 ++++----- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/app/authentication/services/auth.service.ts b/src/app/authentication/services/auth.service.ts index b9e8c5d01..6995ed1b4 100644 --- a/src/app/authentication/services/auth.service.ts +++ b/src/app/authentication/services/auth.service.ts @@ -87,8 +87,8 @@ export class AuthService { } isFdpLoggedIn(): boolean { - const fdpToken = this.tokenService.getFDPToken(); - return fdpToken !== null; + + return !this.tokenService.getFDPToken(); } diff --git a/src/app/authentication/services/fdp.guard.ts b/src/app/authentication/services/fdp.guard.ts index 11770c65a..db094c07b 100644 --- a/src/app/authentication/services/fdp.guard.ts +++ b/src/app/authentication/services/fdp.guard.ts @@ -13,7 +13,7 @@ export class FdpGuard implements CanActivate { canActivate( _next: ActivatedRouteSnapshot, _state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree { - if (this.authService.isFdpLoggedIn()) { + if (!this.authService.isFdpLoggedIn()) { return true; } diff --git a/src/app/authentication/services/token-storage.service.ts b/src/app/authentication/services/token-storage.service.ts index e496c4843..abefc2e65 100644 --- a/src/app/authentication/services/token-storage.service.ts +++ b/src/app/authentication/services/token-storage.service.ts @@ -1,4 +1,5 @@ import { Injectable } from '@angular/core'; +import { Cookie } from 'ng2-cookies'; import { AuthService } from './auth.service'; const TOKEN_KEY = 'auth-token'; @@ -22,16 +23,15 @@ export class TokenStorageService { } - public saveTokenFDP(FdpToken: string): void { - window.sessionStorage.removeItem(FDP_TOKEN_KEY); - window.sessionStorage.setItem(FDP_TOKEN_KEY, FdpToken); + public saveTokenFDP(fdpToken: string): void { + Cookie.set('fdp_token',fdpToken, 1000 ) } public getToken(): string { return window.sessionStorage.getItem(TOKEN_KEY); } public getFDPToken(): string { - return window.sessionStorage.getItem(FDP_TOKEN_KEY); + return Cookie.get('fdp_token'); } public saveUser(user): void { @@ -44,7 +44,6 @@ export class TokenStorageService { } public removeToken(){ window.sessionStorage.removeItem(TOKEN_KEY); - window.sessionStorage.removeItem(FDP_TOKEN_KEY); window.sessionStorage.removeItem(USER_KEY); } -- GitLab From 28862ec4561aea01fe779fd8320eca5c0ae9b934 Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Thu, 2 Dec 2021 14:04:57 +0100 Subject: [PATCH 6/8] modify cookie expiration --- src/app/authentication/services/token-storage.service.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/authentication/services/token-storage.service.ts b/src/app/authentication/services/token-storage.service.ts index abefc2e65..fc199cac7 100644 --- a/src/app/authentication/services/token-storage.service.ts +++ b/src/app/authentication/services/token-storage.service.ts @@ -1,4 +1,5 @@ import { Injectable } from '@angular/core'; +import { Session } from 'inspector'; import { Cookie } from 'ng2-cookies'; import { AuthService } from './auth.service'; @@ -24,7 +25,7 @@ export class TokenStorageService { } public saveTokenFDP(fdpToken: string): void { - Cookie.set('fdp_token',fdpToken, 1000 ) + Cookie.set('fdp_token',fdpToken, 1 ) } public getToken(): string { -- GitLab From f9600c8cfeb3b47890530cd2fb6dcd8d1c3061ee Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Tue, 7 Dec 2021 15:52:31 +0000 Subject: [PATCH 7/8] Update version --- version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version b/version index 0828ab794..62ccda57f 100644 --- a/version +++ b/version @@ -1 +1 @@ -v18 \ No newline at end of file +v19 -- GitLab From 70f829db1c413090a9663a58343e36f03e4e1087 Mon Sep 17 00:00:00 2001 From: Baptiste Toulemonde <toulemonde@cines.fr> Date: Wed, 8 Dec 2021 11:39:06 +0100 Subject: [PATCH 8/8] fix --- src/app/authentication/services/token-storage.service.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/app/authentication/services/token-storage.service.ts b/src/app/authentication/services/token-storage.service.ts index fc199cac7..b949094e4 100644 --- a/src/app/authentication/services/token-storage.service.ts +++ b/src/app/authentication/services/token-storage.service.ts @@ -1,7 +1,5 @@ import { Injectable } from '@angular/core'; -import { Session } from 'inspector'; import { Cookie } from 'ng2-cookies'; -import { AuthService } from './auth.service'; const TOKEN_KEY = 'auth-token'; const USER_KEY = 'auth-user'; -- GitLab