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.title": "DSpace Angular :: EPeople",
|
||||||
|
|
||||||
"admin.access-control.epeople.head": "EPeople",
|
"admin.access-control.epeople.head": "EPeople",
|
||||||
|
@@ -14,6 +14,18 @@
|
|||||||
[formLayout]="formLayout"
|
[formLayout]="formLayout"
|
||||||
(cancel)="onCancel()"
|
(cancel)="onCancel()"
|
||||||
(submitForm)="onSubmit()">
|
(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>
|
</ds-form>
|
||||||
|
|
||||||
<div *ngIf="epersonService.getActiveEPerson() | async">
|
<div *ngIf="epersonService.getActiveEPerson() | async">
|
||||||
|
@@ -7,7 +7,7 @@ import {
|
|||||||
DynamicInputModel
|
DynamicInputModel
|
||||||
} from '@ng-dynamic-forms/core';
|
} from '@ng-dynamic-forms/core';
|
||||||
import { TranslateService } from '@ngx-translate/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 { Observable } from 'rxjs/internal/Observable';
|
||||||
import { take } from 'rxjs/operators';
|
import { take } from 'rxjs/operators';
|
||||||
import { RestResponse } from '../../../../core/cache/response.models';
|
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 { FormBuilderService } from '../../../../shared/form/builder/form-builder.service';
|
||||||
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
|
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
|
||||||
import { PaginationComponentOptions } from '../../../../shared/pagination/pagination-component-options.model';
|
import { PaginationComponentOptions } from '../../../../shared/pagination/pagination-component-options.model';
|
||||||
|
import { AuthService } from '../../../../core/auth/auth.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-eperson-form',
|
selector: 'ds-eperson-form',
|
||||||
@@ -105,6 +106,24 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
|
|||||||
*/
|
*/
|
||||||
@Output() cancelForm: EventEmitter<any> = new EventEmitter();
|
@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
|
* List of subscriptions
|
||||||
*/
|
*/
|
||||||
@@ -129,13 +148,20 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
|
|||||||
*/
|
*/
|
||||||
epersonInitial: EPerson;
|
epersonInitial: EPerson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not this EPerson is currently being impersonated
|
||||||
|
*/
|
||||||
|
isImpersonated = false;
|
||||||
|
|
||||||
constructor(public epersonService: EPersonDataService,
|
constructor(public epersonService: EPersonDataService,
|
||||||
public groupsDataService: GroupDataService,
|
public groupsDataService: GroupDataService,
|
||||||
private formBuilderService: FormBuilderService,
|
private formBuilderService: FormBuilderService,
|
||||||
private translateService: TranslateService,
|
private translateService: TranslateService,
|
||||||
private notificationsService: NotificationsService,) {
|
private notificationsService: NotificationsService,
|
||||||
|
private authService: AuthService) {
|
||||||
this.subs.push(this.epersonService.getActiveEPerson().subscribe((eperson: EPerson) => {
|
this.subs.push(this.epersonService.getActiveEPerson().subscribe((eperson: EPerson) => {
|
||||||
this.epersonInitial = 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
|
* 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 { AuthService } from './auth.service';
|
||||||
import { AuthStatus } from './models/auth-status.model';
|
import { AuthStatus } from './models/auth-status.model';
|
||||||
import { AuthTokenInfo } from './models/auth-token-info.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 { RedirectWhenTokenExpiredAction, RefreshTokenAction } from './auth.actions';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
@@ -235,8 +235,16 @@ export class AuthInterceptor implements HttpInterceptor {
|
|||||||
});
|
});
|
||||||
// Get the auth header from the service.
|
// Get the auth header from the service.
|
||||||
authorization = authService.buildAuthHeader(token);
|
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.
|
// Clone the request to add the new header.
|
||||||
newReq = req.clone({ headers: req.headers.set('authorization', authorization) });
|
newReq = req.clone({ headers: newHeaders });
|
||||||
} else {
|
} else {
|
||||||
newReq = req.clone();
|
newReq = req.clone();
|
||||||
}
|
}
|
||||||
|
@@ -14,7 +14,7 @@ import { AuthRequestService } from './auth-request.service';
|
|||||||
import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
|
import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
|
||||||
import { AuthStatus } from './models/auth-status.model';
|
import { AuthStatus } from './models/auth-status.model';
|
||||||
import { AuthTokenInfo, TOKENITEM } from './models/auth-token-info.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 { CookieService } from '../services/cookie.service';
|
||||||
import { getAuthenticationToken, getRedirectUrl, isAuthenticated, isTokenRefreshing } from './selectors';
|
import { getAuthenticationToken, getRedirectUrl, isAuthenticated, isTokenRefreshing } from './selectors';
|
||||||
import { AppState, routerStateSelector } from '../../app.reducer';
|
import { AppState, routerStateSelector } from '../../app.reducer';
|
||||||
@@ -33,6 +33,7 @@ import { AuthMethod } from './models/auth.method';
|
|||||||
export const LOGIN_ROUTE = '/login';
|
export const LOGIN_ROUTE = '/login';
|
||||||
export const LOGOUT_ROUTE = '/logout';
|
export const LOGOUT_ROUTE = '/logout';
|
||||||
export const REDIRECT_COOKIE = 'dsRedirectUrl';
|
export const REDIRECT_COOKIE = 'dsRedirectUrl';
|
||||||
|
export const IMPERSONATING_COOKIE = 'dsImpersonatingEPerson';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The auth service.
|
* The auth service.
|
||||||
@@ -469,4 +470,44 @@ export class AuthService {
|
|||||||
this.storage.remove(REDIRECT_COOKIE);
|
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>
|
</ds-dynamic-form>
|
||||||
|
|
||||||
|
<ng-content></ng-content>
|
||||||
|
|
||||||
<div *ngIf="displaySubmit">
|
<div *ngIf="displaySubmit">
|
||||||
<hr>
|
<hr>
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
|
Reference in New Issue
Block a user