mirror of https://github.com/apache/archiva.git
Additional angular code
This commit is contained in:
parent
108b60a4df
commit
fb2a7fd643
|
@ -30,6 +30,7 @@ const routes: Routes = [
|
|||
{ path: 'contact', component: ContactComponent },
|
||||
{ path: 'about', component: AboutComponent },
|
||||
{ path: 'login', component: LoginComponent },
|
||||
{ path: 'logout', component: HomeComponent },
|
||||
{ path: '**', component: NotFoundComponent }
|
||||
];
|
||||
|
||||
|
|
|
@ -16,70 +16,84 @@
|
|||
~ specific language governing permissions and limitations
|
||||
~ under the License.
|
||||
-->
|
||||
<div class="app d-flex flex-column" >
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-md fixed-top navbar-light " style="background-color: #c6cbd2;">
|
||||
<a class="navbar-brand" routerLink="/">
|
||||
<img src="../assets/params/images/archiva_logo_40h.png" alt="ARCHIVA">
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsDefault"
|
||||
aria-controls="navbarsDefault" aria-expanded="false" aria-label="Toggle Navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarsDefault">
|
||||
<ul class="navbar-nav ml-auto">
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" routerLink="/">
|
||||
<i class="fas fa-home mr-1"></i>{{ 'menu.home' |translate }}
|
||||
<div class="app d-flex flex-column">
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-md fixed-top navbar-light " style="background-color: #c6cbd2;">
|
||||
<a class="navbar-brand" routerLink="/">
|
||||
<img src="../assets/params/images/archiva_logo_40h.png" alt="ARCHIVA">
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" routerLink="/login" data-toggle="modal" data-target="#loginModal">
|
||||
<i class="fas fa-user mr-1"></i>{{'menu.login' | translate}}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item active dropdown">
|
||||
<a class="nav-link dropdown-toggle" id="dropdown09" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><span class="flag-icon {{langIcon()}}"></span></a>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdown09">
|
||||
<a class="dropdown-item" href="#en" (click)="switchLang('en')"><span class="flag-icon flag-icon-gb"> </span> English</a>
|
||||
<a class="dropdown-item" href="#de" (click)="switchLang('de')"><span class="flag-icon flag-icon-de"> </span> German</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsDefault"
|
||||
aria-controls="navbarsDefault" aria-expanded="false" aria-label="Toggle Navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarsDefault">
|
||||
<div class="navbar-nav ml-auto">
|
||||
<span *ngIf="auth.loggedIn" class="navbar-text border-right pr-2 mr-2">
|
||||
{{user.userInfo.fullName}}
|
||||
</span>
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" routerLink="/">
|
||||
<i class="fas fa-home mr-1"></i>{{ 'menu.home' |translate }}
|
||||
</a>
|
||||
</li>
|
||||
<li *ngIf="!auth.loggedIn" class="nav-item active">
|
||||
<a class="nav-link" routerLink="/login" data-toggle="modal" data-target="#loginModal">
|
||||
<i class="fas fa-user mr-1"></i>{{'menu.login' | translate}}
|
||||
</a>
|
||||
</li>
|
||||
<li *ngIf="auth.loggedIn" class="nav-item active">
|
||||
<a class="nav-link" routerLink="/logout" (click)="auth.logout()">
|
||||
<i class="fas fa-user mr-1"></i>{{'menu.logout' | translate}}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item active dropdown">
|
||||
<a class="nav-link dropdown-toggle" id="dropdown09" data-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="false"><span class="flag-icon {{langIcon()}}"></span></a>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdown09">
|
||||
<a class="dropdown-item" href="#en" (click)="switchLang('en')"><span
|
||||
class="flag-icon flag-icon-gb"> </span> English</a>
|
||||
<a class="dropdown-item" href="#de" (click)="switchLang('de')"><span
|
||||
class="flag-icon flag-icon-de"> </span> German</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" routerLink="/about">
|
||||
<i class="far fa-question-circle mr-1"></i>{{'menu.about' | translate}}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" routerLink="/contact">
|
||||
<i class="fas fa-envelope mr-1"></i>{{ 'menu.contact' | translate }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="https://github.com/apache/archiva">
|
||||
<i class="fab fa-github mr-1"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" routerLink="/about">
|
||||
<i class="far fa-question-circle mr-1"></i>{{'menu.about' | translate}}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" routerLink="/contact">
|
||||
<i class="fas fa-envelope mr-1"></i>{{ 'menu.contact' | translate }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="https://github.com/apache/archiva">
|
||||
<i class="fab fa-github mr-1"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container-fluid flex-fill">
|
||||
<div >
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<hr />
|
||||
<footer class="container-fluid">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<p class="text-center text-black-50">© 2020 - archiva.apache.org</p>
|
||||
<main class="container-fluid flex-fill">
|
||||
<div>
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</main>
|
||||
|
||||
<hr/>
|
||||
<footer class="container-fluid">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<p class="text-center text-black-50">© 2020 - archiva.apache.org</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
|
@ -16,28 +16,33 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { Component } from '@angular/core';
|
||||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { AuthenticationService } from "./services/authentication.service";
|
||||
import {UserService} from "./services/user.service";
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss']
|
||||
})
|
||||
export class AppComponent {
|
||||
export class AppComponent implements OnInit, OnDestroy{
|
||||
title = 'archiva-web';
|
||||
version = 'Angular version 10.0.2';
|
||||
|
||||
constructor(
|
||||
public translate: TranslateService
|
||||
public translate: TranslateService,
|
||||
public auth: AuthenticationService,
|
||||
public user: UserService
|
||||
) {
|
||||
translate.addLangs(['en', 'de']);
|
||||
translate.setDefaultLang('en');
|
||||
translate.use('en');
|
||||
}
|
||||
|
||||
switchLang(lang: string) {
|
||||
this.translate.use(lang);
|
||||
this.user.userInfo.language = lang;
|
||||
this.user.persistUserInfo();
|
||||
}
|
||||
|
||||
langIcon() : string {
|
||||
|
@ -50,4 +55,25 @@ export class AppComponent {
|
|||
return "flag-icon-" + this.translate.currentLang;
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.auth.LoginEvent.unsubscribe();
|
||||
}
|
||||
|
||||
|
||||
ngOnInit(): void {
|
||||
let lang = this.user.userInfo.language;
|
||||
if (lang==null) {
|
||||
this.translate.use('en');
|
||||
} else {
|
||||
this.translate.use(lang);
|
||||
}
|
||||
// Subscribe to login event in authenticator to switch the language
|
||||
this.auth.LoginEvent.subscribe(userInfo => {
|
||||
if (userInfo.language != null) {
|
||||
this.switchLang(userInfo.language);
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { UserInfo } from './user-info';
|
||||
|
||||
describe('UserInfo', () => {
|
||||
it('should create an instance', () => {
|
||||
expect(new UserInfo()).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
export class UserInfo {
|
||||
user_id:string;
|
||||
id:string;
|
||||
fullName:string;
|
||||
email:string;
|
||||
validated:boolean;
|
||||
locked:boolean;
|
||||
passwordChangeRequired:boolean;
|
||||
permanent:boolean;
|
||||
timestampAccountCreation:Date;
|
||||
timestampLastLogin:Date;
|
||||
timestampLastPasswordChange:Date;
|
||||
assignedRoles:string[];
|
||||
readOnly:boolean;
|
||||
userManagerId:string;
|
||||
validationToken:string;
|
||||
language:string;
|
||||
}
|
|
@ -74,4 +74,7 @@ export class LoginComponent implements OnInit {
|
|||
this.loginForm.reset();
|
||||
this.authenticationService.login(customerData.userid, customerData.password, resultHandler);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -16,49 +16,81 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { Injectable } from '@angular/core';
|
||||
import {HttpClient, HttpEvent, HttpResponse} from "@angular/common/http";
|
||||
import { environment } from "../../environments/environment";
|
||||
import {Injectable} from '@angular/core';
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
import {environment} from "../../environments/environment";
|
||||
import {Observable} from "rxjs";
|
||||
import {ErrorMessage} from "../model/error-message";
|
||||
import {TranslateService} from "@ngx-translate/core";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ArchivaRequestService {
|
||||
|
||||
constructor(private http : HttpClient, private translator : TranslateService) { }
|
||||
// Stores the access token locally
|
||||
accessToken: string;
|
||||
|
||||
executeRestCall<R>(type: string, module: string, service: string, input: object ) : Observable<R> {
|
||||
let modulePath = environment.application.servicePaths[module];
|
||||
let url = environment.application.baseUrl + environment.application.restPath + "/" + modulePath + "/" + service;
|
||||
let token = localStorage.getItem("access_token")
|
||||
let headers = null;
|
||||
if (token != null) {
|
||||
headers = {
|
||||
"Authorization": "Bearer " + localStorage.getItem("access_token")
|
||||
}
|
||||
} else {
|
||||
headers = {};
|
||||
constructor(private http: HttpClient, private translator: TranslateService) {
|
||||
}
|
||||
if (type == "get") {
|
||||
return this.http.get<R>(url, {"headers":headers});
|
||||
} else if ( type == "post") {
|
||||
return this.http.post<R>(url, input, {"headers":headers});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
translateError(errorMsg : ErrorMessage) : string {
|
||||
if (errorMsg.errorKey!=null && errorMsg.errorKey!='') {
|
||||
let parms = {};
|
||||
if (errorMsg.args!=null && errorMsg.args.length>0) {
|
||||
for ( let i=0; i<errorMsg.args.length; i++) {
|
||||
parms['arg' + i] = errorMsg.args[i];
|
||||
/**
|
||||
* Executes a rest call to the archiva / redback REST services.
|
||||
* @param type the type of the call (get, post, update)
|
||||
* @param module the module (archiva, redback)
|
||||
* @param service the REST service to call
|
||||
* @param input the input data, if this is a POST or UPDATE request
|
||||
*/
|
||||
executeRestCall<R>(type: string, module: string, service: string, input: object): Observable<R> {
|
||||
let modulePath = environment.application.servicePaths[module];
|
||||
let url = environment.application.baseUrl + environment.application.restPath + "/" + modulePath + "/" + service;
|
||||
let token = this.getToken();
|
||||
let headers = null;
|
||||
if (token != null) {
|
||||
headers = {
|
||||
"Authorization": "Bearer " + token
|
||||
}
|
||||
} else {
|
||||
headers = {};
|
||||
}
|
||||
if (type == "get") {
|
||||
return this.http.get<R>(url, {"headers": headers});
|
||||
} else if (type == "post") {
|
||||
return this.http.post<R>(url, input, {"headers": headers});
|
||||
}
|
||||
}
|
||||
|
||||
public resetToken() {
|
||||
this.accessToken = null;
|
||||
}
|
||||
|
||||
private getToken(): string {
|
||||
if (this.accessToken != null) {
|
||||
return this.accessToken;
|
||||
} else {
|
||||
let token = localStorage.getItem("access_token");
|
||||
if (token != null && token != "") {
|
||||
this.accessToken = token;
|
||||
return token;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a given error message to the current set language.
|
||||
* @param errorMsg the errorMsg as returned by a REST call
|
||||
*/
|
||||
public translateError(errorMsg: ErrorMessage): string {
|
||||
if (errorMsg.errorKey != null && errorMsg.errorKey != '') {
|
||||
let parms = {};
|
||||
if (errorMsg.args != null && errorMsg.args.length > 0) {
|
||||
for (let i = 0; i < errorMsg.args.length; i++) {
|
||||
parms['arg' + i] = errorMsg.args[i];
|
||||
}
|
||||
}
|
||||
return this.translator.instant('api.' + errorMsg.errorKey, parms);
|
||||
}
|
||||
}
|
||||
return this.translator.instant('api.'+errorMsg.errorKey, parms);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,61 +16,117 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { Injectable } from '@angular/core';
|
||||
import {EventEmitter, Injectable} from '@angular/core';
|
||||
import {ArchivaRequestService} from "./archiva-request.service";
|
||||
import {AccessToken} from "../model/access-token";
|
||||
import { environment } from "../../environments/environment";
|
||||
import {environment} from "../../environments/environment";
|
||||
import {ErrorMessage} from "../model/error-message";
|
||||
import {ErrorResult} from "../model/error-result";
|
||||
import {HttpErrorResponse} from "@angular/common/http";
|
||||
import {UserService} from "./user.service";
|
||||
import {UserInfo} from "../model/user-info";
|
||||
|
||||
/**
|
||||
* The AuthenticationService handles user authentication and stores user data after successful login
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AuthenticationService {
|
||||
loggedIn: boolean;
|
||||
|
||||
constructor(private rest: ArchivaRequestService) { }
|
||||
/**
|
||||
* The LoginEvent is emitted, when a successful login happened. And the corresponding user info was retrieved.
|
||||
*/
|
||||
public LoginEvent: EventEmitter<UserInfo> = new EventEmitter<UserInfo>();
|
||||
|
||||
login(userid:string, password:string, resultHandler: (n: string, err?: ErrorMessage[]) => void) {
|
||||
|
||||
const data = { 'grant_type':'authorization_code',
|
||||
'client_id':environment.application.client_id,
|
||||
'user_id':userid, 'password':password
|
||||
};
|
||||
let authObserver = this.rest.executeRestCall<AccessToken>('post','redback', 'auth/authenticate', data );
|
||||
let tokenObserver = {
|
||||
next: (x: AccessToken) => {
|
||||
localStorage.setItem("access_token", x.access_token);
|
||||
localStorage.setItem("refresh_token", x.refresh_token);
|
||||
if (x.expires_in!=null) {
|
||||
let dt = new Date();
|
||||
dt.setSeconds(dt.getSeconds() + x.expires_in);
|
||||
localStorage.setItem("token_expire", dt.toISOString());
|
||||
}
|
||||
resultHandler("OK");
|
||||
},
|
||||
error: ( err: HttpErrorResponse) => {
|
||||
console.log("Error " + (JSON.stringify(err)));
|
||||
let result = err.error as ErrorResult
|
||||
if (result.errorMessages!=null) {
|
||||
for (let msg of result.errorMessages) {
|
||||
console.error('Observer got an error: ' + msg.errorKey)
|
||||
}
|
||||
resultHandler("ERROR", result.errorMessages);
|
||||
} else {
|
||||
resultHandler("ERROR", null);
|
||||
}
|
||||
constructor(private rest: ArchivaRequestService,
|
||||
private userService: UserService) {
|
||||
this.loggedIn = false;
|
||||
this.restoreLoginData();
|
||||
}
|
||||
|
||||
},
|
||||
// complete: () => console.log('Observer got a complete notification'),
|
||||
};
|
||||
authObserver.subscribe(tokenObserver)
|
||||
private restoreLoginData() {
|
||||
let accessToken = localStorage.getItem("access_token");
|
||||
if (accessToken != null) {
|
||||
let expirationDate = localStorage.getItem("token_expire");
|
||||
if (expirationDate != null) {
|
||||
let expDate = new Date(expirationDate);
|
||||
let currentDate = new Date();
|
||||
if (currentDate < expDate) {
|
||||
this.loggedIn = true
|
||||
let observer = this.userService.retrieveUserInfo();
|
||||
observer.subscribe(userInfo =>
|
||||
this.LoginEvent.emit(userInfo)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
logout() {
|
||||
localStorage.removeItem("access_token");
|
||||
localStorage.removeItem("refresh_token");
|
||||
localStorage.removeItem("token_expire");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tries to login by sending the login data to the REST service. If the login was successful the access
|
||||
* and refresh token is stored locally.
|
||||
*
|
||||
* @param userid The user id for the login
|
||||
* @param password The password
|
||||
* @param resultHandler A result handler that is executed, after calling the login service
|
||||
*/
|
||||
login(userid: string, password: string, resultHandler: (n: string, err?: ErrorMessage[]) => void) {
|
||||
|
||||
const data = {
|
||||
'grant_type': 'authorization_code',
|
||||
'client_id': environment.application.client_id,
|
||||
'user_id': userid, 'password': password
|
||||
};
|
||||
let authObserver = this.rest.executeRestCall<AccessToken>('post', 'redback', 'auth/authenticate', data);
|
||||
let tokenObserver = {
|
||||
next: (x: AccessToken) => {
|
||||
localStorage.setItem("access_token", x.access_token);
|
||||
localStorage.setItem("refresh_token", x.refresh_token);
|
||||
if (x.expires_in != null) {
|
||||
let dt = new Date();
|
||||
dt.setSeconds(dt.getSeconds() + x.expires_in);
|
||||
localStorage.setItem("token_expire", dt.toISOString());
|
||||
}
|
||||
let userObserver = this.userService.retrieveUserInfo();
|
||||
this.loggedIn = true;
|
||||
userObserver.subscribe(userInfo =>
|
||||
this.LoginEvent.emit(userInfo));
|
||||
resultHandler("OK");
|
||||
},
|
||||
error: (err: HttpErrorResponse) => {
|
||||
console.log("Error " + (JSON.stringify(err)));
|
||||
let result = err.error as ErrorResult
|
||||
if (result.errorMessages != null) {
|
||||
for (let msg of result.errorMessages) {
|
||||
console.error('Observer got an error: ' + msg.errorKey)
|
||||
}
|
||||
resultHandler("ERROR", result.errorMessages);
|
||||
} else {
|
||||
resultHandler("ERROR", null);
|
||||
}
|
||||
|
||||
},
|
||||
// complete: () => console.log('Observer got a complete notification'),
|
||||
};
|
||||
authObserver.subscribe(tokenObserver)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the stored user data
|
||||
*/
|
||||
logout() {
|
||||
localStorage.removeItem("access_token");
|
||||
localStorage.removeItem("refresh_token");
|
||||
localStorage.removeItem("token_expire");
|
||||
this.loggedIn = false;
|
||||
this.userService.resetUser();
|
||||
this.rest.resetToken();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { UserService } from './user.service';
|
||||
|
||||
describe('UserService', () => {
|
||||
let service: UserService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(UserService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import {Injectable} from '@angular/core';
|
||||
import {ArchivaRequestService} from "./archiva-request.service";
|
||||
import {UserInfo} from '../model/user-info';
|
||||
import {HttpErrorResponse} from "@angular/common/http";
|
||||
import {ErrorResult} from "../model/error-result";
|
||||
import {Observable} from "rxjs";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class UserService {
|
||||
|
||||
userInfo: UserInfo;
|
||||
|
||||
constructor(private rest: ArchivaRequestService) {
|
||||
this.userInfo = new UserInfo()
|
||||
this.loadPersistedUserInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the user information from the REST service for the current logged in user.
|
||||
* This works only, if a valid access token is present.
|
||||
* It returns a observable that can be subscribed to catch the user information.
|
||||
*/
|
||||
public retrieveUserInfo(): Observable<UserInfo> {
|
||||
return new Observable<UserInfo>((resultObserver) => {
|
||||
let accessToken = localStorage.getItem("access_token");
|
||||
|
||||
if (accessToken != null) {
|
||||
let infoObserver = this.rest.executeRestCall<UserInfo>("get", "redback", "users/me", null);
|
||||
let userInfoObserver = {
|
||||
next: (x: UserInfo) => {
|
||||
this.userInfo = x;
|
||||
if (this.userInfo.language == null) {
|
||||
this.loadPersistedUserInfo();
|
||||
}
|
||||
this.persistUserInfo();
|
||||
resultObserver.next(this.userInfo);
|
||||
},
|
||||
error: (err: HttpErrorResponse) => {
|
||||
console.log("Error " + (JSON.stringify(err)));
|
||||
let result = err.error as ErrorResult
|
||||
if (result.errorMessages != null) {
|
||||
for (let msg of result.errorMessages) {
|
||||
console.error('Observer got an error: ' + msg.errorKey)
|
||||
}
|
||||
}
|
||||
resultObserver.error();
|
||||
},
|
||||
complete: () => {
|
||||
resultObserver.complete();
|
||||
}
|
||||
};
|
||||
infoObserver.subscribe(userInfoObserver);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores user information persistent. Not the complete UserInfo object, only properties, that
|
||||
* are needed.
|
||||
*/
|
||||
public persistUserInfo() {
|
||||
if (this.userInfo != null && this.userInfo.user_id != null && this.userInfo.user_id != "") {
|
||||
let prefix = "user." + this.userInfo.user_id;
|
||||
localStorage.setItem(prefix + ".user_id", this.userInfo.user_id);
|
||||
localStorage.setItem(prefix + ".id", this.userInfo.id);
|
||||
if (this.userInfo.language != null && this.userInfo.language != "") {
|
||||
localStorage.setItem(prefix + ".language", this.userInfo.language);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the persisted user info from the local storage
|
||||
*/
|
||||
public loadPersistedUserInfo() {
|
||||
if (this.userInfo.user_id != null && this.userInfo.user_id != "") {
|
||||
let prefix = "user." + this.userInfo.user_id;
|
||||
this.userInfo.language = localStorage.getItem(prefix + ".language");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the user info to default values.
|
||||
*/
|
||||
resetUser() {
|
||||
this.userInfo = new UserInfo();
|
||||
}
|
||||
|
||||
}
|
|
@ -11,6 +11,7 @@
|
|||
"menu": {
|
||||
"home": "Home",
|
||||
"login": "Anmelden",
|
||||
"logout": "Abmelden",
|
||||
"about": "Über",
|
||||
"contact": "Kontakt"
|
||||
},
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
"menu": {
|
||||
"home": "Home",
|
||||
"login": "Login",
|
||||
"logout": "Logout",
|
||||
"about": "About",
|
||||
"contact": "Contact"
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue