mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-14 13:33:03 +00:00
Dynamic rendering of auth methods via decorator
This commit is contained in:
@@ -3,8 +3,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<img class="mb-4 login-logo" src="assets/images/dspace-logo.png">
|
<img class="mb-4 login-logo" src="assets/images/dspace-logo.png">
|
||||||
<h1 class="h3 mb-0 font-weight-normal">{{"login.form.header" | translate}}</h1>
|
<h1 class="h3 mb-0 font-weight-normal">{{"login.form.header" | translate}}</h1>
|
||||||
<!-- <ds-log-in></ds-log-in>-->
|
<ds-login-container></ds-login-container>
|
||||||
<ds-log-in></ds-log-in>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,30 +1,32 @@
|
|||||||
|
import {AuthMethodType} from '../../../shared/log-in/authMethods-type';
|
||||||
|
|
||||||
export class AuthMethodModel {
|
export class AuthMethodModel {
|
||||||
authMethodName: string;
|
authMethodName: string;
|
||||||
location?: string;
|
location?: string;
|
||||||
authMethodConstant: AuthMethodType
|
authMethodType: AuthMethodType
|
||||||
|
|
||||||
constructor(authMethodName: string, location?: string) {
|
constructor(authMethodName: string, location?: string) {
|
||||||
this.authMethodName = authMethodName;
|
this.authMethodName = authMethodName;
|
||||||
this.location = location;
|
this.location = location;
|
||||||
switch (authMethodName) {
|
switch (authMethodName) {
|
||||||
case 'ip': {
|
case 'ip': {
|
||||||
this.authMethodConstant = AuthMethodType.Ip;
|
this.authMethodType = AuthMethodType.Ip;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'ldap': {
|
case 'ldap': {
|
||||||
this.authMethodConstant = AuthMethodType.Ldap;
|
this.authMethodType = AuthMethodType.Ldap;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'shibboleth': {
|
case 'shibboleth': {
|
||||||
this.authMethodConstant = AuthMethodType.Shibboleth;
|
this.authMethodType = AuthMethodType.Shibboleth;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'x509': {
|
case 'x509': {
|
||||||
this.authMethodConstant = AuthMethodType.X509;
|
this.authMethodType = AuthMethodType.X509;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'password': {
|
case 'password': {
|
||||||
this.authMethodConstant = AuthMethodType.Password;
|
this.authMethodType = AuthMethodType.Password;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,11 +36,3 @@ export class AuthMethodModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AuthMethodType {
|
|
||||||
Password = 'password',
|
|
||||||
Shibboleth = 'shibboleth',
|
|
||||||
Ldap = 'ldap',
|
|
||||||
Ip = 'ip',
|
|
||||||
X509 = 'x509'
|
|
||||||
}
|
|
||||||
|
@@ -3,8 +3,8 @@
|
|||||||
<div ngbDropdown placement="bottom-right" class="d-inline-block" @fadeInOut>
|
<div ngbDropdown placement="bottom-right" class="d-inline-block" @fadeInOut>
|
||||||
<a href="#" id="dropdownLogin" (click)="$event.preventDefault()" ngbDropdownToggle class="px-1">{{ 'nav.login' | translate }}</a>
|
<a href="#" id="dropdownLogin" (click)="$event.preventDefault()" ngbDropdownToggle class="px-1">{{ 'nav.login' | translate }}</a>
|
||||||
<div id="loginDropdownMenu" [ngClass]="{'pl-3 pr-3': (loading | async)}" ngbDropdownMenu aria-labelledby="dropdownLogin">
|
<div id="loginDropdownMenu" [ngClass]="{'pl-3 pr-3': (loading | async)}" ngbDropdownMenu aria-labelledby="dropdownLogin">
|
||||||
<!-- <ds-log-in></ds-log-in>-->
|
<!-- <ds-log-in></ds-log-in>-->
|
||||||
<ds-log-in></ds-log-in>
|
<ds-login-container></ds-login-container>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
15
src/app/shared/log-in/authMethods-decorator.ts
Normal file
15
src/app/shared/log-in/authMethods-decorator.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { AuthMethodType } from './authMethods-type';
|
||||||
|
|
||||||
|
const authMethodsMap = new Map();
|
||||||
|
export function renderAuthMethodFor(authMethodType: AuthMethodType) {
|
||||||
|
return function decorator(objectElement: any) {
|
||||||
|
if (!objectElement) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
authMethodsMap.set(authMethodType, objectElement);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function rendersAuthMethodType(authMethodType: AuthMethodType) {
|
||||||
|
return authMethodsMap.get(authMethodType);
|
||||||
|
}
|
7
src/app/shared/log-in/authMethods-type.ts
Normal file
7
src/app/shared/log-in/authMethods-type.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export enum AuthMethodType {
|
||||||
|
Password = 'password',
|
||||||
|
Shibboleth = 'shibboleth',
|
||||||
|
Ldap = 'ldap',
|
||||||
|
Ip = 'ip',
|
||||||
|
X509 = 'x509'
|
||||||
|
}
|
@@ -0,0 +1,3 @@
|
|||||||
|
<div *ngFor="let authMethod of authMethodData | async">
|
||||||
|
<ng-container *ngComponentOutlet="getAuthMethodContent(authMethod.authMethodType); injector: objectInjector;"></ng-container>
|
||||||
|
</div>
|
@@ -0,0 +1,21 @@
|
|||||||
|
:host /deep/ .card {
|
||||||
|
margin-bottom: $submission-sections-margin-bottom;
|
||||||
|
overflow: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-focus {
|
||||||
|
border-radius: $border-radius;
|
||||||
|
box-shadow: $btn-focus-box-shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO to remove the following when upgrading @ng-bootstrap
|
||||||
|
:host /deep/ .card:first-of-type {
|
||||||
|
border-bottom: $card-border-width solid $card-border-color !important;
|
||||||
|
border-bottom-left-radius: $card-border-radius !important;
|
||||||
|
border-bottom-right-radius: $card-border-radius !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host /deep/ .card-header button {
|
||||||
|
box-shadow: none !important;
|
||||||
|
width: 100%;
|
||||||
|
}
|
60
src/app/shared/log-in/container/login-container.component.ts
Normal file
60
src/app/shared/log-in/container/login-container.component.ts
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import { Component, Injector, Input, OnInit, ViewChild } from '@angular/core';
|
||||||
|
import { rendersAuthMethodType } from '../authMethods-decorator';
|
||||||
|
import { AuthMethodModel } from '../../../core/auth/models/auth-method.model';
|
||||||
|
import { getAuthenticationMethods } from '../../../core/auth/selectors';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { AppState } from '../../../app.reducer';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { AuthMethodType } from '../authMethods-type';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component represents a section that contains the submission license form.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-login-container',
|
||||||
|
templateUrl: './login-container.component.html',
|
||||||
|
styleUrls: ['./login-container.component.scss']
|
||||||
|
})
|
||||||
|
export class LoginContainerComponent implements OnInit {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The section data
|
||||||
|
* @type {SectionDataObject}
|
||||||
|
*/
|
||||||
|
@Input() authMethodData: Observable<AuthMethodModel[]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injector to inject a section component with the @Input parameters
|
||||||
|
* @type {Injector}
|
||||||
|
*/
|
||||||
|
public objectInjector: Injector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize instance variables
|
||||||
|
*
|
||||||
|
* @param {Injector} injector
|
||||||
|
*/
|
||||||
|
constructor(private injector: Injector, private store: Store<AppState>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize all instance variables
|
||||||
|
*/
|
||||||
|
ngOnInit() {
|
||||||
|
this.objectInjector = Injector.create({
|
||||||
|
providers: [
|
||||||
|
{provide: 'authMethodProvider', useFactory: () => (this.authMethodData), deps: []},
|
||||||
|
],
|
||||||
|
parent: this.injector
|
||||||
|
});
|
||||||
|
|
||||||
|
this.authMethodData = this.store.select(getAuthenticationMethods);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the correct component based on the authMethod's type
|
||||||
|
*/
|
||||||
|
getAuthMethodContent(authMethodType: AuthMethodType): string {
|
||||||
|
return rendersAuthMethodType(authMethodType)
|
||||||
|
}
|
||||||
|
}
|
@@ -1,12 +0,0 @@
|
|||||||
<br>
|
|
||||||
<div *ngFor="let method of dynamicLoginMethods | async; let i = index" >
|
|
||||||
|
|
||||||
|
|
||||||
<!-- <div class="dropdown-divider"></div>-->
|
|
||||||
<br *ngIf="i >= 1">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<ng-container *ngComponentOutlet="method.component; injector: objectInjector;">
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
|
@@ -1,84 +0,0 @@
|
|||||||
import {Component, Injector, OnDestroy, OnInit} from '@angular/core';
|
|
||||||
import {Store} from '@ngrx/store';
|
|
||||||
import {DynamicShibbolethComponent} from './methods/shibboleth/dynamic-shibboleth.component';
|
|
||||||
import {getAuthenticationMethods} from '../../core/auth/selectors';
|
|
||||||
import {map} from 'rxjs/operators';
|
|
||||||
import {AppState} from '../../app.reducer';
|
|
||||||
import {Observable} from 'rxjs';
|
|
||||||
import {AuthMethodType} from '../../core/auth/models/auth-method.model';
|
|
||||||
import {DynamicLoginMethod} from './log-in.model';
|
|
||||||
import {LogInPasswordComponent} from './methods/password/log-in-password.component';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'ds-log-in',
|
|
||||||
templateUrl: './log-in.component.html',
|
|
||||||
styleUrls: ['./log-in.component.scss'],
|
|
||||||
|
|
||||||
})
|
|
||||||
export class LogInComponent implements OnDestroy, OnInit {
|
|
||||||
|
|
||||||
public dynamicLoginMethods: Observable<DynamicLoginMethod[]>;
|
|
||||||
/**
|
|
||||||
* Injector to inject a section component with the @Input parameters
|
|
||||||
* @type {Injector}
|
|
||||||
*/
|
|
||||||
public objectInjector: Injector;
|
|
||||||
private shibbolethUrl: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @constructor
|
|
||||||
* @param {Store<State>} store
|
|
||||||
* @param {Injector} injector
|
|
||||||
*/
|
|
||||||
constructor(
|
|
||||||
private store: Store<AppState>,
|
|
||||||
private injector: Injector
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lifecycle hook that is called after data-bound properties of a directive are initialized.
|
|
||||||
* @method ngOnInit
|
|
||||||
*/
|
|
||||||
public ngOnInit() {
|
|
||||||
|
|
||||||
this.objectInjector = Injector.create({
|
|
||||||
providers: [
|
|
||||||
{provide: 'shibbolethUrlProvider', useFactory: () => (this.shibbolethUrl), deps: []},
|
|
||||||
// if other authentication methods need further data to work add a provider here e.g
|
|
||||||
// {provide: 'otherDataProvider', useFactory: () => (this.otherData), deps: []},
|
|
||||||
],
|
|
||||||
parent: this.injector
|
|
||||||
});
|
|
||||||
|
|
||||||
this.dynamicLoginMethods = this.store.select(getAuthenticationMethods).pipe(
|
|
||||||
map(((authMethods) => authMethods.map((authMethod) => {
|
|
||||||
switch (authMethod.authMethodConstant) {
|
|
||||||
case AuthMethodType.Password:
|
|
||||||
return new DynamicLoginMethod(authMethod.authMethodName, LogInPasswordComponent)
|
|
||||||
break;
|
|
||||||
case AuthMethodType.Shibboleth:
|
|
||||||
this.shibbolethUrl = authMethod.location;
|
|
||||||
// this.shibbolethUrl = 'https://fis.tiss.tuwien.ac.at/Shibboleth.sso/Login?target=https://fis.tiss.tuwien.ac.at/shibboleth';
|
|
||||||
return new DynamicLoginMethod(authMethod.authMethodName, DynamicShibbolethComponent, authMethod.location)
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lifecycle hook that is called when a directive, pipe or service is destroyed.
|
|
||||||
* @method ngOnDestroy
|
|
||||||
*/
|
|
||||||
public ngOnDestroy() {
|
|
||||||
// console.log('ngOnDestroy() in LogInContainerComponent was called');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
export class DynamicLoginMethod {
|
|
||||||
label: string;
|
|
||||||
component: any;
|
|
||||||
location?: string;
|
|
||||||
|
|
||||||
constructor(label, component, location?) {
|
|
||||||
this.label = label;
|
|
||||||
this.component = component;
|
|
||||||
this.location = location;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -20,6 +20,8 @@ import {CoreState} from '../../../../core/core.reducers';
|
|||||||
import {isNotEmpty} from '../../../empty.util';
|
import {isNotEmpty} from '../../../empty.util';
|
||||||
import {fadeOut} from '../../../animations/fade';
|
import {fadeOut} from '../../../animations/fade';
|
||||||
import {AuthService} from '../../../../core/auth/auth.service';
|
import {AuthService} from '../../../../core/auth/auth.service';
|
||||||
|
import { AuthMethodType } from '../../authMethods-type';
|
||||||
|
import { renderAuthMethodFor } from '../../authMethods-decorator';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* /users/sign-in
|
* /users/sign-in
|
||||||
@@ -31,6 +33,7 @@ import {AuthService} from '../../../../core/auth/auth.service';
|
|||||||
styleUrls: ['./log-in-password.component.scss'],
|
styleUrls: ['./log-in-password.component.scss'],
|
||||||
animations: [fadeOut]
|
animations: [fadeOut]
|
||||||
})
|
})
|
||||||
|
@renderAuthMethodFor(AuthMethodType.Password)
|
||||||
export class LogInPasswordComponent implements OnDestroy, OnInit {
|
export class LogInPasswordComponent implements OnDestroy, OnInit {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
|
|
||||||
import {Component, Inject, Input, OnInit} from '@angular/core';
|
import {Component, Inject, Input, OnInit} from '@angular/core';
|
||||||
|
import { renderAuthMethodFor } from '../../authMethods-decorator';
|
||||||
|
import { AuthMethodType } from '../../authMethods-type';
|
||||||
|
import { AuthMethodModel } from '../../../../core/auth/models/auth-method.model';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-dynamic-shibboleth',
|
selector: 'ds-dynamic-shibboleth',
|
||||||
@@ -7,11 +9,17 @@ import {Component, Inject, Input, OnInit} from '@angular/core';
|
|||||||
styleUrls: ['./dynamic-shibboleth.component.scss'],
|
styleUrls: ['./dynamic-shibboleth.component.scss'],
|
||||||
|
|
||||||
})
|
})
|
||||||
export class DynamicShibbolethComponent {
|
@renderAuthMethodFor(AuthMethodType.Shibboleth)
|
||||||
|
export class DynamicShibbolethComponent implements OnInit {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
constructor(@Inject('shibbolethUrlProvider') public injectedShibbolethUrl: string) {
|
constructor(@Inject('authMethodProvider') public injectedObject: AuthMethodModel) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
console.log('injectedObject', this.injectedObject)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -138,8 +138,9 @@ import { UserMenuComponent } from './auth-nav-menu/user-menu/user-menu.component
|
|||||||
import { ClaimedTaskActionsReturnToPoolComponent } from './mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component';
|
import { ClaimedTaskActionsReturnToPoolComponent } from './mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component';
|
||||||
import { ItemDetailPreviewFieldComponent } from './object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component';
|
import { ItemDetailPreviewFieldComponent } from './object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component';
|
||||||
import {DynamicShibbolethComponent} from './log-in/methods/shibboleth/dynamic-shibboleth.component';
|
import {DynamicShibbolethComponent} from './log-in/methods/shibboleth/dynamic-shibboleth.component';
|
||||||
import {LogInComponent} from './log-in/log-in.component';
|
// import {LogInComponent} from './log-in/log-in.component';
|
||||||
import {LogInPasswordComponent} from './log-in/methods/password/log-in-password.component';
|
import {LogInPasswordComponent} from './log-in/methods/password/log-in-password.component';
|
||||||
|
import { LoginContainerComponent } from './log-in/container/login-container.component';
|
||||||
|
|
||||||
const MODULES = [
|
const MODULES = [
|
||||||
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
||||||
@@ -212,7 +213,7 @@ const COMPONENTS = [
|
|||||||
FormComponent,
|
FormComponent,
|
||||||
LangSwitchComponent,
|
LangSwitchComponent,
|
||||||
LoadingComponent,
|
LoadingComponent,
|
||||||
LogInComponent,
|
// LogInComponent,
|
||||||
LogOutComponent,
|
LogOutComponent,
|
||||||
NumberPickerComponent,
|
NumberPickerComponent,
|
||||||
ObjectListComponent,
|
ObjectListComponent,
|
||||||
@@ -260,9 +261,10 @@ const COMPONENTS = [
|
|||||||
TypedItemSearchResultListElementComponent,
|
TypedItemSearchResultListElementComponent,
|
||||||
ItemTypeSwitcherComponent,
|
ItemTypeSwitcherComponent,
|
||||||
BrowseByComponent,
|
BrowseByComponent,
|
||||||
LogInComponent,
|
// LogInComponent,
|
||||||
DynamicShibbolethComponent,
|
DynamicShibbolethComponent,
|
||||||
LogInPasswordComponent
|
LogInPasswordComponent,
|
||||||
|
LoginContainerComponent
|
||||||
];
|
];
|
||||||
|
|
||||||
const ENTRY_COMPONENTS = [
|
const ENTRY_COMPONENTS = [
|
||||||
|
Reference in New Issue
Block a user