mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
70373: Login as EPerson intermediate commit
This commit is contained in:
@@ -170,6 +170,14 @@
|
||||
|
||||
|
||||
|
||||
"admin.access-control.epeople.actions.delete": "Delete EPerson",
|
||||
|
||||
"admin.access-control.epeople.actions.impersonate": "Impersonate EPerson",
|
||||
|
||||
"admin.access-control.epeople.actions.reset": "Reset password",
|
||||
|
||||
"admin.access-control.epeople.actions.stop-impersonating": "Stop impersonating EPerson",
|
||||
|
||||
"admin.access-control.epeople.title": "DSpace Angular :: EPeople",
|
||||
|
||||
"admin.access-control.epeople.head": "EPeople",
|
||||
|
@@ -14,6 +14,18 @@
|
||||
[formLayout]="formLayout"
|
||||
(cancel)="onCancel()"
|
||||
(submitForm)="onSubmit()">
|
||||
<button class="btn btn-light" [disabled]="!(canReset$ | async)">
|
||||
<i class="fa fa-key"></i> {{'admin.access-control.epeople.actions.reset' | translate}}
|
||||
</button>
|
||||
<button class="btn btn-light" [disabled]="!(canDelete$ | async)">
|
||||
<i class="fa fa-trash"></i> {{'admin.access-control.epeople.actions.delete' | translate}}
|
||||
</button>
|
||||
<button *ngIf="!isImpersonated" class="btn btn-light" [disabled]="!(canImpersonate$ | async)" (click)="impersonate()">
|
||||
<i class="fa fa-user-secret"></i> {{'admin.access-control.epeople.actions.impersonate' | translate}}
|
||||
</button>
|
||||
<button *ngIf="isImpersonated" class="btn btn-light" (click)="stopImpersonating()">
|
||||
<i class="fa fa-user-secret"></i> {{'admin.access-control.epeople.actions.stop-impersonating' | translate}}
|
||||
</button>
|
||||
</ds-form>
|
||||
|
||||
<div *ngIf="epersonService.getActiveEPerson() | async">
|
||||
|
@@ -7,7 +7,7 @@ import {
|
||||
DynamicInputModel
|
||||
} from '@ng-dynamic-forms/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Subscription, combineLatest } from 'rxjs';
|
||||
import { Subscription, combineLatest, of } from 'rxjs';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { RestResponse } from '../../../../core/cache/response.models';
|
||||
@@ -22,6 +22,7 @@ import { hasValue } from '../../../../shared/empty.util';
|
||||
import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service';
|
||||
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
|
||||
import { PaginationComponentOptions } from '../../../../shared/pagination/pagination-component-options.model';
|
||||
import { AuthService } from '../../../../core/auth/auth.service';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-eperson-form',
|
||||
@@ -105,6 +106,24 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
|
||||
*/
|
||||
@Output() cancelForm: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
/**
|
||||
* Observable whether or not the admin is allowed to reset the EPerson's password
|
||||
* TODO: Initialize the observable once the REST API supports this (currently hardcoded to return false)
|
||||
*/
|
||||
canReset$: Observable<boolean> = of(false);
|
||||
|
||||
/**
|
||||
* Observable whether or not the admin is allowed to delete the EPerson
|
||||
* TODO: Initialize the observable once the REST API supports this (currently hardcoded to return false)
|
||||
*/
|
||||
canDelete$: Observable<boolean> = of(false);
|
||||
|
||||
/**
|
||||
* Observable whether or not the admin is allowed to impersonate the EPerson
|
||||
* TODO: Initialize the observable once the REST API supports this (currently hardcoded to return true)
|
||||
*/
|
||||
canImpersonate$: Observable<boolean> = of(true);
|
||||
|
||||
/**
|
||||
* List of subscriptions
|
||||
*/
|
||||
@@ -129,13 +148,20 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
|
||||
*/
|
||||
epersonInitial: EPerson;
|
||||
|
||||
/**
|
||||
* Whether or not this EPerson is currently being impersonated
|
||||
*/
|
||||
isImpersonated = false;
|
||||
|
||||
constructor(public epersonService: EPersonDataService,
|
||||
public groupsDataService: GroupDataService,
|
||||
private formBuilderService: FormBuilderService,
|
||||
private translateService: TranslateService,
|
||||
private notificationsService: NotificationsService,) {
|
||||
private notificationsService: NotificationsService,
|
||||
private authService: AuthService) {
|
||||
this.subs.push(this.epersonService.getActiveEPerson().subscribe((eperson: EPerson) => {
|
||||
this.epersonInitial = eperson;
|
||||
this.isImpersonated = this.authService.isImpersonatingUser(eperson.id);
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -364,6 +390,22 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Start impersonating the EPerson
|
||||
*/
|
||||
impersonate() {
|
||||
this.authService.impersonate(this.epersonInitial.id);
|
||||
this.isImpersonated = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop impersonating the EPerson
|
||||
*/
|
||||
stopImpersonating() {
|
||||
this.authService.stopImpersonating();
|
||||
this.isImpersonated = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the current edit when component is destroyed & unsub all subscriptions
|
||||
*/
|
||||
|
@@ -18,7 +18,7 @@ import { AppState } from '../../app.reducer';
|
||||
import { AuthService } from './auth.service';
|
||||
import { AuthStatus } from './models/auth-status.model';
|
||||
import { AuthTokenInfo } from './models/auth-token-info.model';
|
||||
import { isNotEmpty, isNotNull, isUndefined } from '../../shared/empty.util';
|
||||
import { hasValue, isNotEmpty, isNotNull, isUndefined } from '../../shared/empty.util';
|
||||
import { RedirectWhenTokenExpiredAction, RefreshTokenAction } from './auth.actions';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Router } from '@angular/router';
|
||||
@@ -235,8 +235,16 @@ export class AuthInterceptor implements HttpInterceptor {
|
||||
});
|
||||
// Get the auth header from the service.
|
||||
authorization = authService.buildAuthHeader(token);
|
||||
let newHeaders = req.headers.set('authorization', authorization);
|
||||
|
||||
// When present, add the ID of the EPerson we're impersonating to the headers
|
||||
const impersonatingID = authService.getImpersonateID();
|
||||
if (hasValue(impersonatingID)) {
|
||||
newHeaders = newHeaders.set('X-On-Behalf-Of', impersonatingID);
|
||||
}
|
||||
|
||||
// Clone the request to add the new header.
|
||||
newReq = req.clone({ headers: req.headers.set('authorization', authorization) });
|
||||
newReq = req.clone({ headers: newHeaders });
|
||||
} else {
|
||||
newReq = req.clone();
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@ import { AuthRequestService } from './auth-request.service';
|
||||
import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
|
||||
import { AuthStatus } from './models/auth-status.model';
|
||||
import { AuthTokenInfo, TOKENITEM } from './models/auth-token-info.model';
|
||||
import { isEmpty, isNotEmpty, isNotNull, isNotUndefined } from '../../shared/empty.util';
|
||||
import { hasValue, isEmpty, isNotEmpty, isNotNull, isNotUndefined } from '../../shared/empty.util';
|
||||
import { CookieService } from '../services/cookie.service';
|
||||
import { getAuthenticationToken, getRedirectUrl, isAuthenticated, isTokenRefreshing } from './selectors';
|
||||
import { AppState, routerStateSelector } from '../../app.reducer';
|
||||
@@ -33,6 +33,7 @@ import { AuthMethod } from './models/auth.method';
|
||||
export const LOGIN_ROUTE = '/login';
|
||||
export const LOGOUT_ROUTE = '/logout';
|
||||
export const REDIRECT_COOKIE = 'dsRedirectUrl';
|
||||
export const IMPERSONATING_COOKIE = 'dsImpersonatingEPerson';
|
||||
|
||||
/**
|
||||
* The auth service.
|
||||
@@ -469,4 +470,44 @@ export class AuthService {
|
||||
this.storage.remove(REDIRECT_COOKIE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start impersonating EPerson
|
||||
* @param epersonId ID of the EPerson to impersonate
|
||||
*/
|
||||
impersonate(epersonId: string) {
|
||||
this.storage.set(IMPERSONATING_COOKIE, epersonId);
|
||||
this.refreshAfterLogout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop impersonating EPerson
|
||||
*/
|
||||
stopImpersonating() {
|
||||
this.storage.remove(IMPERSONATING_COOKIE);
|
||||
this.refreshAfterLogout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ID of the EPerson we're currently impersonating
|
||||
* Returns undefined if we're not impersonating anyone
|
||||
*/
|
||||
getImpersonateID(): string {
|
||||
return this.storage.get(IMPERSONATING_COOKIE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not we are currently impersonating an EPerson
|
||||
*/
|
||||
isImpersonating(): boolean {
|
||||
return hasValue(this.getImpersonateID());
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not we are currently impersonating a specific EPerson
|
||||
* @param epersonId ID of the EPerson to check
|
||||
*/
|
||||
isImpersonatingUser(epersonId: string): boolean {
|
||||
return this.getImpersonateID() === epersonId;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -45,6 +45,8 @@
|
||||
|
||||
</ds-dynamic-form>
|
||||
|
||||
<ng-content></ng-content>
|
||||
|
||||
<div *ngIf="displaySubmit">
|
||||
<hr>
|
||||
<div class="form-group row">
|
||||
|
Reference in New Issue
Block a user