|
|
@ -4,6 +4,9 @@ import { Filter, PortfolioPosition } from '@ghostfolio/common/interfaces'; |
|
|
import { |
|
|
import { |
|
|
SCOPES_OF_READ_ACCESS, |
|
|
SCOPES_OF_READ_ACCESS, |
|
|
SCOPES_OF_READ_RESTRICTED_ACCESS, |
|
|
SCOPES_OF_READ_RESTRICTED_ACCESS, |
|
|
|
|
|
SCOPES_OF_WRITE_ACCESS, |
|
|
|
|
|
Scope, |
|
|
|
|
|
hasAnyScopeOfWriteAccess, |
|
|
hasScope, |
|
|
hasScope, |
|
|
scopes |
|
|
scopes |
|
|
} from '@ghostfolio/common/scopes'; |
|
|
} from '@ghostfolio/common/scopes'; |
|
|
@ -49,7 +52,10 @@ import { MatSelectModule } from '@angular/material/select'; |
|
|
import { StatusCodes } from 'http-status-codes'; |
|
|
import { StatusCodes } from 'http-status-codes'; |
|
|
import { EMPTY, catchError } from 'rxjs'; |
|
|
import { EMPTY, catchError } from 'rxjs'; |
|
|
|
|
|
|
|
|
import { CreateOrUpdateAccessDialogParams } from './interfaces/interfaces'; |
|
|
import { |
|
|
|
|
|
AccessLevel, |
|
|
|
|
|
CreateOrUpdateAccessDialogParams |
|
|
|
|
|
} from './interfaces/interfaces'; |
|
|
|
|
|
|
|
|
@Component({ |
|
|
@Component({ |
|
|
changeDetection: ChangeDetectionStrategy.OnPush, |
|
|
changeDetection: ChangeDetectionStrategy.OnPush, |
|
|
@ -105,21 +111,22 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit { |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public get canGrantWriteAccess() { |
|
|
|
|
|
return this.hasExperimentalFeatures; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
public ngOnInit() { |
|
|
public ngOnInit() { |
|
|
const access = this.data?.access; |
|
|
const access = this.data?.access; |
|
|
const isPublic = access?.type === 'PUBLIC'; |
|
|
const isPublic = access?.type === 'PUBLIC'; |
|
|
|
|
|
|
|
|
this.accessForm = this.formBuilder.group({ |
|
|
this.accessForm = this.formBuilder.group({ |
|
|
|
|
|
accessLevel: this.getAccessLevel(access?.scopes), |
|
|
alias: [access?.alias ?? ''], |
|
|
alias: [access?.alias ?? ''], |
|
|
filters: [null], |
|
|
filters: [null], |
|
|
granteeUserId: [ |
|
|
granteeUserId: [ |
|
|
access?.grantee ?? null, |
|
|
access?.grantee ?? null, |
|
|
isPublic ? null : Validators.required |
|
|
isPublic ? null : Validators.required |
|
|
], |
|
|
], |
|
|
hasScopeToReadValues: hasScope( |
|
|
|
|
|
access?.scopes, |
|
|
|
|
|
scopes.portfolioReadValues |
|
|
|
|
|
), |
|
|
|
|
|
type: [ |
|
|
type: [ |
|
|
{ disabled: this.mode === 'update', value: access?.type ?? 'PRIVATE' }, |
|
|
{ disabled: this.mode === 'update', value: access?.type ?? 'PRIVATE' }, |
|
|
Validators.required |
|
|
Validators.required |
|
|
@ -145,10 +152,6 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit { |
|
|
.subscribe((accessType) => { |
|
|
.subscribe((accessType) => { |
|
|
const granteeUserIdControl = this.accessForm.get('granteeUserId'); |
|
|
const granteeUserIdControl = this.accessForm.get('granteeUserId'); |
|
|
|
|
|
|
|
|
const hasScopeToReadValuesControl = this.accessForm.get( |
|
|
|
|
|
'hasScopeToReadValues' |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
if (accessType === 'PRIVATE') { |
|
|
if (accessType === 'PRIVATE') { |
|
|
granteeUserIdControl?.setValidators(Validators.required); |
|
|
granteeUserIdControl?.setValidators(Validators.required); |
|
|
this.accessForm.get('filters')?.setValue(null); |
|
|
this.accessForm.get('filters')?.setValue(null); |
|
|
@ -156,8 +159,9 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit { |
|
|
granteeUserIdControl?.clearValidators(); |
|
|
granteeUserIdControl?.clearValidators(); |
|
|
granteeUserIdControl?.setValue(null); |
|
|
granteeUserIdControl?.setValue(null); |
|
|
|
|
|
|
|
|
// A public access never exposes the monetary values
|
|
|
// A public access never exposes the monetary values and never
|
|
|
hasScopeToReadValuesControl?.setValue(false); |
|
|
// changes data
|
|
|
|
|
|
this.accessForm.get('accessLevel')?.setValue('READ_RESTRICTED'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
granteeUserIdControl?.updateValueAndValidity(); |
|
|
granteeUserIdControl?.updateValueAndValidity(); |
|
|
@ -186,16 +190,29 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit { |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
private buildScopes(): Scope[] { |
|
|
* The dialog offers the read access only. The write scopes are not granted |
|
|
const accessLevel = this.accessForm.get('accessLevel') |
|
|
* here yet. |
|
|
?.value as AccessLevel; |
|
|
*/ |
|
|
|
|
|
private buildScopes() { |
|
|
const scopesOfAccess = this.data.access?.scopes ?? []; |
|
|
return [ |
|
|
|
|
|
...(this.accessForm.get('hasScopeToReadValues')?.value |
|
|
if ( |
|
|
? SCOPES_OF_READ_ACCESS |
|
|
scopesOfAccess.length > 0 && |
|
|
: SCOPES_OF_READ_RESTRICTED_ACCESS) |
|
|
accessLevel === this.getAccessLevel(scopesOfAccess) |
|
|
]; |
|
|
) { |
|
|
|
|
|
return Object.values(scopes).filter((scope) => { |
|
|
|
|
|
return hasScope(scopesOfAccess, scope); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
switch (accessLevel) { |
|
|
|
|
|
case 'CREATE_READ_UPDATE_DELETE': |
|
|
|
|
|
return [...SCOPES_OF_READ_ACCESS, ...SCOPES_OF_WRITE_ACCESS]; |
|
|
|
|
|
case 'READ': |
|
|
|
|
|
return [...SCOPES_OF_READ_ACCESS]; |
|
|
|
|
|
default: |
|
|
|
|
|
return [...SCOPES_OF_READ_RESTRICTED_ACCESS]; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private async createAccess() { |
|
|
private async createAccess() { |
|
|
@ -237,6 +254,16 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private getAccessLevel(scopesOfAccess: string[] | undefined): AccessLevel { |
|
|
|
|
|
if (hasAnyScopeOfWriteAccess(scopesOfAccess)) { |
|
|
|
|
|
return 'CREATE_READ_UPDATE_DELETE'; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return hasScope(scopesOfAccess, scopes.portfolioReadValues) |
|
|
|
|
|
? 'READ' |
|
|
|
|
|
: 'READ_RESTRICTED'; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
private loadHoldings() { |
|
|
private loadHoldings() { |
|
|
this.dataService |
|
|
this.dataService |
|
|
.fetchPortfolioHoldings() |
|
|
.fetchPortfolioHoldings() |
|
|
|