Browse Source

Add write access

pull/7676/head
Thomas Kaul 1 week ago
parent
commit
2db36f4acc
  1. 10
      apps/client/src/app/components/access-table/access-table.component.ts
  2. 59
      apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts
  3. 24
      apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html
  4. 2
      apps/client/src/app/components/user-account-access/create-or-update-access-dialog/interfaces/interfaces.ts

10
apps/client/src/app/components/access-table/access-table.component.ts

@ -1,7 +1,11 @@
import { ConfirmationDialogType } from '@ghostfolio/common/enums';
import { Access, User } from '@ghostfolio/common/interfaces';
import { publicRoutes } from '@ghostfolio/common/routes/routes';
import { hasScope, scopes } from '@ghostfolio/common/scopes';
import {
SCOPES_OF_WRITE_ACCESS,
hasScope,
scopes
} from '@ghostfolio/common/scopes';
import { NotificationService } from '@ghostfolio/ui/notifications';
import { Clipboard, ClipboardModule } from '@angular/cdk/clipboard';
@ -106,7 +110,9 @@ export class GfAccessTableComponent {
}
protected hasScopesToWrite({ scopes: scopesOfAccess }: Access) {
return hasScope(scopesOfAccess, scopes.activityCreate);
return SCOPES_OF_WRITE_ACCESS.some((scope) => {
return hasScope(scopesOfAccess, scope);
});
}
protected onCopyUrlToClipboard(aId: string) {

59
apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts

@ -5,6 +5,7 @@ import {
SCOPES_OF_READ_ACCESS,
SCOPES_OF_READ_RESTRICTED_ACCESS,
SCOPES_OF_WRITE_ACCESS,
Scope,
hasScope,
scopes
} from '@ghostfolio/common/scopes';
@ -47,11 +48,13 @@ import {
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { StatusCodes } from 'http-status-codes';
import { EMPTY, catchError } from 'rxjs';
import { CreateOrUpdateAccessDialogParams } from './interfaces/interfaces';
import {
AccessLevel,
CreateOrUpdateAccessDialogParams
} from './interfaces/interfaces';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
@ -64,7 +67,6 @@ import { CreateOrUpdateAccessDialogParams } from './interfaces/interfaces';
MatFormFieldModule,
MatInputModule,
MatSelectModule,
MatSlideToggleModule,
ReactiveFormsModule
],
selector: 'gf-create-or-update-access-dialog',
@ -113,17 +115,13 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit {
const isPublic = access?.type === 'PUBLIC';
this.accessForm = this.formBuilder.group({
accessLevel: this.getAccessLevel(access?.scopes),
alias: [access?.alias ?? ''],
filters: [null],
granteeUserId: [
access?.grantee ?? null,
isPublic ? null : Validators.required
],
hasScopeToReadValues: hasScope(
access?.scopes,
scopes.portfolioReadValues
),
hasScopesToWrite: hasScope(access?.scopes, scopes.activityCreate),
type: [
{ disabled: this.mode === 'update', value: access?.type ?? 'PRIVATE' },
Validators.required
@ -149,12 +147,6 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit {
.subscribe((accessType) => {
const granteeUserIdControl = this.accessForm.get('granteeUserId');
const hasScopeToReadValuesControl = this.accessForm.get(
'hasScopeToReadValues'
);
const hasScopesToWriteControl = this.accessForm.get('hasScopesToWrite');
if (accessType === 'PRIVATE') {
granteeUserIdControl?.setValidators(Validators.required);
this.accessForm.get('filters')?.setValue(null);
@ -164,8 +156,7 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit {
// A public access never exposes the monetary values and never
// changes data
hasScopeToReadValuesControl?.setValue(false);
hasScopesToWriteControl?.setValue(false);
this.accessForm.get('accessLevel')?.setValue('RESTRICTED_VIEW');
}
granteeUserIdControl?.updateValueAndValidity();
@ -194,19 +185,15 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit {
);
}
/**
* The write access is granted as one unit, hence the dialog offers a single
* control for all write scopes
*/
private buildScopes() {
return [
...(this.accessForm.get('hasScopeToReadValues')?.value
? SCOPES_OF_READ_ACCESS
: SCOPES_OF_READ_RESTRICTED_ACCESS),
...(this.accessForm.get('hasScopesToWrite')?.value
? SCOPES_OF_WRITE_ACCESS
: [])
];
private buildScopes(): Scope[] {
switch (this.accessForm.get('accessLevel')?.value as AccessLevel) {
case 'CHANGE':
return [...SCOPES_OF_READ_ACCESS, ...SCOPES_OF_WRITE_ACCESS];
case 'VIEW':
return [...SCOPES_OF_READ_ACCESS];
default:
return [...SCOPES_OF_READ_RESTRICTED_ACCESS];
}
}
private async createAccess() {
@ -248,6 +235,20 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit {
}
}
private getAccessLevel(scopesOfAccess: string[] | undefined): AccessLevel {
if (
SCOPES_OF_WRITE_ACCESS.some((scope) => {
return hasScope(scopesOfAccess, scope);
})
) {
return 'CHANGE';
}
return hasScope(scopesOfAccess, scopes.portfolioReadValues)
? 'VIEW'
: 'RESTRICTED_VIEW';
}
private loadHoldings() {
this.dataService
.fetchPortfolioHoldings()

24
apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html

@ -36,31 +36,15 @@
<div>
<mat-form-field appearance="outline" class="w-100">
<mat-label i18n>Permission</mat-label>
<mat-select formControlName="hasScopeToReadValues">
<mat-option i18n [value]="false">Restricted view</mat-option>
<mat-select formControlName="accessLevel">
<mat-option i18n value="RESTRICTED_VIEW">Restricted view</mat-option>
@if (accessForm.get('type')?.value === 'PRIVATE') {
<mat-option i18n [value]="true">View</mat-option>
<mat-option i18n value="VIEW">View</mat-option>
<mat-option i18n value="CHANGE">View and change</mat-option>
}
</mat-select>
</mat-form-field>
</div>
@if (accessForm.get('type')?.value === 'PRIVATE') {
<div class="align-items-center d-flex mb-3">
<div class="w-50">
<div i18n>Changes</div>
<div class="hint-text text-muted" i18n>
Allow to add, to update and to delete data of your portfolio
</div>
</div>
<div class="pl-1 w-50">
<mat-slide-toggle
color="primary"
formControlName="hasScopesToWrite"
hideIcon="true"
/>
</div>
</div>
}
@if (accessForm.get('type')?.value === 'PRIVATE') {
<div>
<mat-form-field appearance="outline" class="w-100">

2
apps/client/src/app/components/user-account-access/create-or-update-access-dialog/interfaces/interfaces.ts

@ -3,3 +3,5 @@ import { Access } from '@ghostfolio/common/interfaces';
export interface CreateOrUpdateAccessDialogParams {
access?: Access;
}
export type AccessLevel = 'CHANGE' | 'RESTRICTED_VIEW' | 'VIEW';

Loading…
Cancel
Save