mirror of https://github.com/apache/archiva.git
Adding permission handling to webapp
This commit is contained in:
parent
e597490140
commit
2313e1cd86
|
@ -29,7 +29,7 @@
|
|||
|
||||
<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">
|
||||
<span *ngIf="auth.authenticated" class="navbar-text border-right pr-2 mr-2">
|
||||
{{user.userInfo.fullName}}
|
||||
</span>
|
||||
<ul class="navbar-nav">
|
||||
|
@ -38,12 +38,12 @@
|
|||
<i class="fas fa-home mr-1"></i>{{ 'menu.home' |translate }}
|
||||
</a>
|
||||
</li>
|
||||
<li *ngIf="!auth.loggedIn" class="nav-item active">
|
||||
<li *ngIf="!auth.authenticated" 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">
|
||||
<li *ngIf="auth.authenticated" 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>
|
||||
|
|
|
@ -62,17 +62,17 @@ export class AppComponent implements OnInit, OnDestroy{
|
|||
|
||||
|
||||
ngOnInit(): void {
|
||||
let lang = this.user.userInfo.language;
|
||||
if (lang==null) {
|
||||
this.translate.use('en');
|
||||
if (this.user.userInfo!=null && this.user.userInfo.language!=null ) {
|
||||
this.translate.use(this.user.userInfo.language);
|
||||
} else {
|
||||
this.translate.use(lang);
|
||||
this.translate.use('en');
|
||||
}
|
||||
// Subscribe to login event in authenticator to switch the language
|
||||
this.auth.LoginEvent.subscribe(userInfo => {
|
||||
if (userInfo.language != null) {
|
||||
this.switchLang(userInfo.language);
|
||||
}
|
||||
// console.log("Permissions: " + JSON.stringify(this.user.permissions));
|
||||
})
|
||||
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import { NotFoundComponent } from './modules/general/not-found/not-found.compone
|
|||
import { SidemenuComponent } from './modules/general/sidemenu/sidemenu.component';
|
||||
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
|
||||
import { LoginComponent } from './modules/general/login/login.component';
|
||||
import { ViewPermissionDirective } from './directives/view-permission.directive';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
@ -41,6 +42,7 @@ import { LoginComponent } from './modules/general/login/login.component';
|
|||
NotFoundComponent,
|
||||
SidemenuComponent,
|
||||
LoginComponent,
|
||||
ViewPermissionDirective,
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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 { ViewPermissionDirective } from './view-permission.directive';
|
||||
|
||||
describe('ViewPermissionDirective', () => {
|
||||
it('should create an instance', () => {
|
||||
const directive = new ViewPermissionDirective(null, null);
|
||||
expect(directive).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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 {Directive, ElementRef, Input, OnChanges, OnInit, Renderer2, SimpleChanges} from '@angular/core';
|
||||
|
||||
/**
|
||||
* This directive can be used to render based on permissions
|
||||
*/
|
||||
@Directive({
|
||||
selector: '[appViewPermission]'
|
||||
})
|
||||
export class ViewPermissionDirective implements OnInit, OnChanges {
|
||||
@Input('appViewPermission') permission: boolean;
|
||||
|
||||
constructor(private renderer: Renderer2, private el: ElementRef) {
|
||||
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
// console.log("Init appViewPermission " + this.permission + " " + typeof (this.permission));
|
||||
// this.togglePermission();
|
||||
}
|
||||
|
||||
private togglePermission() {
|
||||
if (this.permission) {
|
||||
this.removeClass("d-none");
|
||||
} else {
|
||||
this.addClass("d-none");
|
||||
}
|
||||
}
|
||||
|
||||
addClass(className: string) {
|
||||
// make sure you declare classname in your main style.css
|
||||
this.renderer.addClass(this.el.nativeElement, className);
|
||||
}
|
||||
|
||||
removeClass(className: string) {
|
||||
this.renderer.removeClass(this.el.nativeElement, className);
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes.permission != null &&
|
||||
(changes.permission.firstChange || changes.permission.currentValue != changes.permission.previousValue)) {
|
||||
// console.debug("Changed " + JSON.stringify(changes));
|
||||
this.togglePermission();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -8,7 +8,6 @@
|
|||
* 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
|
||||
|
|
|
@ -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 { Operation } from './operation';
|
||||
|
||||
describe('Operation', () => {
|
||||
it('should create an instance', () => {
|
||||
expect(new Operation()).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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 Operation {
|
||||
name: string;
|
||||
description: string;
|
||||
descriptionKey: string;
|
||||
permanent: boolean;
|
||||
}
|
|
@ -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 { Permission } from './permission';
|
||||
|
||||
describe('Permission', () => {
|
||||
it('should create an instance', () => {
|
||||
expect(new Permission()).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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 {Operation} from "./operation";
|
||||
import {Resource} from "./resource";
|
||||
|
||||
export class Permission {
|
||||
name: string;
|
||||
description: string;
|
||||
permanent: boolean;
|
||||
descriptionKey: string;
|
||||
operation: Operation;
|
||||
resource: Resource;
|
||||
}
|
|
@ -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 { Resource } from './resource';
|
||||
|
||||
describe('Resource', () => {
|
||||
it('should create an instance', () => {
|
||||
expect(new Resource()).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 Resource {
|
||||
identifier: string;
|
||||
permanent: boolean;
|
||||
pattern: boolean;
|
||||
}
|
|
@ -28,7 +28,6 @@ export class UserInfo {
|
|||
timestampAccountCreation:Date;
|
||||
timestampLastLogin:Date;
|
||||
timestampLastPasswordChange:Date;
|
||||
assignedRoles:string[];
|
||||
readOnly:boolean;
|
||||
userManagerId:string;
|
||||
validationToken:string;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
-->
|
||||
<nav class="nav flex-column nav-pills " role="tablist" aria-orientation="vertical">
|
||||
|
||||
<div [appViewPermission]="perms.menu.repo.section">
|
||||
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true" >Artifacts</a>
|
||||
|
||||
<a class="nav-link active my-0 py-0" href="#" data-toggle="pill"
|
||||
|
@ -27,8 +28,10 @@
|
|||
role="tab" aria-controls="v-pills-browse" aria-selected="false">Browse</a>
|
||||
|
||||
<a class="nav-link my-0 py-0" href="#" data-toggle="pill"
|
||||
role="tab" aria-controls="v-pills-browse" aria-selected="false">Upload Artifact</a>
|
||||
|
||||
role="tab" aria-controls="v-pills-browse" aria-selected="false"
|
||||
[appViewPermission]="perms.menu.repo.upload">Upload Artifact</a>
|
||||
</div>
|
||||
<div [appViewPermission]="perms.menu.admin.section">
|
||||
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true" data-toggle="pill"
|
||||
role="tab" aria-controls="v-pills-home" aria-selected="false" >Administration</a>
|
||||
<a class="nav-link my-0 py-0" href="#" data-toggle="pill"
|
||||
|
@ -51,6 +54,8 @@
|
|||
role="tab" aria-controls="v-pills-browse" aria-selected="false">UI Configuration</a>
|
||||
<a class="nav-link my-0 py-0" href="#" data-toggle="pill"
|
||||
role="tab" aria-controls="v-pills-browse" aria-selected="false">Reports</a>
|
||||
</div>
|
||||
<div [appViewPermission]="perms.menu.user.section">
|
||||
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true" data-toggle="pill"
|
||||
role="tab" aria-controls="v-pills-home" aria-selected="false">Users</a>
|
||||
<a class="nav-link my-0 py-0" href="#" data-toggle="pill"
|
||||
|
@ -59,6 +64,7 @@
|
|||
role="tab" aria-controls="v-pills-browse" aria-selected="false">Roles</a>
|
||||
<a class="nav-link my-0 py-0" href="#" data-toggle="pill"
|
||||
role="tab" aria-controls="v-pills-browse" aria-selected="false">Users Runtime Configuration</a>
|
||||
</div>
|
||||
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true" data-toggle="pill"
|
||||
role="tab" aria-controls="v-pills-home" aria-selected="false">Documentation</a>
|
||||
<a class="nav-link my-0 py-0" href="#" data-toggle="pill"
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import {UserService} from "../../../services/user.service";
|
||||
|
||||
@Component({
|
||||
selector: 'app-sidemenu',
|
||||
|
@ -25,7 +26,11 @@ import { Component, OnInit } from '@angular/core';
|
|||
})
|
||||
export class SidemenuComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
perms;
|
||||
|
||||
constructor(private user: UserService) {
|
||||
this.perms = user.uiPermissions;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
|
|
@ -33,17 +33,22 @@ import {UserInfo} from "../model/user-info";
|
|||
providedIn: 'root'
|
||||
})
|
||||
export class AuthenticationService {
|
||||
loggedIn: boolean;
|
||||
authenticated: boolean;
|
||||
|
||||
/**
|
||||
* The LoginEvent is emitted, when a successful login happened. And the corresponding user info was retrieved.
|
||||
*/
|
||||
public LoginEvent: EventEmitter<UserInfo> = new EventEmitter<UserInfo>();
|
||||
|
||||
/**
|
||||
* The LogoutEvent is emitted, when the user has been logged out.
|
||||
*/
|
||||
public LogoutEvent: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
|
||||
constructor(private rest: ArchivaRequestService,
|
||||
private userService: UserService) {
|
||||
this.loggedIn = false;
|
||||
this.authenticated = false;
|
||||
this.restoreLoginData();
|
||||
}
|
||||
|
||||
|
@ -55,13 +60,35 @@ export class AuthenticationService {
|
|||
let expDate = new Date(expirationDate);
|
||||
let currentDate = new Date();
|
||||
if (currentDate < expDate) {
|
||||
this.loggedIn = true
|
||||
let observer = this.userService.retrieveUserInfo();
|
||||
observer.subscribe(userInfo =>
|
||||
observer.subscribe({
|
||||
next: (userInfo: UserInfo) => {
|
||||
if (userInfo != null) {
|
||||
let permObserver = this.userService.retrievePermissionInfo();
|
||||
permObserver.subscribe({
|
||||
next: () => {
|
||||
this.authenticated = true;
|
||||
this.LoginEvent.emit(userInfo)
|
||||
);
|
||||
},
|
||||
error: (err) => {
|
||||
console.debug("Error retrieving perms: " + JSON.stringify(err));
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
error: (err: HttpErrorResponse) => {
|
||||
console.debug("Error retrieving user info: " + JSON.stringify(err));
|
||||
this.logout();
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.logout();
|
||||
}
|
||||
} else {
|
||||
this.logout();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -94,9 +121,16 @@ export class AuthenticationService {
|
|||
localStorage.setItem("token_expire", dt.toISOString());
|
||||
}
|
||||
let userObserver = this.userService.retrieveUserInfo();
|
||||
this.loggedIn = true;
|
||||
userObserver.subscribe(userInfo =>
|
||||
this.LoginEvent.emit(userInfo));
|
||||
this.authenticated = true;
|
||||
userObserver.subscribe(userInfo => {
|
||||
if (userInfo != null) {
|
||||
let permObserver = this.userService.retrievePermissionInfo();
|
||||
permObserver.subscribe((perms) => {
|
||||
this.LoginEvent.emit(userInfo);
|
||||
}
|
||||
)
|
||||
}
|
||||
});
|
||||
resultHandler("OK");
|
||||
},
|
||||
error: (err: HttpErrorResponse) => {
|
||||
|
@ -104,7 +138,7 @@ export class AuthenticationService {
|
|||
let result = err.error as ErrorResult
|
||||
if (result.errorMessages != null) {
|
||||
for (let msg of result.errorMessages) {
|
||||
console.error('Observer got an error: ' + msg.errorKey)
|
||||
console.debug('Observer got an error: ' + msg.errorKey)
|
||||
}
|
||||
resultHandler("ERROR", result.errorMessages);
|
||||
} else {
|
||||
|
@ -125,8 +159,9 @@ export class AuthenticationService {
|
|||
localStorage.removeItem("access_token");
|
||||
localStorage.removeItem("refresh_token");
|
||||
localStorage.removeItem("token_expire");
|
||||
this.loggedIn = false;
|
||||
this.authenticated = false;
|
||||
this.userService.resetUser();
|
||||
this.rest.resetToken();
|
||||
this.LogoutEvent.emit();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,23 +16,77 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Injectable, OnDestroy, OnInit} 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";
|
||||
import {Permission} from '../model/permission';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class UserService {
|
||||
export class UserService implements OnInit, OnDestroy {
|
||||
|
||||
userInfo: UserInfo;
|
||||
permissions: Permission[];
|
||||
guestPermissions: Permission[];
|
||||
authenticated: boolean;
|
||||
uiPermissionsDefault = {
|
||||
'menu': {
|
||||
'repo':{
|
||||
'section':true,
|
||||
'browse':true,
|
||||
'search':true,
|
||||
'upload':false
|
||||
},
|
||||
'admin':{
|
||||
'section':false,
|
||||
'config':false,
|
||||
'status':false,
|
||||
'reports':false
|
||||
},
|
||||
'user':{
|
||||
'section':false,
|
||||
'manage':false,
|
||||
'roles':false,
|
||||
'config':false
|
||||
}
|
||||
}
|
||||
};
|
||||
uiPermissions;
|
||||
|
||||
constructor(private rest: ArchivaRequestService) {
|
||||
this.userInfo = new UserInfo()
|
||||
this.userInfo = new UserInfo();
|
||||
this.uiPermissions = {};
|
||||
this.deepCopy(this.uiPermissionsDefault, this.uiPermissions);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.resetUser();
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.userInfo.user_id = "guest";
|
||||
this.loadPersistedUserInfo();
|
||||
this.authenticated = false;
|
||||
this.deepCopy(this.uiPermissionsDefault, this.uiPermissions);
|
||||
if (this.guestPermissions == null) {
|
||||
let observer = {
|
||||
next: (permList: Permission[]) => {
|
||||
this.guestPermissions = permList;
|
||||
if (!this.authenticated) {
|
||||
this.permissions = this.guestPermissions;
|
||||
this.parsePermissions(this.permissions);
|
||||
}
|
||||
},
|
||||
error: err => {
|
||||
console.log("Could not retrieve permissions "+err);
|
||||
}
|
||||
}
|
||||
this.retrievePermissionInfo().subscribe(observer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -53,16 +107,20 @@ export class UserService {
|
|||
this.loadPersistedUserInfo();
|
||||
}
|
||||
this.persistUserInfo();
|
||||
this.authenticated = true;
|
||||
resultObserver.next(this.userInfo);
|
||||
},
|
||||
error: (err: HttpErrorResponse) => {
|
||||
console.log("Error " + (JSON.stringify(err)));
|
||||
let result = err.error as ErrorResult
|
||||
if (result.errorMessages != null) {
|
||||
if (result != null && result.errorMessages != null) {
|
||||
for (let msg of result.errorMessages) {
|
||||
console.error('Observer got an error: ' + msg.errorKey)
|
||||
}
|
||||
} else if (err.message != null) {
|
||||
console.error("Bad response from user info call: " + err.message);
|
||||
}
|
||||
this.authenticated = false;
|
||||
resultObserver.error();
|
||||
},
|
||||
complete: () => {
|
||||
|
@ -74,6 +132,96 @@ export class UserService {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the permission list from the REST service
|
||||
*/
|
||||
public retrievePermissionInfo(): Observable<Permission[]> {
|
||||
return new Observable<Permission[]>((resultObserver) => {
|
||||
let userName = this.authenticated ? "me" : "guest";
|
||||
let infoObserver = this.rest.executeRestCall<Permission[]>("get", "redback", "users/" + userName + "/permissions", null);
|
||||
let permissionObserver = {
|
||||
next: (x: Permission[]) => {
|
||||
this.permissions = x;
|
||||
this.parsePermissions(x);
|
||||
resultObserver.next(this.permissions);
|
||||
},
|
||||
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.debug('Observer got an error: ' + msg.errorKey)
|
||||
}
|
||||
}
|
||||
this.resetPermissions();
|
||||
resultObserver.error(err);
|
||||
},
|
||||
complete: () => {
|
||||
resultObserver.complete();
|
||||
}
|
||||
};
|
||||
infoObserver.subscribe(permissionObserver);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
resetPermissions() {
|
||||
this.deepCopy(this.uiPermissionsDefault, this.uiPermissions);
|
||||
}
|
||||
parsePermissions(permissions: Permission[]) {
|
||||
this.resetPermissions();
|
||||
for ( let perm of permissions) {
|
||||
// console.debug("Checking permission for op: " + perm.operation.name);
|
||||
switch (perm.operation.name) {
|
||||
case "archiva-manage-configuration": {
|
||||
if (perm.resource.identifier=='*') {
|
||||
this.uiPermissions.menu.admin.section = true;
|
||||
this.uiPermissions.menu.admin.config = true;
|
||||
this.uiPermissions.menu.admin.reports = true;
|
||||
this.uiPermissions.menu.admin.status = true;
|
||||
}
|
||||
|
||||
}
|
||||
case "archiva-manage-users": {
|
||||
if (perm.resource.identifier=='*') {
|
||||
this.uiPermissions.menu.user.section = true;
|
||||
this.uiPermissions.menu.user.config = true;
|
||||
this.uiPermissions.menu.user.manage = true;
|
||||
this.uiPermissions.menu.user.roles = true;
|
||||
}
|
||||
}
|
||||
case "redback-configuration-edit": {
|
||||
if (perm.resource.identifier=='*') {
|
||||
this.uiPermissions.menu.user.section = true;
|
||||
this.uiPermissions.menu.user.config = true;
|
||||
}
|
||||
}
|
||||
case "archiva-upload-file": {
|
||||
this.uiPermissions.menu.repo.upload = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log("New permissions: " + JSON.stringify(this.uiPermissions));
|
||||
}
|
||||
|
||||
private deepCopy(src: Object, dst: Object) {
|
||||
Object.keys(src).forEach((key, idx) => {
|
||||
let srcEl = src[key];
|
||||
if (typeof(srcEl)=='object' ) {
|
||||
let dstEl;
|
||||
if (!dst.hasOwnProperty(key)) {
|
||||
dst[key] = {}
|
||||
}
|
||||
dstEl = dst[key];
|
||||
this.deepCopy(srcEl, dstEl);
|
||||
} else {
|
||||
// console.debug("setting " + key + " = " + srcEl);
|
||||
dst[key] = srcEl;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stores user information persistent. Not the complete UserInfo object, only properties, that
|
||||
* are needed.
|
||||
|
@ -104,6 +252,9 @@ export class UserService {
|
|||
*/
|
||||
resetUser() {
|
||||
this.userInfo = new UserInfo();
|
||||
this.userInfo.user_id = "guest";
|
||||
this.resetPermissions();
|
||||
this.authenticated = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue