From 6ca343384c794b4785016eac4973396849e4da15 Mon Sep 17 00:00:00 2001 From: Aram Al-Sabti Date: Fri, 17 Dec 2021 15:37:28 +0100 Subject: [PATCH 1/9] Revised permission system. Admin pages can still be accessed by url if only read --- .../organisation-detail.component.html | 13 +++- .../organisation-detail.component.ts | 12 +++- .../organisation-list.component.html | 4 +- .../organisation-list.component.ts | 22 ++++--- .../permission-detail.component.html | 8 +-- .../permission-detail.component.ts | 11 +++- .../permission-edit.component.ts | 13 ++-- .../permission-list.component.html | 4 +- .../permission-list.component.ts | 7 +- .../permission-tabel.component.ts | 5 +- src/app/admin/permission/permission.model.ts | 6 +- .../user-detail/user-detail.component.html | 4 +- .../user-detail/user-detail.component.ts | 9 ++- .../users/user-edit/user-edit.component.html | 4 +- .../users/user-edit/user-edit.component.ts | 9 ++- .../users/user-list/user-list.component.html | 4 +- .../users/user-list/user-list.component.ts | 12 ++-- .../application-detail.component.html | 5 +- .../application-detail.component.ts | 3 +- .../applications-list.component.html | 6 +- .../applications-list.component.ts | 7 +- .../applications-table.component.spec.ts | 10 +-- .../applications-table.component.ts | 3 +- .../bulk-import/bulk-import.component.html | 4 +- .../bulk-import/bulk-import.component.ts | 9 ++- .../datatarget-detail.component.html | 4 +- .../datatarget-detail.component.ts | 13 ++-- .../datatarget-edit.component.html | 65 ++++++++++--------- .../datatarget-edit.component.ts | 13 ++-- .../datatarget-list.component.html | 5 +- .../datatarget-list.component.ts | 13 ++-- .../datatarget-table.component.ts | 5 +- .../iot-device-detail.component.html | 7 +- .../iot-device-detail.component.ts | 5 +- .../iot-device-edit.component.html | 4 +- .../iot-device-edit.component.ts | 23 ++++--- .../iot-devices-table.component.ts | 5 +- .../device-model-detail.component.html | 5 +- .../device-model-detail.component.ts | 7 +- .../device-model-list.component.html | 5 +- .../device-model-list.component.ts | 7 +- .../device-model-table.component.ts | 3 +- .../gateway-detail.component.html | 4 +- .../gateway-detail.component.ts | 21 +++--- .../gateway-list/gateway-list.component.html | 5 +- .../gateway-list/gateway-list.component.ts | 5 +- .../gateway-table/gateway-table.component.ts | 3 +- .../organisation-dropdown.component.html | 4 +- .../organisation-dropdown.component.ts | 12 ++-- .../payload-decoder-detail.component.html | 5 +- .../payload-decoder-detail.component.ts | 3 +- .../payload-decoder-edit.component.html | 4 +- .../payload-decoder-edit.component.ts | 21 +++--- .../payload-decoder-list.component.html | 5 +- .../payload-decoder-list.component.ts | 11 +++- .../payload-decoder-table.component.html | 2 +- .../payload-decoder-table.component.ts | 3 +- .../device-profiles/device-profile.service.ts | 2 +- .../device-profiles-edit.component.html | 6 +- .../device-profiles-edit.component.ts | 3 +- .../device-profiles-list.component.ts | 6 +- .../profiles-list.component.html | 4 +- .../profiles-list/profiles-list.component.ts | 9 ++- .../service-profiles-edit.component.ts | 11 ++-- .../service-profiles-list.component.ts | 7 +- .../search-table/search-table.component.html | 10 +-- src/app/search/search.component.html | 4 +- src/app/search/search.component.ts | 3 + .../components/top-bar/top-bar.component.ts | 7 +- src/app/shared/enums/access-scopes.ts | 5 ++ src/app/shared/services/me.service.ts | 65 +++++++++++++------ .../shared-variable.service.ts | 21 ------ .../sigfox-device-types-edit.component.ts | 3 +- .../sigfox-groups-detail.component.html | 5 +- .../sigfox-groups-detail.component.ts | 6 +- .../sigfox-groups-edit.component.html | 4 +- .../sigfox-groups-edit.component.ts | 9 ++- .../sigfox-groups-list-item.component.ts | 3 +- .../sigfox-groups-list.component.html | 5 +- .../sigfox-groups-list.component.ts | 8 ++- src/assets/i18n/da.json | 11 ++-- 81 files changed, 432 insertions(+), 276 deletions(-) create mode 100644 src/app/shared/enums/access-scopes.ts diff --git a/src/app/admin/organisation/organisation-detail/organisation-detail.component.html b/src/app/admin/organisation/organisation-detail/organisation-detail.component.html index ced52e8af..0f7fac379 100644 --- a/src/app/admin/organisation/organisation-detail/organisation-detail.component.html +++ b/src/app/admin/organisation/organisation-detail/organisation-detail.component.html @@ -1,6 +1,13 @@
- +
@@ -34,4 +41,4 @@

- \ No newline at end of file + diff --git a/src/app/admin/organisation/organisation-detail/organisation-detail.component.ts b/src/app/admin/organisation/organisation-detail/organisation-detail.component.ts index 38cce3fba..737aa23e1 100644 --- a/src/app/admin/organisation/organisation-detail/organisation-detail.component.ts +++ b/src/app/admin/organisation/organisation-detail/organisation-detail.component.ts @@ -15,6 +15,8 @@ import { DropdownButton } from '@shared/models/dropdown-button.model'; import { ApplicationService } from '@applications/application.service'; import { environment } from '@environments/environment'; import { Title } from '@angular/platform-browser'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-organisation-detail', @@ -41,6 +43,7 @@ export class OrganisationDetailComponent implements OnInit, OnChanges, OnDestroy id: number; subscription: Subscription; permissions: PermissionResponse[]; + canEdit: boolean; constructor( public translate: TranslateService, @@ -49,7 +52,8 @@ export class OrganisationDetailComponent implements OnInit, OnChanges, OnDestroy private permissionsService: PermissionService, private deleteDialogService: DeleteDialogService, private location: Location, - private titleService: Title + private titleService: Title, + private meService: MeService ) { } ngOnChanges(changes: SimpleChanges): void { @@ -71,8 +75,10 @@ export class OrganisationDetailComponent implements OnInit, OnChanges, OnDestroy .subscribe(translations => { this.backButton.label = translations['NAV.ORGANISATIONS']; this.dropdownButton.label = translations['ORGANISATION.DROPDOWN']; - this.titleService.setTitle(translations['TITLE.ORGANIZATION']) + this.titleService.setTitle(translations['TITLE.ORGANIZATION']); }); + + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.UserAdministrationWrite); } ngOnDestroy() { @@ -119,6 +125,6 @@ export class OrganisationDetailComponent implements OnInit, OnChanges, OnDestroy } }); } - }) + }); } } diff --git a/src/app/admin/organisation/organisation-list/organisation-list.component.html b/src/app/admin/organisation/organisation-list/organisation-list.component.html index 9cba6082c..d1b269ec0 100644 --- a/src/app/admin/organisation/organisation-list/organisation-list.component.html +++ b/src/app/admin/organisation/organisation-list/organisation-list.component.html @@ -1,5 +1,5 @@ + [ctaLabel]="'ORGANISATION.FORM.CREATE-NEW-ORGANISATION' | translate" [ctaRouterLink]="'new-organisation'" [canEdit]="canEdit">
@@ -9,4 +9,4 @@
- \ No newline at end of file + diff --git a/src/app/admin/organisation/organisation-list/organisation-list.component.ts b/src/app/admin/organisation/organisation-list/organisation-list.component.ts index 3ce2a103b..0fe174476 100644 --- a/src/app/admin/organisation/organisation-list/organisation-list.component.ts +++ b/src/app/admin/organisation/organisation-list/organisation-list.component.ts @@ -1,7 +1,8 @@ import { Component, OnInit } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { TranslateService } from '@ngx-translate/core'; -import { Sort } from '@shared/models/sort.model'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-organisation-list', @@ -9,15 +10,20 @@ import { Sort } from '@shared/models/sort.model'; styleUrls: ['./organisation-list.component.scss'], }) export class OrganisationListComponent implements OnInit { - - constructor(public translate: TranslateService, private titleService: Title) { + canEdit: boolean; + + constructor( + public translate: TranslateService, + private titleService: Title, + private meService: MeService + ) { translate.use('da'); } ngOnInit(): void { - this.translate.get(['TITLE.ORGANIZATION']) - .subscribe(translations => { - this.titleService.setTitle(translations['TITLE.ORGANIZATION']); - }); - } + this.translate.get(['TITLE.ORGANIZATION']).subscribe((translations) => { + this.titleService.setTitle(translations['TITLE.ORGANIZATION']); + }); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.UserAdministrationWrite); + } } diff --git a/src/app/admin/permission/permission-detail/permission-detail.component.html b/src/app/admin/permission/permission-detail/permission-detail.component.html index c7ae3ae5e..95b261592 100644 --- a/src/app/admin/permission/permission-detail/permission-detail.component.html +++ b/src/app/admin/permission/permission-detail/permission-detail.component.html @@ -1,6 +1,6 @@
+ [dropDownButton]="dropdownButton" (deleteSelectedInDropdown)="onDeletePermission()" [canEdit]="canEdit">
@@ -33,13 +33,13 @@

{{ 'PERMISSION.DETAIL.APPLICATIONS' | translate }}

- + - +
- \ No newline at end of file + diff --git a/src/app/admin/permission/permission-detail/permission-detail.component.ts b/src/app/admin/permission/permission-detail/permission-detail.component.ts index 28a0ab3eb..072668ce8 100644 --- a/src/app/admin/permission/permission-detail/permission-detail.component.ts +++ b/src/app/admin/permission/permission-detail/permission-detail.component.ts @@ -11,6 +11,8 @@ import { DropdownButton } from '@shared/models/dropdown-button.model'; import { DeleteDialogService } from '@shared/components/delete-dialog/delete-dialog.service'; import { environment } from '@environments/environment'; import { Title } from '@angular/platform-browser'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ @@ -43,6 +45,7 @@ export class PermissionDetailComponent implements OnInit, OnChanges { subscription: Subscription; users: UserResponse[]; dropdownButton: DropdownButton; + canEdit: boolean; constructor( public translate: TranslateService, @@ -50,7 +53,8 @@ export class PermissionDetailComponent implements OnInit, OnChanges { private permissionService: PermissionService, private router: Router, private titleService: Title, - private deleteDialogService: DeleteDialogService + private deleteDialogService: DeleteDialogService, + private meService: MeService ) { } ngOnInit(): void { @@ -62,7 +66,7 @@ export class PermissionDetailComponent implements OnInit, OnChanges { label: '', editRouterLink: 'edit-permission', isErasable: true, - } + }; } this.translate.get(['NAV.PERMISSIONS', 'PERMISSION.DETAIL.DROPDOWN', 'TITLE.PERMISSION']) .subscribe(translations => { @@ -70,6 +74,7 @@ export class PermissionDetailComponent implements OnInit, OnChanges { this.dropdownButton.label = translations['PERMISSION.DETAIL.DROPDOWN']; this.titleService.setTitle(translations['TITLE.PERMISSION']); }); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.UserAdministrationWrite); } ngOnChanges(changes: SimpleChanges): void { @@ -95,7 +100,7 @@ export class PermissionDetailComponent implements OnInit, OnChanges { } }); } - }) + }); } onEditPermission() { diff --git a/src/app/admin/permission/permission-edit/permission-edit.component.ts b/src/app/admin/permission/permission-edit/permission-edit.component.ts index 327d85724..766c04856 100644 --- a/src/app/admin/permission/permission-edit/permission-edit.component.ts +++ b/src/app/admin/permission/permission-edit/permission-edit.component.ts @@ -213,7 +213,7 @@ export class PermissionEditComponent implements OnInit, OnDestroy { if ( response.type === PermissionType.Read || - response.type === PermissionType.Write + response.type === PermissionType.OrganizationApplicationAdmin ) { this.getApplications(this.permission.organizationId); this.permission.applicationIds = response.applications.map( @@ -252,12 +252,13 @@ export class PermissionEditComponent implements OnInit, OnDestroy { } allowedLevels() { - if (this.permission.level == PermissionType.GlobalAdmin) { + if (this.permission.level === PermissionType.GlobalAdmin) { return [PermissionType.GlobalAdmin]; } return [ - PermissionType.OrganizationAdmin, - PermissionType.Write, + PermissionType.OrganizationUserAdmin, + PermissionType.OrganizationApplicationAdmin, + PermissionType.OrganizationGatewayAdmin, PermissionType.Read, ]; } @@ -280,7 +281,7 @@ export class PermissionEditComponent implements OnInit, OnDestroy { isOrganizationApplicationPermission() { return ( - this.permission.level == + this.permission.level === PermissionType.OrganizationApplicationPermissions || this.isReadOrWrite() ); @@ -289,7 +290,7 @@ export class PermissionEditComponent implements OnInit, OnDestroy { isReadOrWrite(): boolean { return ( this.permission.level === PermissionType.Read || - this.permission.level === PermissionType.Write + this.permission.level === PermissionType.OrganizationApplicationAdmin ); } diff --git a/src/app/admin/permission/permission-list/permission-list.component.html b/src/app/admin/permission/permission-list/permission-list.component.html index e41723ac3..684ba789d 100644 --- a/src/app/admin/permission/permission-list/permission-list.component.html +++ b/src/app/admin/permission/permission-list/permission-list.component.html @@ -1,5 +1,5 @@ + [ctaLabel]="'FORM.CREATE-NEW-PERMISSION' | translate" [ctaRouterLink]="'new-permission'" [canEdit]="canEdit">
@@ -9,4 +9,4 @@
- \ No newline at end of file + diff --git a/src/app/admin/permission/permission-list/permission-list.component.ts b/src/app/admin/permission/permission-list/permission-list.component.ts index cec1432d5..4812055c0 100644 --- a/src/app/admin/permission/permission-list/permission-list.component.ts +++ b/src/app/admin/permission/permission-list/permission-list.component.ts @@ -6,6 +6,8 @@ import { PermissionService } from '../permission.service'; import { Sort } from '@shared/models/sort.model'; import { environment } from '@environments/environment'; import { Title } from '@angular/platform-browser'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-permission-list', @@ -19,11 +21,13 @@ export class PermissionListComponent implements OnInit, OnChanges { public permissions: PermissionResponse[]; permissionSubscription: Subscription; + canEdit: boolean; constructor( public translate: TranslateService, private titleService: Title, - private permissionService: PermissionService + private permissionService: PermissionService, + private meService: MeService ) { translate.use('da'); } @@ -37,6 +41,7 @@ export class PermissionListComponent implements OnInit, OnChanges { .subscribe(translations => { this.titleService.setTitle(translations['TITLE.PERMISSION']); }); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.UserAdministrationWrite); } getPermissions() { diff --git a/src/app/admin/permission/permission-list/permission-tabel/permission-tabel.component.ts b/src/app/admin/permission/permission-list/permission-tabel/permission-tabel.component.ts index 0b93c8e21..79ff57d30 100644 --- a/src/app/admin/permission/permission-list/permission-tabel/permission-tabel.component.ts +++ b/src/app/admin/permission/permission-list/permission-tabel/permission-tabel.component.ts @@ -14,6 +14,7 @@ import { PermissionType, } from '../../permission.model'; import { PermissionService } from '../../permission.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-permission-tabel', @@ -110,10 +111,10 @@ export class PermissionTabelComponent implements AfterViewInit { } canAccess(element: PermissionResponse) { - if (element.type == PermissionType.GlobalAdmin) { + if (element.type === PermissionType.GlobalAdmin) { return this.meService.hasGlobalAdmin(); } - return this.meService.hasAdminAccessInTargetOrganization(element.organization.id); + return this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.UserAdministrationWrite, element.organization.id); } private refresh() { diff --git a/src/app/admin/permission/permission.model.ts b/src/app/admin/permission/permission.model.ts index 00ca3c2d2..b80ef7fd0 100644 --- a/src/app/admin/permission/permission.model.ts +++ b/src/app/admin/permission/permission.model.ts @@ -34,9 +34,11 @@ export interface PermissionGetManyResponse { export enum PermissionType { GlobalAdmin = 'GlobalAdmin', - OrganizationAdmin = 'OrganizationAdmin', - Write = 'Write', + OrganizationUserAdmin = 'OrganizationUserAdmin', + OrganizationGatewayAdmin = 'OrganizationGatewayAdmin', + OrganizationApplicationAdmin = 'OrganizationApplicationAdmin', Read = 'Read', + OrganizationPermission = 'OrganizationPermission', OrganizationApplicationPermissions = 'OrganizationApplicationPermissions', } diff --git a/src/app/admin/users/user-detail/user-detail.component.html b/src/app/admin/users/user-detail/user-detail.component.html index 57974557e..89edbc39e 100644 --- a/src/app/admin/users/user-detail/user-detail.component.html +++ b/src/app/admin/users/user-detail/user-detail.component.html @@ -1,6 +1,6 @@
+ [dropDownButton]="dropdownButton" [canEdit]="canEdit">
@@ -34,4 +34,4 @@

-
\ No newline at end of file + diff --git a/src/app/admin/users/user-detail/user-detail.component.ts b/src/app/admin/users/user-detail/user-detail.component.ts index a902b4767..a509f1082 100644 --- a/src/app/admin/users/user-detail/user-detail.component.ts +++ b/src/app/admin/users/user-detail/user-detail.component.ts @@ -10,6 +10,8 @@ import { Application } from '@applications/application.model'; import { OrganisationResponse } from '@app/admin/organisation/organisation.model'; import { DropdownButton } from '@shared/models/dropdown-button.model'; import { environment } from '@environments/environment'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-user-detail', @@ -43,12 +45,14 @@ export class UserDetailComponent implements OnInit, OnDestroy { dropdownButton: DropdownButton; id: number; subscription: Subscription; + canEdit: boolean; constructor( public translate: TranslateService, private route: ActivatedRoute, private userService: UserService, private router: Router, + private meService: MeService ) { } ngOnInit(): void { @@ -60,13 +64,14 @@ export class UserDetailComponent implements OnInit, OnDestroy { label: '', editRouterLink: 'edit-user', isErasable: false, - } + }; } this.translate.get(['NAV.USERS', 'USERS.DETAIL.DROPDOWN']) .subscribe(translations => { this.backButton.label = translations['NAV.USERS']; - this.dropdownButton.label = translations['USERS.DETAIL.DROPDOWN'] + this.dropdownButton.label = translations['USERS.DETAIL.DROPDOWN']; }); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.UserAdministrationWrite); } private getUser(id: number) { diff --git a/src/app/admin/users/user-edit/user-edit.component.html b/src/app/admin/users/user-edit/user-edit.component.html index 0d1b2e5dd..eed313831 100644 --- a/src/app/admin/users/user-edit/user-edit.component.html +++ b/src/app/admin/users/user-edit/user-edit.component.html @@ -1,4 +1,4 @@ - +
    @@ -53,4 +53,4 @@
-
\ No newline at end of file + diff --git a/src/app/admin/users/user-edit/user-edit.component.ts b/src/app/admin/users/user-edit/user-edit.component.ts index 5ac145bea..4f89b8739 100644 --- a/src/app/admin/users/user-edit/user-edit.component.ts +++ b/src/app/admin/users/user-edit/user-edit.component.ts @@ -10,6 +10,8 @@ import { Location } from '@angular/common'; import { PermissionType } from '@app/admin/permission/permission.model'; import { AuthService, CurrentUserInfoResponse } from '@auth/auth.service'; import { SharedVariableService } from '@shared/shared-variable/shared-variable.service'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-user-edit', @@ -30,6 +32,7 @@ export class UserEditComponent implements OnInit { subscription: Subscription; isGlobalAdmin = false; isKombit: boolean; + canEdit: boolean; constructor( private translate: TranslateService, @@ -37,7 +40,8 @@ export class UserEditComponent implements OnInit { private userService: UserService, private location: Location, private authService: AuthService, - private sharedVariableService: SharedVariableService + private sharedVariableService: SharedVariableService, + private meService: MeService ) {} ngOnInit(): void { @@ -57,6 +61,7 @@ export class UserEditComponent implements OnInit { this.user.active = true; } this.amIGlobalAdmin(); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.UserAdministrationWrite); } private getUser(id: number) { @@ -66,7 +71,7 @@ export class UserEditComponent implements OnInit { this.user.id = response.id; this.user.active = response.active; this.user.globalAdmin = response.permissions.some( - (x) => x.type == PermissionType.GlobalAdmin + (x) => x.type === PermissionType.GlobalAdmin ); this.isKombit = response.nameId != null; // We cannot set the password. diff --git a/src/app/admin/users/user-list/user-list.component.html b/src/app/admin/users/user-list/user-list.component.html index 33c5d7767..eb93c46a4 100644 --- a/src/app/admin/users/user-list/user-list.component.html +++ b/src/app/admin/users/user-list/user-list.component.html @@ -1,5 +1,5 @@ + [ctaLabel]="'USERS.CREATE' | translate" [ctaRouterLink]="'new-user'" [canEdit]="canEdit">
@@ -8,4 +8,4 @@
- \ No newline at end of file + diff --git a/src/app/admin/users/user-list/user-list.component.ts b/src/app/admin/users/user-list/user-list.component.ts index 9563dffc7..17fc8848a 100644 --- a/src/app/admin/users/user-list/user-list.component.ts +++ b/src/app/admin/users/user-list/user-list.component.ts @@ -1,21 +1,23 @@ -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { TranslateService } from '@ngx-translate/core'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; +import { MeService } from '@shared/services/me.service'; @Component({ selector: 'app-user-list', templateUrl: './user-list.component.html', styleUrls: ['./user-list.component.scss'], }) -export class UserListComponent { - constructor(private titleService: Title, private translate: TranslateService) {} +export class UserListComponent implements OnInit { + canEdit: boolean; + constructor(private titleService: Title, private translate: TranslateService, private meService: MeService) {} ngOnInit(): void { this.translate.get(['TITLE.USER']) .subscribe(translations => { this.titleService.setTitle(translations['TITLE.USER']); }); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.UserAdministrationWrite); } - - ngOnChanges(): void {} } diff --git a/src/app/applications/application-detail/application-detail.component.html b/src/app/applications/application-detail/application-detail.component.html index 1eac588db..cfadc3a29 100644 --- a/src/app/applications/application-detail/application-detail.component.html +++ b/src/app/applications/application-detail/application-detail.component.html @@ -1,7 +1,8 @@
+ [addDetailDowndown]="true" [dropDownButton]="dropdownButton" (deleteSelectedInDropdown)="onDeleteApplication()" + [canEdit]="canEdit">
@@ -36,4 +37,4 @@

Detaljer

- \ No newline at end of file + diff --git a/src/app/applications/application-detail/application-detail.component.ts b/src/app/applications/application-detail/application-detail.component.ts index 009f3a63b..1c894f1ef 100644 --- a/src/app/applications/application-detail/application-detail.component.ts +++ b/src/app/applications/application-detail/application-detail.component.ts @@ -9,6 +9,7 @@ import { BackButton } from '@shared/models/back-button.model'; import { DropdownButton } from '@shared/models/dropdown-button.model'; import { MeService } from '@shared/services/me.service'; import { Subscription } from 'rxjs'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-application', @@ -55,7 +56,7 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy { this.dropdownButton.label = translations['APPLICATION-TABLE-ROW.SHOW-OPTIONS']; this.titleService.setTitle(translations['TITLE.APPLICATION']); }); - this.canEdit = this.meService.canWriteInTargetOrganization(); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } onDeleteApplication() { diff --git a/src/app/applications/applications-list/applications-list.component.html b/src/app/applications/applications-list/applications-list.component.html index 8e1ca4949..04da671d6 100644 --- a/src/app/applications/applications-list/applications-list.component.html +++ b/src/app/applications/applications-list/applications-list.component.html @@ -1,14 +1,12 @@ + [ctaRouterLink]="'new-application'" (updatePageLimit)="updatePageLimit($event)" [canEdit]="canEdit">
-
-
\ No newline at end of file + diff --git a/src/app/applications/applications-list/applications-list.component.ts b/src/app/applications/applications-list/applications-list.component.ts index 1e9bab84c..00b34de94 100644 --- a/src/app/applications/applications-list/applications-list.component.ts +++ b/src/app/applications/applications-list/applications-list.component.ts @@ -9,6 +9,8 @@ import { Application } from '@applications/application.model'; import { environment } from '@environments/environment'; import { TranslateService } from '@ngx-translate/core'; import { SharedVariableService } from '@shared/shared-variable/shared-variable.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; +import { MeService } from '@shared/services/me.service'; @Component({ providers: [NavbarComponent], @@ -24,11 +26,13 @@ export class ApplicationsListComponent implements OnInit { public pageOffset = 0; public applications: Application[]; @Input() organizationId: number; + canEdit: boolean; constructor( public translate: TranslateService, private titleService: Title, - private globalService: SharedVariableService + private globalService: SharedVariableService, + private meService: MeService ) { translate.use('da'); } @@ -39,6 +43,7 @@ export class ApplicationsListComponent implements OnInit { this.titleService.setTitle(translations['TITLE.APPLICATION']); }); this.organizationId = this.globalService.getSelectedOrganisationId(); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } updatePageLimit(limit: any) { diff --git a/src/app/applications/applications-list/applications-table/applications-table.component.spec.ts b/src/app/applications/applications-list/applications-table/applications-table.component.spec.ts index 60135d748..8406c40a4 100644 --- a/src/app/applications/applications-list/applications-table/applications-table.component.spec.ts +++ b/src/app/applications/applications-list/applications-table/applications-table.component.spec.ts @@ -1,20 +1,20 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { ApplicationTableOtherComponent } from './applications-table.component +import { ApplicationsTableComponent } from './applications-table.component'; describe('ApplicationTableOtherComponent', () => { - let component: ApplicationTableOtherComponent; - let fixture: ComponentFixture; + let component: ApplicationsTableComponent; + let fixture: ComponentFixture; beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ ApplicationTableOtherComponent ] + declarations: [ ApplicationsTableComponent ] }) .compileComponents(); })); beforeEach(() => { - fixture = TestBed.createComponent(ApplicationTableOtherComponent); + fixture = TestBed.createComponent(ApplicationsTableComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/src/app/applications/applications-list/applications-table/applications-table.component.ts b/src/app/applications/applications-list/applications-table/applications-table.component.ts index 4da383044..1e132956b 100644 --- a/src/app/applications/applications-list/applications-table/applications-table.component.ts +++ b/src/app/applications/applications-list/applications-table/applications-table.component.ts @@ -10,6 +10,7 @@ import { DeleteDialogService } from '@shared/components/delete-dialog/delete-dia import { MeService } from '@shared/services/me.service'; import { merge, Observable, of as observableOf } from 'rxjs'; import { catchError, map, startWith, switchMap } from 'rxjs/operators'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; /** * @title Table retrieving data through HTTP @@ -43,7 +44,7 @@ export class ApplicationsTableComponent implements AfterViewInit, OnInit { ) { } ngOnInit() { - this.canEdit = this.meService.canWriteInTargetOrganization(); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } ngAfterViewInit() { diff --git a/src/app/applications/bulk-import/bulk-import.component.html b/src/app/applications/bulk-import/bulk-import.component.html index 447b772e0..466dcaf36 100644 --- a/src/app/applications/bulk-import/bulk-import.component.html +++ b/src/app/applications/bulk-import/bulk-import.component.html @@ -1,4 +1,4 @@ - +
@@ -89,4 +89,4 @@
\ No newline at end of file +
--> diff --git a/src/app/applications/bulk-import/bulk-import.component.ts b/src/app/applications/bulk-import/bulk-import.component.ts index e28d2506f..e91e91e26 100644 --- a/src/app/applications/bulk-import/bulk-import.component.ts +++ b/src/app/applications/bulk-import/bulk-import.component.ts @@ -12,6 +12,8 @@ import { Papa } from 'ngx-papaparse'; import { Observable } from 'rxjs'; import { BulkImport } from './bulk-import.model'; import { BulkMapping } from './bulkMapping'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-bulk-import', @@ -31,11 +33,12 @@ export class BulkImportComponent implements OnInit { { name: 'generic-http-sample.csv', url: '../../../assets/docs/iotdevice_generichttp.csv' }, { name: 'lorawan-otaa-sample.csv', url: '../../../assets/docs/iotdevice_lorawan_otaa.csv' }, { name: 'lorawan-abp-sample.csv', url: '../../../assets/docs/iotdevice_lorawan_abp.csv' }, - ] + ]; download$: Observable; private bulkMapper = new BulkMapping(); public backButtonTitle: string; private applicationId; + canEdit: boolean; constructor( private papa: Papa, @@ -44,7 +47,8 @@ export class BulkImportComponent implements OnInit { private titleService: Title, private translate: TranslateService, private downloads: DownloadService, - private errorMessageService: ErrorMessageService + private errorMessageService: ErrorMessageService, + private meService: MeService ) { this.translate.use('da'); } @@ -55,6 +59,7 @@ export class BulkImportComponent implements OnInit { this.titleService.setTitle(translations['TITLE.BULKIMPORT']); }); this.applicationId = +this.route.snapshot.paramMap.get('id'); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } diff --git a/src/app/applications/datatarget/datatarget-detail/datatarget-detail.component.html b/src/app/applications/datatarget/datatarget-detail/datatarget-detail.component.html index cc9829db2..2ac565937 100644 --- a/src/app/applications/datatarget/datatarget-detail/datatarget-detail.component.html +++ b/src/app/applications/datatarget/datatarget-detail/datatarget-detail.component.html @@ -1,6 +1,6 @@
+ [dropDownButton]="dropdownButton" (deleteSelectedInDropdown)="onDeleteDatatarget()" [canEdit]="canEdit">
@@ -71,4 +71,4 @@

{{ 'DATATARGET.RELATIONS' | translate }}

-
\ No newline at end of file + diff --git a/src/app/applications/datatarget/datatarget-detail/datatarget-detail.component.ts b/src/app/applications/datatarget/datatarget-detail/datatarget-detail.component.ts index 7af258890..adcb4d5f3 100644 --- a/src/app/applications/datatarget/datatarget-detail/datatarget-detail.component.ts +++ b/src/app/applications/datatarget/datatarget-detail/datatarget-detail.component.ts @@ -12,6 +12,8 @@ import { Datatarget } from '../datatarget.model'; import { DropdownButton } from '@shared/models/dropdown-button.model'; import { faArrowsAltH } from '@fortawesome/free-solid-svg-icons'; import { IotDevice } from '@applications/iot-devices/iot-device.model'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-datatarget-detail', @@ -28,6 +30,7 @@ export class DatatargetDetailComponent implements OnInit, OnDestroy { public dropdownButton: DropdownButton; arrowsAltH = faArrowsAltH; private applicationName: string; + canEdit: boolean; constructor( private route: ActivatedRoute, @@ -35,7 +38,8 @@ export class DatatargetDetailComponent implements OnInit, OnDestroy { private location: Location, private datatargetRelationServicer: PayloadDeviceDatatargetService, private datatargetService: DatatargetService, - public translate: TranslateService) { } + public translate: TranslateService, + private meService: MeService) { } ngOnInit(): void { const id: number = +this.route.snapshot.paramMap.get('datatargetId'); @@ -47,13 +51,14 @@ export class DatatargetDetailComponent implements OnInit, OnDestroy { label: '', editRouterLink: '../../datatarget-edit/' + id, isErasable: true, - } + }; } this.translate.get(['NAV.MY-DATATARGET', 'DATATARGET.SHOW-OPTIONS']) .subscribe(translations => { this.backButton.label = translations['NAV.MY-DATATARGET']; - this.dropdownButton.label = translations['DATATARGET.SHOW-OPTIONS'] + this.dropdownButton.label = translations['DATATARGET.SHOW-OPTIONS']; }); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } getDatatarget(id: number) { @@ -65,7 +70,7 @@ export class DatatargetDetailComponent implements OnInit, OnDestroy { } private setBackButton(applicationId: number) { - this.backButton.routerLink = ['applications', applicationId.toString(), 'datatarget-list', this.applicationName ] + this.backButton.routerLink = ['applications', applicationId.toString(), 'datatarget-list', this.applicationName ]; } onDeleteDatatarget() { diff --git a/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.html b/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.html index 4d4df069e..73725f599 100644 --- a/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.html +++ b/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.html @@ -1,6 +1,7 @@ + backButtonTitle="{{backButtonTitle}}" + title="{{title}}" + [canEdit]="canEdit">
@@ -11,9 +12,9 @@ - {{'DATATARGET.ADD-TO-OPENDATADK' | translate}} @@ -26,7 +27,7 @@ [ngClass]="{'is-invalid' : formFailedSubmit && errorFields.includes('name'), 'is-valid' : formFailedSubmit && !errorFields.includes('name')}"> - +
* @@ -38,17 +39,17 @@
* -
@@ -70,19 +71,19 @@
{{'QUESTION.DATATARGET.RELATIONS' | translate}}
{{'QUESTION.ADD-RELATIONS' | translate}} - - - - + + +
+ + + + - + @@ -125,15 +126,15 @@
{{'QUESTION.DATATARGET.RELATIONS' | translate}}

{{'DATATARGET.DELETE' | translate}}

- - - - -
{{'QUESTION.DATATARGET.SELECT-DEVICES' | translate}} - -
-
+
{{'QUESTION.DATATARGET.SELECT-PAYLOADDECODER' | translate}} @@ -115,7 +116,7 @@
{{'QUESTION.DATATARGET.RELATIONS' | translate}}
{{payloadDecoder.name}} - +
- + +
+
- \ No newline at end of file + diff --git a/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.ts b/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.ts index 968df9e23..fd669e739 100644 --- a/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.ts +++ b/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.ts @@ -21,6 +21,8 @@ import { OpendatadkDialogService } from '@shared/components/opendatadk-dialog/op import { OpendatadkService } from '@shared/services/opendatadk.service'; import { ScrollToTopService } from '@shared/services/scroll-to-top.service'; import { OpenDataDkDataset } from '../opendatadk/opendatadk-dataset.model'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-datatarget-edit', @@ -54,6 +56,7 @@ export class DatatargetEditComponent implements OnInit, OnDestroy { payloadDeviceDatatarget: PayloadDeviceDatatarget[]; newDynamic: any = {}; + canEdit: boolean; constructor( public translate: TranslateService, @@ -69,6 +72,7 @@ export class DatatargetEditComponent implements OnInit, OnDestroy { private opendatadkService: OpendatadkService, private opendatadkDialogService: OpendatadkDialogService, private scrollToTopService: ScrollToTopService, + private meService: MeService ) { translate.use('da'); } @@ -104,6 +108,7 @@ export class DatatargetEditComponent implements OnInit, OnDestroy { } this.getPayloadDecoders(); this.setDataSetExcists(); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } addRow() { @@ -161,7 +166,7 @@ export class DatatargetEditComponent implements OnInit, OnDestroy { this.datatargetService.update(this.datatarget) .subscribe( (response: Datatarget) => { - this.datatarget = response; + this.datatarget = response; if (this.datatarget.openDataDkDataset != null) { this.datatarget.openDataDkDataset.acceptTerms = true; } @@ -288,7 +293,7 @@ export class DatatargetEditComponent implements OnInit, OnDestroy { } routeToDatatargets(): void { - this.router.navigate(['applications',this.applicationId.toString(),'datatarget-list', this.applicationNane]) + this.router.navigate(['applications', this.applicationId.toString(), 'datatarget-list', this.applicationNane]); } onCoordinateKey(event: any) { @@ -337,12 +342,12 @@ export class DatatargetEditComponent implements OnInit, OnDestroy { observer.next(true); } } - ) + ); } private showMailClient() { if (!this.datatarget.openDataDkDataset.url) { - this.datatarget.openDataDkDataset.url = this.datatargetService.getOpendataSharingApiUrl() + this.datatarget.openDataDkDataset.url = this.datatargetService.getOpendataSharingApiUrl(); } window.location.href = 'mailto:FG2V@kk.dk?subject=Oprettelse%20af%20datas%C3%A6t%20i%20OpenDataDK&body=K%C3%A6re%20Frans%0D%0A%0D%0AHermed%20fremsendes%20linket%20til%20DCAT%20kataloget%20%2C%20du%20bedes%20registrere%20p%C3%A5%20Open%20Data%20DK%20platformen.%0D%0A%0D%0ALink%3A ' + this.datatarget.openDataDkDataset.url; } diff --git a/src/app/applications/datatarget/datatarget-list/datatarget-list.component.html b/src/app/applications/datatarget/datatarget-list/datatarget-list.component.html index bad1cea61..6675c9a6b 100644 --- a/src/app/applications/datatarget/datatarget-list/datatarget-list.component.html +++ b/src/app/applications/datatarget/datatarget-list/datatarget-list.component.html @@ -1,6 +1,7 @@ + [backButton]="backButton" + [canEdit]="canEdit">
@@ -10,4 +11,4 @@
-
\ No newline at end of file + diff --git a/src/app/applications/datatarget/datatarget-list/datatarget-list.component.ts b/src/app/applications/datatarget/datatarget-list/datatarget-list.component.ts index 2f5236cd9..4d5c33f3e 100644 --- a/src/app/applications/datatarget/datatarget-list/datatarget-list.component.ts +++ b/src/app/applications/datatarget/datatarget-list/datatarget-list.component.ts @@ -5,10 +5,12 @@ import { Datatarget } from '../datatarget.model'; import { BackButton } from '@shared/models/back-button.model'; import { environment } from '@environments/environment'; import { Title } from '@angular/platform-browser'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ - selector: 'a[app-datatarget-list]', + selector: 'app-datatarget-list', templateUrl: './datatarget-list.component.html', styleUrls: ['./datatarget-list.component.scss'] }) @@ -19,24 +21,27 @@ export class DatatargetListComponent implements OnInit { public backButton: BackButton = { label: '', routerLink: ''}; public datatarget: Datatarget; private applikationId: string; + canEdit: boolean; constructor( public translate: TranslateService, private titleService: Title, - private route: ActivatedRoute) { + private route: ActivatedRoute, + private meService: MeService) { translate.use('da'); } ngOnInit(): void { const applikationName: string = this.route.snapshot.paramMap.get('name'); this.applikationId = this.route.snapshot.paramMap.get('id'); - this.translate.get(["NAV.DATATARGET", "NAV.APPLICATIONS", "TITLE.DATATARGET"]) + this.translate.get(['NAV.DATATARGET', 'NAV.APPLICATIONS', 'TITLE.DATATARGET']) .subscribe((translate) => { this.title = translate['NAV.DATATARGET'] + ' - ' + applikationName; this.backButton.label = translate['NAV.APPLICATIONS']; this.titleService.setTitle(translate['TITLE.DATATARGET']); }); - this.setBackButton() + this.setBackButton(); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } setBackButton() { diff --git a/src/app/applications/datatarget/datatarget-table/datatarget-table.component.ts b/src/app/applications/datatarget/datatarget-table/datatarget-table.component.ts index c3bbc0df6..0421e9334 100644 --- a/src/app/applications/datatarget/datatarget-table/datatarget-table.component.ts +++ b/src/app/applications/datatarget/datatarget-table/datatarget-table.component.ts @@ -11,6 +11,7 @@ import { MatTableDataSource } from '@angular/material/table'; import { environment } from '@environments/environment'; import { tableSorter } from '@shared/helpers/table-sorting.helper'; import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-datatarget-table', @@ -25,7 +26,7 @@ export class DatatargetTableComponent implements OnInit, AfterViewInit, OnDestro datatargets: Datatarget[]; resultsLength = 0; public canEdit = false; - @Input() isLoadingResults: boolean = true; + @Input() isLoadingResults = true; public pageSize = environment.tablePageSize; @Input() pageLimit: number; @@ -49,7 +50,7 @@ export class DatatargetTableComponent implements OnInit, AfterViewInit, OnDestro this.applicationId = +Number(this.route.parent.parent.snapshot.paramMap.get('id')); console.log(this.applicationId); this.getDatatarget(); - this.canEdit = this.meService.canWriteInTargetOrganization() + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } ngAfterViewInit() { diff --git a/src/app/applications/iot-devices/iot-device-detail/iot-device-detail.component.html b/src/app/applications/iot-devices/iot-device-detail/iot-device-detail.component.html index 6e5b25b24..3ad5ef645 100644 --- a/src/app/applications/iot-devices/iot-device-detail/iot-device-detail.component.html +++ b/src/app/applications/iot-devices/iot-device-detail/iot-device-detail.component.html @@ -1,6 +1,7 @@
+ [dropDownButton]="dropdownButton" (deleteSelectedInDropdown)="clickDelete()" + [canEdit]="canEdit">
@@ -15,7 +16,7 @@ - +
- \ No newline at end of file + diff --git a/src/app/applications/iot-devices/iot-device-detail/iot-device-detail.component.ts b/src/app/applications/iot-devices/iot-device-detail/iot-device-detail.component.ts index 0ce2b4763..e4e4cdb3b 100644 --- a/src/app/applications/iot-devices/iot-device-detail/iot-device-detail.component.ts +++ b/src/app/applications/iot-devices/iot-device-detail/iot-device-detail.component.ts @@ -15,6 +15,7 @@ import { IoTDeviceService } from '../iot-device.service'; import { DropdownButton } from '@shared/models/dropdown-button.model'; import { Title } from '@angular/platform-browser'; import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-iot-device', @@ -39,7 +40,7 @@ export class IoTDeviceDetailComponent implements OnInit, OnDestroy { public errorMessages: string[]; private deleteDialogSubscription: Subscription; public dropdownButton: DropdownButton; - public canStartDownlink = false; + public canEdit = false; // TODO: Få aktivt miljø? public baseUrl = environment.baseUrl; @@ -58,7 +59,7 @@ export class IoTDeviceDetailComponent implements OnInit, OnDestroy { ) { } ngOnInit(): void { - this.canStartDownlink = this.meService.canWriteInTargetOrganization(); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); this.deviceId = +this.route.snapshot.paramMap.get('deviceId'); if (this.deviceId) { diff --git a/src/app/applications/iot-devices/iot-device-edit/iot-device-edit.component.html b/src/app/applications/iot-devices/iot-device-edit/iot-device-edit.component.html index 46b96a94e..28008c978 100644 --- a/src/app/applications/iot-devices/iot-device-edit/iot-device-edit.component.html +++ b/src/app/applications/iot-devices/iot-device-edit/iot-device-edit.component.html @@ -1,4 +1,4 @@ - +
@@ -226,4 +226,4 @@

{{'QUESTION.ABP' | translate}}

-
\ No newline at end of file + diff --git a/src/app/applications/iot-devices/iot-device-edit/iot-device-edit.component.ts b/src/app/applications/iot-devices/iot-device-edit/iot-device-edit.component.ts index 831d3c6a6..d243b7455 100644 --- a/src/app/applications/iot-devices/iot-device-edit/iot-device-edit.component.ts +++ b/src/app/applications/iot-devices/iot-device-edit/iot-device-edit.component.ts @@ -21,6 +21,8 @@ import { SharedVariableService } from '@shared/shared-variable/shared-variable.s import { Subscription } from 'rxjs'; import { IotDevice } from '../iot-device.model'; import { IoTDeviceService } from '../iot-device.service'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ @@ -49,6 +51,7 @@ export class IotDeviceEditComponent implements OnInit, OnDestroy { private serviceProfilesSubscription: Subscription; private deviceProfileSubscription: Subscription; private devicesProfileSubscription: Subscription; + canEdit: boolean; constructor( private route: ActivatedRoute, @@ -63,7 +66,8 @@ export class IotDeviceEditComponent implements OnInit, OnDestroy { private deviceModelService: DeviceModelService, private errorMessageService: ErrorMessageService, private scrollToTopService: ScrollToTopService, - private titleService: Title + private titleService: Title, + private meService: MeService ) { } ngOnInit(): void { @@ -86,6 +90,7 @@ export class IotDeviceEditComponent implements OnInit, OnDestroy { this.getServiceProfiles(); this.getDeviceProfiles(); this.getDeviceModels(); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } public compare(o1: any, o2: any): boolean { @@ -95,9 +100,9 @@ export class IotDeviceEditComponent implements OnInit, OnDestroy { getDeviceModels() { this.deviceModelService.getMultiple( 1000, - 0, - "id", - "ASC", + 0, + 'id', + 'ASC', this.shareVariable.getSelectedOrganisationId() ).subscribe( (response) => { @@ -194,7 +199,7 @@ export class IotDeviceEditComponent implements OnInit, OnDestroy { private adjustModelBasedOnType() { if (this.iotDevice.deviceModelId === 0) { - this.iotDevice.deviceModelId = null + this.iotDevice.deviceModelId = null; } switch (this.iotDevice.type) { case DeviceType.GENERICHTTP: { @@ -253,11 +258,11 @@ export class IotDeviceEditComponent implements OnInit, OnDestroy { } handleError(error: HttpErrorResponse) { - if (error?.error?.message == "MESSAGE.OTAA-INFO-MISSING") { - this.errorFields = ["OTAAapplicationKey"]; + if (error?.error?.message === 'MESSAGE.OTAA-INFO-MISSING') { + this.errorFields = ['OTAAapplicationKey']; this.errorMessages = [error?.error?.message]; - } else if (error?.error?.message == "MESSAGE.ID-INVALID-OR-ALREADY-IN-USE") { - this.errorFields = ["devEUI"]; + } else if (error?.error?.message === 'MESSAGE.ID-INVALID-OR-ALREADY-IN-USE') { + this.errorFields = ['devEUI']; this.errorMessages = [error?.error?.message]; } else { const errorMessage: ErrorMessage = this.errorMessageService.handleErrorMessageWithFields(error); diff --git a/src/app/applications/iot-devices/iot-devices-table/iot-devices-table.component.ts b/src/app/applications/iot-devices/iot-devices-table/iot-devices-table.component.ts index ac550bb76..a4ad26719 100644 --- a/src/app/applications/iot-devices/iot-devices-table/iot-devices-table.component.ts +++ b/src/app/applications/iot-devices/iot-devices-table/iot-devices-table.component.ts @@ -24,6 +24,7 @@ import { ReceivedMessageMetadata } from '@shared/models/received-message-metadat import { environment } from '@environments/environment'; import { startWith, switchMap, map, catchError } from 'rxjs/operators'; import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-iot-devices-table', @@ -65,7 +66,7 @@ export class IotDevicesTableComponent implements AfterViewInit, OnInit { } ngOnInit() { - this.canEdit = this.meService.canWriteInTargetOrganization(); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } ngAfterViewInit() { @@ -126,7 +127,7 @@ export class IotDevicesTableComponent implements AfterViewInit, OnInit { } clickDelete(element: any) { - if (element.type == DeviceType.SIGFOX) { + if (element.type === DeviceType.SIGFOX) { this.showSigfoxDeleteDialog(); } else { this.deleteDialogService.showSimpleDialog().subscribe((response) => { diff --git a/src/app/device-model/device-model-detail/device-model-detail.component.html b/src/app/device-model/device-model-detail/device-model-detail.component.html index 0347b31cf..f43d3ab07 100644 --- a/src/app/device-model/device-model-detail/device-model-detail.component.html +++ b/src/app/device-model/device-model-detail/device-model-detail.component.html @@ -1,6 +1,7 @@
+ [addDetailDowndown]="true" [dropDownButton]="dropdownButton" (deleteSelectedInDropdown)="clickDelete()" + [canEdit]="canEdit">
@@ -28,4 +29,4 @@

{{ 'DEVICE-MODEL.HEADLINE' | translate }}

- \ No newline at end of file + diff --git a/src/app/device-model/device-model-detail/device-model-detail.component.ts b/src/app/device-model/device-model-detail/device-model-detail.component.ts index 3e238a17f..d3cdebc30 100644 --- a/src/app/device-model/device-model-detail/device-model-detail.component.ts +++ b/src/app/device-model/device-model-detail/device-model-detail.component.ts @@ -8,6 +8,8 @@ import { DropdownButton } from '@shared/models/dropdown-button.model'; import { Subscription } from 'rxjs'; import { DeviceModelService } from '../device-model.service'; import { DeviceModel } from '../device.model'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-device-model-detail', @@ -22,6 +24,7 @@ export class DeviceModelDetailComponent implements OnInit, OnDestroy { deleteDialogSubscription: Subscription; dropdownButton: DropdownButton; errorTitle: string; + canEdit: boolean; constructor( private translate: TranslateService, @@ -29,6 +32,7 @@ export class DeviceModelDetailComponent implements OnInit, OnDestroy { private deviceModelService: DeviceModelService, private deleteDialogservice: DeleteDialogService, private router: Router, + private meService: MeService ) { } ngOnInit(): void { @@ -39,7 +43,7 @@ export class DeviceModelDetailComponent implements OnInit, OnDestroy { label: '', editRouterLink: '/device-model/device-model-edit/' + deviceModelId, isErasable: true, - } + }; } this.translate.use('da'); this.translate.get(['DEVICE-MODEL.DETAIL-TITLE', 'DEVICE-MODEL.DEVICE-MODEL', 'DEVICE-MODEL.SHOW-OPTIONS', 'DEVICE-MODEL.DELETE-FAILED']) @@ -49,6 +53,7 @@ export class DeviceModelDetailComponent implements OnInit, OnDestroy { this.title = translations['DEVICE-MODEL.DETAIL-TITLE']; this.errorTitle = translations['DEVICE-MODEL.DELETE-FAILED']; }); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } private getDeviceModel(id: number) { diff --git a/src/app/device-model/device-model-list/device-model-list.component.html b/src/app/device-model/device-model-list/device-model-list.component.html index 3e6f89a69..4c06fc42d 100644 --- a/src/app/device-model/device-model-list/device-model-list.component.html +++ b/src/app/device-model/device-model-list/device-model-list.component.html @@ -1,5 +1,6 @@ + [ctaRouterLink]="'device-model-edit'" + [canEdit]="canEdit">
@@ -9,4 +10,4 @@
- \ No newline at end of file + diff --git a/src/app/device-model/device-model-list/device-model-list.component.ts b/src/app/device-model/device-model-list/device-model-list.component.ts index 2d2676a9a..287897d00 100644 --- a/src/app/device-model/device-model-list/device-model-list.component.ts +++ b/src/app/device-model/device-model-list/device-model-list.component.ts @@ -2,6 +2,8 @@ import { Component, OnInit } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { TranslateService } from '@ngx-translate/core'; import { SharedVariableService } from '@shared/shared-variable/shared-variable.service'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-device-model-list', @@ -9,10 +11,12 @@ import { SharedVariableService } from '@shared/shared-variable/shared-variable.s styleUrls: ['./device-model-list.component.scss'] }) export class DeviceModelListComponent implements OnInit { + canEdit: boolean; constructor( private translate: TranslateService, - private titleService: Title + private titleService: Title, + private meService: MeService ) { translate.use('da'); } @@ -22,6 +26,7 @@ export class DeviceModelListComponent implements OnInit { .subscribe(translations => { this.titleService.setTitle(translations['TITLE.DEVICEMODEL']); }); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } } diff --git a/src/app/device-model/device-model-table/device-model-table.component.ts b/src/app/device-model/device-model-table/device-model-table.component.ts index 62d9fac29..b4529ae10 100644 --- a/src/app/device-model/device-model-table/device-model-table.component.ts +++ b/src/app/device-model/device-model-table/device-model-table.component.ts @@ -18,6 +18,7 @@ import { merge, Observable, of as observableOf, Subscription } from 'rxjs'; import { startWith, switchMap, map, catchError } from 'rxjs/operators'; import { DeviceModelService } from '../device-model.service'; import { DeviceModel, DeviceModelResponse } from '../device.model'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-device-model-table', @@ -45,7 +46,7 @@ export class DeviceModelTableComponent implements OnInit, AfterViewInit { ) {} ngOnInit(): void { - this.canEdit = this.meService.canWriteInTargetOrganization() + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); this.translateService .get(['DEVICE-MODEL.DELETE-FAILED']) .subscribe((translations) => { diff --git a/src/app/gateway/gateway-detail/gateway-detail.component.html b/src/app/gateway/gateway-detail/gateway-detail.component.html index f6981726c..01f4d957b 100644 --- a/src/app/gateway/gateway-detail/gateway-detail.component.html +++ b/src/app/gateway/gateway-detail/gateway-detail.component.html @@ -1,6 +1,6 @@
+ [dropDownButton]="dropdownButton" (deleteSelectedInDropdown)="onDeleteGateway()" [canEdit]="canEdit">
@@ -78,4 +78,4 @@

{{ 'GATEWAY.STATS' | translate }}

-
\ No newline at end of file + diff --git a/src/app/gateway/gateway-detail/gateway-detail.component.ts b/src/app/gateway/gateway-detail/gateway-detail.component.ts index b9e750079..b3230041e 100644 --- a/src/app/gateway/gateway-detail/gateway-detail.component.ts +++ b/src/app/gateway/gateway-detail/gateway-detail.component.ts @@ -11,6 +11,7 @@ import { DeleteDialogService } from '@shared/components/delete-dialog/delete-dia import { MeService } from '@shared/services/me.service'; import { environment } from '@environments/environment'; import { DropdownButton } from '@shared/models/dropdown-button.model'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-gateway-detail', @@ -34,6 +35,7 @@ export class GatewayDetailComponent implements OnInit, OnDestroy, AfterViewInit private deleteDialogSubscription: Subscription; public dropdownButton: DropdownButton; isLoadingResults = true; + canEdit: boolean; constructor( private gatewayService: ChirpstackGatewayService, @@ -47,11 +49,10 @@ export class GatewayDetailComponent implements OnInit, OnDestroy, AfterViewInit ngOnInit(): void { this.translate.use('da'); this.id = this.route.snapshot.paramMap.get('id'); - this.translate.get(['NAV.LORA-GATEWAYS']) - .subscribe(translations => { - this.backButton.label = translations['NAV.LORA-GATEWAYS']; - } - ); + this.translate.get(['NAV.LORA-GATEWAYS']).subscribe((translations) => { + this.backButton.label = translations['NAV.LORA-GATEWAYS']; + }); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.GatewayWrite, this.gateway.internalOrganizationId); } ngAfterViewInit() { @@ -75,7 +76,7 @@ export class GatewayDetailComponent implements OnInit, OnDestroy, AfterViewInit this.gatewayService.get(id).subscribe((result: any) => { result.gateway.tagsString = JSON.stringify(result.gateway.tags); this.gateway = result.gateway; - this.gateway.canEdit = this.canEdit(); + this.gateway.canEdit = this.canEdit; this.gatewayStats = result.stats; this.gatewayStats.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()); this.dataSource.data = this.gatewayStats; @@ -87,22 +88,18 @@ export class GatewayDetailComponent implements OnInit, OnDestroy, AfterViewInit } setDropdownButton() { - this.dropdownButton = this.canEdit() ? { + this.dropdownButton = this.canEdit ? { label: 'LORA-GATEWAY-TABLE-ROW.SHOW-OPTIONS', editRouterLink: '../../gateway-edit/' + this.id, isErasable: true, } : null; this.translate.get(['LORA-GATEWAY-TABLE-ROW.SHOW-OPTIONS']) .subscribe(translations => { - this.dropdownButton.label = translations['LORA-GATEWAY-TABLE-ROW.SHOW-OPTIONS'] + this.dropdownButton.label = translations['LORA-GATEWAY-TABLE-ROW.SHOW-OPTIONS']; } ); } - canEdit(): boolean { - return this.meService.canWriteInTargetOrganization(this.gateway.internalOrganizationId); - } - onDeleteGateway() { this.deleteDialogSubscription = this.deleteDialogService.showSimpleDialog().subscribe( (response) => { diff --git a/src/app/gateway/gateway-list/gateway-list.component.html b/src/app/gateway/gateway-list/gateway-list.component.html index 8c92e32f7..9dd32d932 100644 --- a/src/app/gateway/gateway-list/gateway-list.component.html +++ b/src/app/gateway/gateway-list/gateway-list.component.html @@ -1,5 +1,6 @@ + [ctaLabel]="'FORM.CREATE-NEW-LORA-GATEWAY' | translate" [ctaRouterLink]="'gateway-edit'" + [canEdit]="canEdit">
@@ -22,4 +23,4 @@
-
\ No newline at end of file + diff --git a/src/app/gateway/gateway-list/gateway-list.component.ts b/src/app/gateway/gateway-list/gateway-list.component.ts index d022dd4fe..89ef5a088 100644 --- a/src/app/gateway/gateway-list/gateway-list.component.ts +++ b/src/app/gateway/gateway-list/gateway-list.component.ts @@ -11,6 +11,7 @@ import { MeService } from '@shared/services/me.service'; import { SharedVariableService } from '@shared/shared-variable/shared-variable.service'; import { environment } from '@environments/environment'; import { Title } from '@angular/platform-browser'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ @@ -42,6 +43,7 @@ export class GatewayListComponent implements OnInit, OnChanges, OnDestroy { public pageTotal: number; organisationId: number; organisationChangeSubject: Subject = new Subject(); + canEdit: boolean; constructor( public translate: TranslateService, @@ -61,6 +63,7 @@ export class GatewayListComponent implements OnInit, OnChanges, OnDestroy { .subscribe(translations => { this.titleService.setTitle(translations['TITLE.LORAWAN-GATEWAY']); }); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.GatewayWrite); } ngOnChanges() { @@ -177,7 +180,7 @@ export class GatewayListComponent implements OnInit, OnChanges, OnDestroy { setCanEdit() { this.gateways.forEach( (gateway) => { - gateway.canEdit = this.meService.canWriteInTargetOrganization(gateway.internalOrganizationId); + gateway.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.GatewayWrite, gateway.internalOrganizationId); } ); } diff --git a/src/app/gateway/gateway-table/gateway-table.component.ts b/src/app/gateway/gateway-table/gateway-table.component.ts index 20211329f..aeae7b691 100644 --- a/src/app/gateway/gateway-table/gateway-table.component.ts +++ b/src/app/gateway/gateway-table/gateway-table.component.ts @@ -16,6 +16,7 @@ import { environment } from '@environments/environment'; import { MatSort } from '@angular/material/sort'; import { MatTableDataSource } from '@angular/material/table'; import { tableSorter } from '@shared/helpers/table-sorting.helper'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-gateway-table', @@ -84,7 +85,7 @@ export class GatewayTableComponent implements AfterViewInit { } canEdit(internalOrganizationId: number): boolean { - return this.meService.canWriteInTargetOrganization(internalOrganizationId); + return this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.GatewayWrite, internalOrganizationId); } private getGateways(): Observable { diff --git a/src/app/navbar/organisation-dropdown/organisation-dropdown.component.html b/src/app/navbar/organisation-dropdown/organisation-dropdown.component.html index 566b42df7..85bf40722 100644 --- a/src/app/navbar/organisation-dropdown/organisation-dropdown.component.html +++ b/src/app/navbar/organisation-dropdown/organisation-dropdown.component.html @@ -25,7 +25,7 @@ -
+ - \ No newline at end of file + diff --git a/src/app/navbar/organisation-dropdown/organisation-dropdown.component.ts b/src/app/navbar/organisation-dropdown/organisation-dropdown.component.ts index 3d73055b3..806499a75 100644 --- a/src/app/navbar/organisation-dropdown/organisation-dropdown.component.ts +++ b/src/app/navbar/organisation-dropdown/organisation-dropdown.component.ts @@ -6,6 +6,8 @@ import { UserResponse } from '@app/admin/users/user.model'; import { faExchangeAlt, faLayerGroup, faUsers, faIdBadge, faToolbox, faBurn } from '@fortawesome/free-solid-svg-icons'; import { TranslateService } from '@ngx-translate/core'; import { SharedVariableService } from '@shared/shared-variable/shared-variable.service'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-organisation-dropdown', @@ -15,7 +17,7 @@ import { SharedVariableService } from '@shared/shared-variable/shared-variable.s export class OrganisationDropdownComponent implements OnInit { public organisations: Organisation[]; public user: UserResponse; - public isOrgAdmin = false; + public isUserAdmin = false; public isGlobalAdmin = false; faExchangeAlt = faExchangeAlt; @@ -30,6 +32,7 @@ export class OrganisationDropdownComponent implements OnInit { private sharedVariableService: SharedVariableService, public translate: TranslateService, private route: Router, + private meService: MeService ) { } ngOnInit(): void { @@ -54,15 +57,16 @@ export class OrganisationDropdownComponent implements OnInit { } private setLocalPermissionCheck(orgId: number) { - this.isOrgAdmin = this.user?.permissions?.some(x => x.type == PermissionType.OrganizationAdmin && x.organization.id === +orgId); + this.isUserAdmin = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.UserAdministrationWrite); this.isGlobalAdmin = this.user?.permissions?.some( permission => permission.type === PermissionType.GlobalAdmin); } public onChange(organizationId: string) { this.sharedVariableService.setValue(+organizationId); this.setLocalPermissionCheck(+organizationId); - this.route.navigateByUrl('/', {skipLocationChange: true}).then(()=> - this.route.navigate(['applications'])); + this.route + .navigateByUrl('/', { skipLocationChange: true }) + .then(() => this.route.navigate(['applications'])); } setSelectedOrganisation(value) { diff --git a/src/app/payload-decoder/payload-decoder-detail/payload-decoder-detail.component.html b/src/app/payload-decoder/payload-decoder-detail/payload-decoder-detail.component.html index ed02e0818..c9b29cc68 100644 --- a/src/app/payload-decoder/payload-decoder-detail/payload-decoder-detail.component.html +++ b/src/app/payload-decoder/payload-decoder-detail/payload-decoder-detail.component.html @@ -1,6 +1,7 @@
+ [addDetailDowndown]="true" [dropDownButton]="dropdownButton" (deleteSelectedInDropdown)="onDeletePayload()" + [canEdit]="canEdit">
@@ -32,4 +33,4 @@

{{ 'PAYLOAD-DECODER.IOT-DEVICES' | translate }}

-
\ No newline at end of file + diff --git a/src/app/payload-decoder/payload-decoder-detail/payload-decoder-detail.component.ts b/src/app/payload-decoder/payload-decoder-detail/payload-decoder-detail.component.ts index 55283ea7a..2bd8a0d67 100644 --- a/src/app/payload-decoder/payload-decoder-detail/payload-decoder-detail.component.ts +++ b/src/app/payload-decoder/payload-decoder-detail/payload-decoder-detail.component.ts @@ -8,6 +8,7 @@ import { PayloadDecoder, PayloadDecoderBodyResponse } from '@payload-decoder/pay import { MeService } from '@shared/services/me.service'; import { DropdownButton } from '@shared/models/dropdown-button.model'; import { DeleteDialogService } from '@shared/components/delete-dialog/delete-dialog.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ @@ -57,7 +58,7 @@ export class PayloadDecoderDetailComponent implements OnInit, OnDestroy { } canEdit() { - this.payloadDecoder.canEdit = this.meService.canWriteInTargetOrganization(this.payloadDecoder?.organizationId); + this.payloadDecoder.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite, this.payloadDecoder?.organizationId); } private getPayloadDecoder(id: number) { diff --git a/src/app/payload-decoder/payload-decoder-edit/payload-decoder-edit.component.html b/src/app/payload-decoder/payload-decoder-edit/payload-decoder-edit.component.html index 9fb59fb46..30df23d57 100644 --- a/src/app/payload-decoder/payload-decoder-edit/payload-decoder-edit.component.html +++ b/src/app/payload-decoder/payload-decoder-edit/payload-decoder-edit.component.html @@ -1,4 +1,4 @@ - +
@@ -91,4 +91,4 @@
-
\ No newline at end of file + diff --git a/src/app/payload-decoder/payload-decoder-edit/payload-decoder-edit.component.ts b/src/app/payload-decoder/payload-decoder-edit/payload-decoder-edit.component.ts index cf7462e0a..c18f82549 100644 --- a/src/app/payload-decoder/payload-decoder-edit/payload-decoder-edit.component.ts +++ b/src/app/payload-decoder/payload-decoder-edit/payload-decoder-edit.component.ts @@ -22,6 +22,8 @@ import { SaveSnackService } from '@shared/services/save-snack.service'; import { ErrorMessageService } from '@shared/error-message.service'; import { ScrollToTopService } from '@shared/services/scroll-to-top.service'; import { environment } from '@environments/environment'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-payload-decoder-edit', @@ -64,6 +66,7 @@ export class PayloadDecoderEditComponent implements OnInit { public pageTotal: number; public pageOffset = 0; public deviceSubscription: Subscription; + canEdit: boolean; constructor( private translate: TranslateService, @@ -78,6 +81,7 @@ export class PayloadDecoderEditComponent implements OnInit { private saveSnackService: SaveSnackService, private errorMessageService: ErrorMessageService, private scrollToTopService: ScrollToTopService, + private meService: MeService ) { } ngOnInit(): void { @@ -116,11 +120,12 @@ export class PayloadDecoderEditComponent implements OnInit { this.sharedVariableService.getValue().subscribe((organisationId) => { this.getApplications(organisationId); }); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } setBackButtonLink(payloadDecoderId: number) { if (payloadDecoderId) { - this.backButton.routerLink = ['payload-decoder','payload-decoder-detail', this.id.toString()]; + this.backButton.routerLink = ['payload-decoder', 'payload-decoder-detail', this.id.toString()]; } else { this.backButton.routerLink = ['payload-decoder']; } @@ -136,25 +141,25 @@ export class PayloadDecoderEditComponent implements OnInit { } testPayloadFunction() { - this.errorMessages = null + this.errorMessages = null; this.testPayloadDecoder.code = this.payloadDecoderBody; try { this.testPayloadDecoder.iotDeviceJsonString = JSON.parse(this.metadata); } catch (err) { // Allow the empty string as a valid input if (this.isMetadataDefaultOrEmpty()) { - this.testPayloadDecoder.iotDeviceJsonString = JSON.parse("{}") + this.testPayloadDecoder.iotDeviceJsonString = JSON.parse('{}'); } else { - this.errorFields = ["metadata"]; + this.errorFields = ['metadata']; this.errorMessages = [this.metadataInvalidJSONMessage]; this.formFailedSubmit = true; - return; + return; } } try { this.testPayloadDecoder.rawPayloadJsonString = JSON.parse(this.payloadData); - }catch (err) { - this.errorFields = ["payload"]; + } catch (err) { + this.errorFields = ['payload']; this.errorMessages = [this.payloadInvalidJSONMessage]; this.formFailedSubmit = true; return; @@ -172,7 +177,7 @@ export class PayloadDecoderEditComponent implements OnInit { } private isMetadataDefaultOrEmpty() { - return this.metadata.trim() == "" || this.metadata.split("\n").every(x => x.trim().startsWith("//")); + return this.metadata.trim() === '' || this.metadata.split('\n').every(x => x.trim().startsWith('//')); } getCurrentOrganisationId(): number { diff --git a/src/app/payload-decoder/payload-decoder-list/payload-decoder-list.component.html b/src/app/payload-decoder/payload-decoder-list/payload-decoder-list.component.html index 5a4e84de7..02895820f 100644 --- a/src/app/payload-decoder/payload-decoder-list/payload-decoder-list.component.html +++ b/src/app/payload-decoder/payload-decoder-list/payload-decoder-list.component.html @@ -1,5 +1,6 @@ + [ctaRouterLink]="'payload-decoder-edit'" + [canEdit]="canEdit">
@@ -9,4 +10,4 @@
- \ No newline at end of file + diff --git a/src/app/payload-decoder/payload-decoder-list/payload-decoder-list.component.ts b/src/app/payload-decoder/payload-decoder-list/payload-decoder-list.component.ts index 5fba749e5..cb850a1d9 100644 --- a/src/app/payload-decoder/payload-decoder-list/payload-decoder-list.component.ts +++ b/src/app/payload-decoder/payload-decoder-list/payload-decoder-list.component.ts @@ -2,6 +2,8 @@ import { Component, OnInit } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { TranslateService } from '@ngx-translate/core'; import { Sort } from '@shared/models/sort.model'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-payload-decoder-list', @@ -9,19 +11,22 @@ import { Sort } from '@shared/models/sort.model'; styleUrls: ['./payload-decoder-list.component.scss'] }) export class PayloadDecoderListComponent implements OnInit { + canEdit: boolean; constructor( public translate: TranslateService, - private titleService: Title + private titleService: Title, + private meService: MeService ) { - translate.use('da') + translate.use('da'); } ngOnInit(): void { this.translate.get(['TITLE.PAYLOADDECODER']) .subscribe(translations => { this.titleService.setTitle(translations['TITLE.PAYLOADDECODER']); - }); + }); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } } diff --git a/src/app/payload-decoder/payload-decoder-list/payload-decoder-table/payload-decoder-table.component.html b/src/app/payload-decoder/payload-decoder-list/payload-decoder-table/payload-decoder-table.component.html index 075fcf627..f385794fd 100644 --- a/src/app/payload-decoder/payload-decoder-list/payload-decoder-table/payload-decoder-table.component.html +++ b/src/app/payload-decoder/payload-decoder-list/payload-decoder-table/payload-decoder-table.component.html @@ -69,4 +69,4 @@ showFirstLastButtons> - \ No newline at end of file + diff --git a/src/app/payload-decoder/payload-decoder-list/payload-decoder-table/payload-decoder-table.component.ts b/src/app/payload-decoder/payload-decoder-list/payload-decoder-table/payload-decoder-table.component.ts index 2b4c8cea2..1e1d4f071 100644 --- a/src/app/payload-decoder/payload-decoder-list/payload-decoder-table/payload-decoder-table.component.ts +++ b/src/app/payload-decoder/payload-decoder-list/payload-decoder-table/payload-decoder-table.component.ts @@ -18,6 +18,7 @@ import { Organisation } from '@app/admin/organisation/organisation.model'; import { SharedVariableService } from '@shared/shared-variable/shared-variable.service'; import { DeleteDialogService } from '@shared/components/delete-dialog/delete-dialog.service'; import { TranslateService } from '@ngx-translate/core'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-payload-decoder-table', @@ -95,7 +96,7 @@ export class PayloadDecoderTableComponent } getCanEdit(organizationId: number) { - return this.meService.canWriteInTargetOrganization(organizationId); + return this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite, organizationId); } public filterByOrgId(event: number) { diff --git a/src/app/profiles/device-profiles/device-profile.service.ts b/src/app/profiles/device-profiles/device-profile.service.ts index 7d69a2630..a4e10f3ee 100644 --- a/src/app/profiles/device-profiles/device-profile.service.ts +++ b/src/app/profiles/device-profiles/device-profile.service.ts @@ -42,7 +42,7 @@ export class DeviceProfileService { return response; } ) - );; + ); } getMultiple(): Observable { diff --git a/src/app/profiles/device-profiles/device-profiles-edit/device-profiles-edit.component.html b/src/app/profiles/device-profiles/device-profiles-edit/device-profiles-edit.component.html index 2c647d18f..6595db403 100644 --- a/src/app/profiles/device-profiles/device-profiles-edit/device-profiles-edit.component.html +++ b/src/app/profiles/device-profiles/device-profiles-edit/device-profiles-edit.component.html @@ -224,12 +224,12 @@

{{ 'PROFILES.DEVICE_PROFILE.DETAILS' | translate }}

- \ No newline at end of file + diff --git a/src/app/profiles/device-profiles/device-profiles-edit/device-profiles-edit.component.ts b/src/app/profiles/device-profiles/device-profiles-edit/device-profiles-edit.component.ts index c63fe56a0..2674c83ca 100644 --- a/src/app/profiles/device-profiles/device-profiles-edit/device-profiles-edit.component.ts +++ b/src/app/profiles/device-profiles/device-profiles-edit/device-profiles-edit.component.ts @@ -9,6 +9,7 @@ import { MeService } from '@shared/services/me.service'; import { Subscription } from 'rxjs'; import { DeviceProfile } from '../device-profile.model'; import { DeviceProfileService } from '../device-profile.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-device-profiles-edit', @@ -67,7 +68,7 @@ export class DeviceProfilesEditComponent implements OnInit, OnDestroy { canEdit() { if (this.deviceProfile.organizationID) { - this.deviceProfile.canEdit = this.meService.canWriteInTargetOrganization(this.deviceProfile.internalOrganizationId); + this.deviceProfile.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite, this.deviceProfile.internalOrganizationId); } else { this.deviceProfile.canEdit = true; } diff --git a/src/app/profiles/device-profiles/device-profiles-list/device-profiles-list.component.ts b/src/app/profiles/device-profiles/device-profiles-list/device-profiles-list.component.ts index 04bf5c03f..0c1576929 100644 --- a/src/app/profiles/device-profiles/device-profiles-list/device-profiles-list.component.ts +++ b/src/app/profiles/device-profiles/device-profiles-list/device-profiles-list.component.ts @@ -9,6 +9,7 @@ import { SharedVariableService } from '@shared/shared-variable/shared-variable.s import { DeleteDialogService } from '@shared/components/delete-dialog/delete-dialog.service'; import { TranslateService } from '@ngx-translate/core'; import { environment } from '@environments/environment'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-device-profiles-list', @@ -30,7 +31,6 @@ export class DeviceProfilesListComponent implements OnInit, OnDestroy { private route: ActivatedRoute, private deviceProfileService: DeviceProfileService, private meService: MeService, - private sharedVariableService: SharedVariableService, private deleteDialogService: DeleteDialogService, private translateService: TranslateService ) { } @@ -57,13 +57,13 @@ export class DeviceProfilesListComponent implements OnInit, OnDestroy { } canCreate() { - return this.sharedVariableService.getHasWritePermission() + return this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } setCanEdit() { this.deviceProfiles.forEach( (deviceProfile) => { - deviceProfile.canEdit = this.meService.canWriteInTargetOrganization(deviceProfile.internalOrganizationId); + deviceProfile.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite, deviceProfile.internalOrganizationId); } ); } diff --git a/src/app/profiles/profiles-list/profiles-list.component.html b/src/app/profiles/profiles-list/profiles-list.component.html index 01ed1b057..f51e2b1fd 100644 --- a/src/app/profiles/profiles-list/profiles-list.component.html +++ b/src/app/profiles/profiles-list/profiles-list.component.html @@ -1,4 +1,4 @@ - +
@@ -10,4 +10,4 @@
- \ No newline at end of file + diff --git a/src/app/profiles/profiles-list/profiles-list.component.ts b/src/app/profiles/profiles-list/profiles-list.component.ts index 99dca55b7..adff80882 100644 --- a/src/app/profiles/profiles-list/profiles-list.component.ts +++ b/src/app/profiles/profiles-list/profiles-list.component.ts @@ -1,6 +1,8 @@ import { Component, OnInit } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { TranslateService } from '@ngx-translate/core'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-profiles-list', @@ -8,11 +10,13 @@ import { TranslateService } from '@ngx-translate/core'; styleUrls: ['./profiles-list.component.scss'] }) export class ProfilesListComponent implements OnInit { + canEdit: boolean; constructor( public translate: TranslateService, - private titleService: Title - ) { + private titleService: Title, + private meService: MeService + ) { translate.use('da'); } @@ -21,6 +25,7 @@ export class ProfilesListComponent implements OnInit { .subscribe(translations => { this.titleService.setTitle(translations['TITLE.LORAWAN-PROFILE']); }); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } } diff --git a/src/app/profiles/service-profiles/service-profiles-edit/service-profiles-edit.component.ts b/src/app/profiles/service-profiles/service-profiles-edit/service-profiles-edit.component.ts index eef7d8999..b74458d9c 100644 --- a/src/app/profiles/service-profiles/service-profiles-edit/service-profiles-edit.component.ts +++ b/src/app/profiles/service-profiles/service-profiles-edit/service-profiles-edit.component.ts @@ -9,6 +9,8 @@ import { FormGroup } from '@angular/forms'; import { BackButton } from '@shared/models/back-button.model'; import { ServiceProfileService } from '../service-profile.service'; import { SharedVariableService } from '@shared/shared-variable/shared-variable.service'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ @@ -41,6 +43,7 @@ export class ServiceProfilesEditComponent implements OnInit { private sharedVariableService: SharedVariableService, private serviceProfileService: ServiceProfileService, private location: Location, + private meService: MeService ) { } @@ -56,7 +59,7 @@ export class ServiceProfilesEditComponent implements OnInit { if (this.id) { this.getServiceProfile(this.id); } - this.canEdit = this.sharedVariableService.getHasAnyWritePermission(); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } private getServiceProfile(id: string) { @@ -93,9 +96,9 @@ export class ServiceProfilesEditComponent implements OnInit { } private showError(error: HttpErrorResponse) { - if (error.status == 403) { - this.errorMessages = ["Forbudt"]; - this.errorFields = [] + if (error.status === 403) { + this.errorMessages = ['Forbudt']; + this.errorFields = []; } else { this.errorFields = []; this.errorMessage = ''; diff --git a/src/app/profiles/service-profiles/service-profiles-list/service-profiles-list.component.ts b/src/app/profiles/service-profiles/service-profiles-list/service-profiles-list.component.ts index 538fc8e7b..ab658c2c9 100644 --- a/src/app/profiles/service-profiles/service-profiles-list/service-profiles-list.component.ts +++ b/src/app/profiles/service-profiles/service-profiles-list/service-profiles-list.component.ts @@ -11,6 +11,8 @@ import { SharedVariableService } from '@shared/shared-variable/shared-variable.s import { DeleteDialogService } from '@shared/components/delete-dialog/delete-dialog.service'; import { TranslateService } from '@ngx-translate/core'; import { environment } from '@environments/environment'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-service-profiles-list', @@ -34,6 +36,7 @@ export class ServiceProfilesListComponent implements OnInit, OnDestroy { private sharedVariableService: SharedVariableService, private deleteDialogService: DeleteDialogService, private translateService: TranslateService, + private meService: MeService ) { } ngOnInit() { @@ -50,12 +53,12 @@ export class ServiceProfilesListComponent implements OnInit, OnDestroy { .getMultiple() .subscribe((result: ServiceProfileResponseMany) => { this.serviceProfiles = result.result; - this.setCanEdit() + this.setCanEdit(); }); } canCreate() { - return this.sharedVariableService.getHasAnyWritePermission(); + return this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } setCanEdit() { diff --git a/src/app/search/search-table/search-table.component.html b/src/app/search/search-table/search-table.component.html index 784831a1c..0549e5a85 100644 --- a/src/app/search/search-table/search-table.component.html +++ b/src/app/search/search-table/search-table.component.html @@ -88,11 +88,11 @@

- - \ No newline at end of file + diff --git a/src/app/search/search.component.html b/src/app/search/search.component.html index 684d4b5a2..aa077db6a 100644 --- a/src/app/search/search.component.html +++ b/src/app/search/search.component.html @@ -1,4 +1,4 @@ - +
@@ -8,4 +8,4 @@
- \ No newline at end of file + diff --git a/src/app/search/search.component.ts b/src/app/search/search.component.ts index 4d2d4edd1..a7ea56914 100644 --- a/src/app/search/search.component.ts +++ b/src/app/search/search.component.ts @@ -8,6 +8,9 @@ import { TranslateService } from '@ngx-translate/core'; styleUrls: ['./search.component.scss'], }) export class SearchComponent implements OnInit { + // TODO: Is search component used, and why does it even have a top bar? + canEdit = false; + constructor( public translate: TranslateService, private route: ActivatedRoute diff --git a/src/app/shared/components/top-bar/top-bar.component.ts b/src/app/shared/components/top-bar/top-bar.component.ts index f5a58fe38..fad10d8f9 100644 --- a/src/app/shared/components/top-bar/top-bar.component.ts +++ b/src/app/shared/components/top-bar/top-bar.component.ts @@ -15,7 +15,6 @@ import { PayloadDecoder } from '@payload-decoder/payload-decoder.model'; import { PermissionResponse } from '@app/admin/permission/permission.model'; import { UserResponse } from '@app/admin/users/user.model'; import { DropdownButton } from '@shared/models/dropdown-button.model'; -import { MeService } from '@shared/services/me.service'; @Component({ selector: 'app-top-bar', @@ -50,15 +49,14 @@ export class TopBarComponent implements OnInit { @Output() deleteSelectedInDropdown = new EventEmitter(); @Input() addDetailDowndown: boolean; @Input() dropDownButton: DropdownButton; - public canEdit = false; + @Input() canEdit = false; faSearch = faSearch; constructor( public translate: TranslateService, private location: Location, - private router: Router, - private meService: MeService + private router: Router ) { translate.use('da'); } @@ -68,7 +66,6 @@ export class TopBarComponent implements OnInit { if (this.data) { this.subTitle = this.data.name; } - this.canEdit = this.meService.canWriteInTargetOrganization() } diff --git a/src/app/shared/enums/access-scopes.ts b/src/app/shared/enums/access-scopes.ts new file mode 100644 index 000000000..153a64661 --- /dev/null +++ b/src/app/shared/enums/access-scopes.ts @@ -0,0 +1,5 @@ +export enum OrganizationAccessScope { + ApplicationWrite, + GatewayWrite, + UserAdministrationWrite, +} diff --git a/src/app/shared/services/me.service.ts b/src/app/shared/services/me.service.ts index 6ac54c75c..4f69151b1 100644 --- a/src/app/shared/services/me.service.ts +++ b/src/app/shared/services/me.service.ts @@ -1,7 +1,8 @@ import { Injectable } from '@angular/core'; -import { PermissionType } from '@app/admin/permission/permission.model'; +import { PermissionType, PermissionResponse } from '@app/admin/permission/permission.model'; import { UserResponse } from '@app/admin/users/user.model'; import { SharedVariableService } from '@shared/shared-variable/shared-variable.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Injectable({ providedIn: 'root', @@ -11,28 +12,54 @@ export class MeService { constructor(private sharedVariableService: SharedVariableService) {} - canWriteInTargetOrganization(id: number = this.sharedVariableService.getSelectedOrganisationId()): boolean { - const userInfo = this.sharedVariableService.getUserInfo(); - return userInfo.user.permissions.some((permission) => { - return ( + hasAccessToTargetOrganization( + scope: OrganizationAccessScope, + id: number = this.sharedVariableService.getSelectedOrganisationId() + ): boolean { + const { permissions } = this.sharedVariableService.getUserInfo().user; + + if (permissions.some((p) => p.type === PermissionType.GlobalAdmin)) { + return true; + } + + let canWriteCallback: (p: PermissionResponse) => boolean; + + switch (scope) { + case OrganizationAccessScope.ApplicationWrite: + canWriteCallback = this.canWriteApplicationInTargetOrganization; + break; + case OrganizationAccessScope.GatewayWrite: + canWriteCallback = this.canWriteGatewayInTargetOrganization; + break; + case OrganizationAccessScope.UserAdministrationWrite: + canWriteCallback = this.canWriteUserInTargetOrganization; + break; + default: + // Should never happen + return false; + } + + return permissions.some( + (permission) => permission.type === PermissionType.GlobalAdmin || - (permission.organization.id === id && - (permission.type === PermissionType.Write || - permission.type === PermissionType.OrganizationAdmin)) - ); - }); + (permission.organization.id === id && canWriteCallback(permission)) + ); } - hasAdminAccessInTargetOrganization(id: number): boolean { - const userInfo = this.sharedVariableService.getUserInfo(); - return userInfo.user.permissions.some((permission) => { - return ( - permission.type === PermissionType.GlobalAdmin || - (permission.organization.id === id && - permission.type === PermissionType.OrganizationAdmin) - ); - }); + private canWriteApplicationInTargetOrganization( + permission: PermissionResponse + ): boolean { + return permission.type === PermissionType.OrganizationApplicationAdmin; + } + + private canWriteGatewayInTargetOrganization(permission: PermissionResponse): boolean { + return permission.type === PermissionType.OrganizationGatewayAdmin; } + + private canWriteUserInTargetOrganization(permission: PermissionResponse): boolean { + return permission.type === PermissionType.OrganizationUserAdmin; + } + hasGlobalAdmin() { const userInfo = this.sharedVariableService.getUserInfo(); return userInfo.user.permissions.some( diff --git a/src/app/shared/shared-variable/shared-variable.service.ts b/src/app/shared/shared-variable/shared-variable.service.ts index 9aad08090..f4e8542ba 100644 --- a/src/app/shared/shared-variable/shared-variable.service.ts +++ b/src/app/shared/shared-variable/shared-variable.service.ts @@ -82,27 +82,6 @@ export class SharedVariableService { return this.getUserInfo().user.permissions.length > 0; } - getHasWritePermission(): boolean { - const permissions = this.getUserInfo().user.permissions; - return permissions.some( - (permission) => - permission.type === PermissionType.GlobalAdmin || - (permission.organization?.id === +this.selectedOrganisationId && - (permission.type === PermissionType.OrganizationAdmin || - permission.type === PermissionType.Write)) - ); - } - - getHasAnyWritePermission(): boolean { - const permissions = this.getUserInfo().user.permissions; - return permissions.some( - (permission) => - permission.type === PermissionType.GlobalAdmin || - permission.type === PermissionType.OrganizationAdmin || - permission.type === PermissionType.Write - ); - } - isGlobalAdmin(): boolean { return this.getUserInfo().user.permissions.some( (permission) => permission.type === PermissionType.GlobalAdmin diff --git a/src/app/sigfox/sigfox-groups-detail/sigfox-device-types-edit/sigfox-device-types-edit.component.ts b/src/app/sigfox/sigfox-groups-detail/sigfox-device-types-edit/sigfox-device-types-edit.component.ts index efdc539ba..e291d3099 100644 --- a/src/app/sigfox/sigfox-groups-detail/sigfox-device-types-edit/sigfox-device-types-edit.component.ts +++ b/src/app/sigfox/sigfox-groups-detail/sigfox-device-types-edit/sigfox-device-types-edit.component.ts @@ -14,6 +14,7 @@ import { Location } from '@angular/common'; import { ErrorMessageService } from '@shared/error-message.service'; import { ErrorMessage } from '@shared/models/error-message.model'; import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ @@ -66,7 +67,7 @@ export class SigfoxDeviceTypesEditComponent implements OnInit { this.sigfoxDeviceType.groupId = this.sigfoxGroupId; } this.getContracts(this.sigfoxGroupId); - this.canEdit = this.meService.canWriteInTargetOrganization() + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } private getContracts(groupId: number) { diff --git a/src/app/sigfox/sigfox-groups-detail/sigfox-groups-detail.component.html b/src/app/sigfox/sigfox-groups-detail/sigfox-groups-detail.component.html index a29e61710..b120e8255 100644 --- a/src/app/sigfox/sigfox-groups-detail/sigfox-groups-detail.component.html +++ b/src/app/sigfox/sigfox-groups-detail/sigfox-groups-detail.component.html @@ -1,7 +1,8 @@
+ [ctaLabel]="'SIGFOX-GROUP.PROFILES.CREATE-NEW-DEVICE-TYPE' | translate" [ctaRouterLink]="'new-device-type'" + [canEdit]="canEdit">
@@ -14,4 +15,4 @@

{{'SIGFOX-GROUP.PROFILES.DEVICE-TYPE' | translate}}

- \ No newline at end of file + diff --git a/src/app/sigfox/sigfox-groups-detail/sigfox-groups-detail.component.ts b/src/app/sigfox/sigfox-groups-detail/sigfox-groups-detail.component.ts index f49ecbe08..4a572bd30 100644 --- a/src/app/sigfox/sigfox-groups-detail/sigfox-groups-detail.component.ts +++ b/src/app/sigfox/sigfox-groups-detail/sigfox-groups-detail.component.ts @@ -8,6 +8,8 @@ import { SigfoxGroup } from '@shared/models/sigfox-group.model'; import { SigfoxService } from '@shared/services/sigfox.service'; import { SigfoxGroupData } from '@sigfox/sigfox-settings.model'; import { Observable } from 'rxjs'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ @@ -20,18 +22,20 @@ export class SigfoxGroupsDetailComponent implements OnInit { private sigfoxGroupId: number; sigfoxDevices: SigfoxDeviceType[]; sigfoxGroup: SigfoxGroup; + canEdit: boolean; constructor( public translate: TranslateService, private route: ActivatedRoute, private sigfoxService: SigfoxService, - + private meService: MeService ) { } ngOnInit(): void { this.sigfoxGroupId = +this.route.snapshot.paramMap.get('groupId'); this.getSigFoxGroup(this.sigfoxGroupId); this.getSigFoxDevices(); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } getSigFoxDevices() { diff --git a/src/app/sigfox/sigfox-groups-edit/sigfox-groups-edit.component.html b/src/app/sigfox/sigfox-groups-edit/sigfox-groups-edit.component.html index 10cdaa796..2cd03675a 100644 --- a/src/app/sigfox/sigfox-groups-edit/sigfox-groups-edit.component.html +++ b/src/app/sigfox/sigfox-groups-edit/sigfox-groups-edit.component.html @@ -1,4 +1,4 @@ - +
@@ -34,4 +34,4 @@
- \ No newline at end of file + diff --git a/src/app/sigfox/sigfox-groups-edit/sigfox-groups-edit.component.ts b/src/app/sigfox/sigfox-groups-edit/sigfox-groups-edit.component.ts index b6d2e1e4a..756342293 100644 --- a/src/app/sigfox/sigfox-groups-edit/sigfox-groups-edit.component.ts +++ b/src/app/sigfox/sigfox-groups-edit/sigfox-groups-edit.component.ts @@ -11,6 +11,8 @@ import { Subscription } from 'rxjs'; import { Location } from '@angular/common'; import { ErrorMessageService } from '@shared/error-message.service'; import { ErrorMessage } from '@shared/models/error-message.model'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ @@ -30,6 +32,7 @@ export class SigfoxGroupsEditComponent implements OnInit, OnDestroy { public formFailedSubmit = false; public title = ''; public backButton: BackButton = { label: '', routerLink: '/administration' }; + canEdit: boolean; constructor( private route: ActivatedRoute, @@ -38,12 +41,11 @@ export class SigfoxGroupsEditComponent implements OnInit, OnDestroy { private sigfoxService: SigfoxService, private location: Location, private sharedVariable: SharedVariableService, - private errorMessageService: ErrorMessageService - + private errorMessageService: ErrorMessageService, + private meService: MeService ) { } ngOnInit(): void { - this.translate.get(['SIGFOX-GROUP.SIGFOX-GROUP', 'FORM.EDIT-SIGFOX-GROUPS']) .subscribe(translations => { this.title = translations['FORM.EDIT-SIGFOX-GROUPS']; @@ -55,6 +57,7 @@ export class SigfoxGroupsEditComponent implements OnInit, OnDestroy { this.getSigfoxGroup(this.sigfoxGroupId); } this.sigfoxGroup.organizationId = this.sharedVariable.getSelectedOrganisationId(); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } getSigfoxGroup(id: number) { diff --git a/src/app/sigfox/sigfox-groups-list/sigfox-groups-list-item/sigfox-groups-list-item.component.ts b/src/app/sigfox/sigfox-groups-list/sigfox-groups-list-item/sigfox-groups-list-item.component.ts index 7f3989811..436e17051 100644 --- a/src/app/sigfox/sigfox-groups-list/sigfox-groups-list-item/sigfox-groups-list-item.component.ts +++ b/src/app/sigfox/sigfox-groups-list/sigfox-groups-list-item/sigfox-groups-list-item.component.ts @@ -3,6 +3,7 @@ import { ActivatedRoute, Router } from '@angular/router'; import { faEdit, faPen, faToolbox } from '@fortawesome/free-solid-svg-icons'; import { SigfoxGroup } from '@shared/models/sigfox-group.model'; import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-sigfox-groups-list-item', @@ -23,7 +24,7 @@ export class SigfoxGroupsListItemComponent implements OnInit { ngOnInit(): void { console.log(this.sigfoxGroup); - this.canEdit = this.meService.canWriteInTargetOrganization(); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } onEditSigfoxGroup() { diff --git a/src/app/sigfox/sigfox-groups-list/sigfox-groups-list.component.html b/src/app/sigfox/sigfox-groups-list/sigfox-groups-list.component.html index 0ec63d3df..7628bfa09 100644 --- a/src/app/sigfox/sigfox-groups-list/sigfox-groups-list.component.html +++ b/src/app/sigfox/sigfox-groups-list/sigfox-groups-list.component.html @@ -1,6 +1,7 @@
+ [ctaLabel]="'SIGFOX-GROUP.ADMINISTRATION.CREATE-NEW-GROUP' | translate" + [canEdit]="canEdit">
@@ -15,4 +16,4 @@

{{'SIGFOX-GROUP.ADMINISTRATION.NAME' | translate}}

- \ No newline at end of file + diff --git a/src/app/sigfox/sigfox-groups-list/sigfox-groups-list.component.ts b/src/app/sigfox/sigfox-groups-list/sigfox-groups-list.component.ts index 1f7a76b98..e1a6983b6 100644 --- a/src/app/sigfox/sigfox-groups-list/sigfox-groups-list.component.ts +++ b/src/app/sigfox/sigfox-groups-list/sigfox-groups-list.component.ts @@ -6,6 +6,8 @@ import { SigfoxGroup } from '@shared/models/sigfox-group.model'; import { SigfoxService } from '@shared/services/sigfox.service'; import { SharedVariableService } from '@shared/shared-variable/shared-variable.service'; import { Observable, Subscription } from 'rxjs'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-sigfox-groups-list', @@ -18,12 +20,15 @@ export class SigfoxGroupsListComponent implements OnInit, OnDestroy { subscription: Subscription; public sigfoxGroups: Observable; + canEdit: boolean; constructor( public translate: TranslateService, private globalService: SharedVariableService, private titleService: Title, - private sigfoxService: SigfoxService) { + private sigfoxService: SigfoxService, + private meService: MeService + ) { translate.use('da'); } @@ -33,6 +38,7 @@ export class SigfoxGroupsListComponent implements OnInit, OnDestroy { .subscribe(translations => { this.titleService.setTitle(translations['TITLE.SIGFOX']); }); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } getSigFoxGroups() { diff --git a/src/assets/i18n/da.json b/src/assets/i18n/da.json index 96c8b754f..db20c85cf 100644 --- a/src/assets/i18n/da.json +++ b/src/assets/i18n/da.json @@ -150,7 +150,7 @@ "AUTHORIZATIONHEADER": "Authorization header", "NO-AUTHORIZATIONHEADER": "Ingen Authorization header angivet", "ADD-TO-OPENDATADK": "Send data til OpenDataDK", - "OPENDATA-DK": "OpenDataDK", + "OPENDATA-DK": "OpenDataDK", "NO-OPENDATA-DK": "Der er ikke oprettet nogen datadeling med Open Data DK endnu" }, "OPENDATADK": { @@ -355,9 +355,10 @@ }, "PERMISSION-TYPE": { "GlobalAdmin": "Global administrator", - "OrganizationAdmin": "Organisations administrator", - "Write": "Skrive-rettigheder", - "Read": "Læse-rettigheder" + "OrganizationUserAdmin": "Brugeradministrator administrator", + "OrganizationGatewayAdmin": "Gateway administrator", + "OrganizationApplicationAdmin": "Applikationsadministrator", + "Read": "Læserettigheder" }, "FORM": { "CREATE-NEW-APPLICATION": "Opret ny applikation", @@ -697,7 +698,7 @@ "PINGSLOTFREQ": "Class-B ping-slot frequency", "SUPPORTSCLASSC_ACTIVATE": "Device supports Class-C", "CLASSCTIMEOUT": "Class C confirmed downlink timeout", - "CANCEL": "Anuller", + "CANCEL": "Annuller", "SAVE": "Gem", "OTAA-ABP": "Join (OTAA / ABP)", "MACVERSION_PLACEHOLDER": "1.0.0", From b3863b128701fa132763e047d99bb6aea8170c20 Mon Sep 17 00:00:00 2001 From: Aram Al-Sabti Date: Tue, 22 Feb 2022 15:22:13 +0100 Subject: [PATCH 2/9] Add back "canEdit" checks after merge --- .../fiware-detail.component.html | 10 +-- .../fiware-detail/fiware-detail.component.ts | 7 +- .../fiware-edit/fiware-edit.component.html | 55 ++++++++-------- .../fiware-edit/fiware-edit.component.ts | 7 +- .../httppush-detail.component.html | 4 +- .../httppush-detail.component.ts | 7 +- .../httppush-edit.component.html | 65 ++++++++++--------- .../httppush-edit/httppush-edit.component.ts | 7 +- 8 files changed, 91 insertions(+), 71 deletions(-) diff --git a/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.html b/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.html index 8e895d9c8..8ff3a9d7b 100644 --- a/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.html +++ b/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.html @@ -1,6 +1,6 @@
+ [dropDownButton]="dropdownButton" (deleteSelectedInDropdown)="onDeleteDatatarget()" [canEdit]="canEdit">
@@ -30,11 +30,11 @@

{{ 'DATATARGET.DETAILS' | translate }}

{{ 'DATATARGET.NO-AUTHORIZATIONHEADER' | translate }}

- +
- - + +
@@ -73,4 +73,4 @@

{{ 'DATATARGET.RELATIONS' | translate }}

-
\ No newline at end of file +
diff --git a/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.ts b/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.ts index d56148e67..24b64bb80 100644 --- a/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.ts +++ b/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.ts @@ -12,6 +12,8 @@ import { Datatarget } from '../../datatarget.model'; import { DropdownButton } from '@shared/models/dropdown-button.model'; import { faArrowsAltH } from '@fortawesome/free-solid-svg-icons'; import { DatatargetDetail } from '@applications/datatarget/datatarget-detail/datatarget-detail'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ @@ -28,6 +30,7 @@ export class FiwareDetailComponent implements DatatargetDetail, OnInit, OnDestr private deleteDialogSubscription: Subscription; public dropdownButton: DropdownButton; arrowsAltH = faArrowsAltH; + canEdit: boolean; constructor( private route: ActivatedRoute, @@ -35,7 +38,8 @@ export class FiwareDetailComponent implements DatatargetDetail, OnInit, OnDestr private location: Location, private datatargetRelationServicer: PayloadDeviceDatatargetService, private datatargetService: DatatargetService, - public translate: TranslateService) { } + public translate: TranslateService, + private meService: MeService) { } ngOnInit(): void { const id: number = +this.route.snapshot.paramMap.get('datatargetId'); @@ -54,6 +58,7 @@ export class FiwareDetailComponent implements DatatargetDetail, OnInit, OnDestr this.backButton.label = translations['NAV.MY-DATATARGET']; this.dropdownButton.label = translations['DATATARGET.SHOW-OPTIONS']; }); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } getDatatarget(id: number) { diff --git a/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.html b/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.html index 02ec75295..190a208ab 100644 --- a/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.html +++ b/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.html @@ -1,6 +1,7 @@ + backButtonTitle="{{backButtonTitle}}" + title="{{title}}" + [canEdit]="canEdit">
@@ -67,17 +68,17 @@
* -
@@ -96,19 +97,19 @@
{{'QUESTION.DATATARGET.RELATIONS' | translate}}
{{'QUESTION.ADD-RELATIONS' | translate}} - - - - + + +
+ + + + - + @@ -151,12 +152,12 @@
{{'QUESTION.DATATARGET.RELATIONS' | translate}}

{{'DATATARGET.DELETE' | translate}}

- - - - -
{{'QUESTION.DATATARGET.SELECT-DEVICES' | translate}} - -
-
+
{{'QUESTION.DATATARGET.SELECT-PAYLOADDECODER' | translate}} @@ -141,7 +142,7 @@
{{'QUESTION.DATATARGET.RELATIONS' | translate}}
{{payloadDecoder.name}} - +
- + +
+
diff --git a/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.ts b/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.ts index b52a823b6..92567fe66 100644 --- a/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.ts +++ b/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.ts @@ -21,6 +21,8 @@ import { ScrollToTopService } from '@shared/services/scroll-to-top.service'; import { DataTargetType } from '@shared/enums/datatarget-type'; import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons'; import { DatatargetEdit } from '@applications/datatarget/datatarget-edit/datatarget-edit'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-fiware-edit', @@ -53,7 +55,7 @@ export class FiwareEditComponent implements DatatargetEdit, OnInit, OnDestroy { payloadDeviceDatatarget: PayloadDeviceDatatarget[]; newDynamic: any = {}; faQuestionCircle = faQuestionCircle; - + canEdit: boolean; constructor( public translate: TranslateService, @@ -67,6 +69,7 @@ export class FiwareEditComponent implements DatatargetEdit, OnInit, OnDestroy { private dialog: MatDialog, private errorMessageService: ErrorMessageService, private scrollToTopService: ScrollToTopService, + private meService: MeService, ) { translate.use('da'); } @@ -105,7 +108,7 @@ export class FiwareEditComponent implements DatatargetEdit, OnInit, OnDestroy { this.getDevices(); } this.getPayloadDecoders(); - + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } diff --git a/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.html b/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.html index 42cf6d1f0..6ba94d0ac 100644 --- a/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.html +++ b/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.html @@ -1,6 +1,6 @@
+ [dropDownButton]="dropdownButton" (deleteSelectedInDropdown)="onDeleteDatatarget()" [canEdit]="canEdit">
@@ -71,4 +71,4 @@

{{ 'DATATARGET.RELATIONS' | translate }}

-
\ No newline at end of file +
diff --git a/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.ts b/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.ts index 179aebcf7..1cad19ae3 100644 --- a/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.ts +++ b/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.ts @@ -12,6 +12,8 @@ import { Datatarget } from '../../datatarget.model'; import { DropdownButton } from '@shared/models/dropdown-button.model'; import { faArrowsAltH } from '@fortawesome/free-solid-svg-icons'; import { DatatargetDetail } from '@applications/datatarget/datatarget-detail/datatarget-detail'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-httppush-detail', @@ -28,6 +30,7 @@ export class HttppushDetailComponent implements DatatargetDetail, OnInit, OnDes public dropdownButton: DropdownButton; arrowsAltH = faArrowsAltH; private applicationName: string; + canEdit: boolean; constructor( private route: ActivatedRoute, @@ -35,7 +38,8 @@ export class HttppushDetailComponent implements DatatargetDetail, OnInit, OnDes private location: Location, private datatargetRelationServicer: PayloadDeviceDatatargetService, private datatargetService: DatatargetService, - public translate: TranslateService) { } + public translate: TranslateService, + private meService: MeService) { } ngOnInit(): void { const id: number = +this.route.snapshot.paramMap.get('datatargetId'); @@ -54,6 +58,7 @@ export class HttppushDetailComponent implements DatatargetDetail, OnInit, OnDes this.backButton.label = translations['NAV.MY-DATATARGET']; this.dropdownButton.label = translations['DATATARGET.SHOW-OPTIONS']; }); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } getDatatarget(id: number) { diff --git a/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.html b/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.html index 4d4df069e..73725f599 100644 --- a/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.html +++ b/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.html @@ -1,6 +1,7 @@ + backButtonTitle="{{backButtonTitle}}" + title="{{title}}" + [canEdit]="canEdit"> @@ -11,9 +12,9 @@ - {{'DATATARGET.ADD-TO-OPENDATADK' | translate}} @@ -26,7 +27,7 @@ [ngClass]="{'is-invalid' : formFailedSubmit && errorFields.includes('name'), 'is-valid' : formFailedSubmit && !errorFields.includes('name')}"> - +
* @@ -38,17 +39,17 @@
* -
@@ -70,19 +71,19 @@
{{'QUESTION.DATATARGET.RELATIONS' | translate}}
{{'QUESTION.ADD-RELATIONS' | translate}} - - - - + + +
+ + + + - + @@ -125,15 +126,15 @@
{{'QUESTION.DATATARGET.RELATIONS' | translate}}

{{'DATATARGET.DELETE' | translate}}

- - - - -
{{'QUESTION.DATATARGET.SELECT-DEVICES' | translate}} - -
-
+
{{'QUESTION.DATATARGET.SELECT-PAYLOADDECODER' | translate}} @@ -115,7 +116,7 @@
{{'QUESTION.DATATARGET.RELATIONS' | translate}}
{{payloadDecoder.name}} - +
- + +
+
- \ No newline at end of file + diff --git a/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.ts b/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.ts index d192c2a65..c34cf7403 100644 --- a/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.ts +++ b/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.ts @@ -26,6 +26,8 @@ import { ScrollToTopService } from '@shared/services/scroll-to-top.service'; import { OpenDataDkDataset } from '../../opendatadk/opendatadk-dataset.model'; import { DataTargetType } from '@shared/enums/datatarget-type'; import { DatatargetEdit } from '@applications/datatarget/datatarget-edit/datatarget-edit'; +import { MeService } from '@shared/services/me.service'; +import { OrganizationAccessScope } from '@shared/enums/access-scopes'; @Component({ selector: 'app-httppush-edit', @@ -60,6 +62,7 @@ export class HttppushEditComponent payloadDeviceDatatarget: PayloadDeviceDatatarget[]; newDynamic: any = {}; + canEdit: boolean; constructor( public translate: TranslateService, @@ -74,7 +77,8 @@ export class HttppushEditComponent private errorMessageService: ErrorMessageService, private opendatadkService: OpendatadkService, private opendatadkDialogService: OpendatadkDialogService, - private scrollToTopService: ScrollToTopService + private scrollToTopService: ScrollToTopService, + private meService: MeService, ) { translate.use('da'); } @@ -110,6 +114,7 @@ export class HttppushEditComponent } this.getPayloadDecoders(); this.setDataSetExcists(); + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); } addRow() { From f70c4d3ecf87bdd5ba88b303bc50212632b8420e Mon Sep 17 00:00:00 2001 From: nlg Date: Tue, 10 May 2022 17:11:07 +0200 Subject: [PATCH 3/9] Added null checks on gateway details page --- src/app/auth/auth-guard.service.ts | 4 ++-- .../gateway-detail/gateway-detail.component.ts | 13 +++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/app/auth/auth-guard.service.ts b/src/app/auth/auth-guard.service.ts index 4331ea24b..055f9685c 100644 --- a/src/app/auth/auth-guard.service.ts +++ b/src/app/auth/auth-guard.service.ts @@ -11,8 +11,8 @@ export class AuthGuardService { canActivate(route: ActivatedRouteSnapshot): boolean { // Allow KOMBIT adgangsstyring callback to work if ( - route.queryParams['jwt'] != undefined || - route.queryParams['error'] != undefined + route.queryParams['jwt'] !== undefined || + route.queryParams['error'] !== undefined ) { return true; } diff --git a/src/app/gateway/gateway-detail/gateway-detail.component.ts b/src/app/gateway/gateway-detail/gateway-detail.component.ts index b3230041e..ca34e8e79 100644 --- a/src/app/gateway/gateway-detail/gateway-detail.component.ts +++ b/src/app/gateway/gateway-detail/gateway-detail.component.ts @@ -52,7 +52,10 @@ export class GatewayDetailComponent implements OnInit, OnDestroy, AfterViewInit this.translate.get(['NAV.LORA-GATEWAYS']).subscribe((translations) => { this.backButton.label = translations['NAV.LORA-GATEWAYS']; }); - this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.GatewayWrite, this.gateway.internalOrganizationId); + + if (this.gateway) { + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.GatewayWrite, this.gateway.internalOrganizationId); + } } ngAfterViewInit() { @@ -93,11 +96,13 @@ export class GatewayDetailComponent implements OnInit, OnDestroy, AfterViewInit editRouterLink: '../../gateway-edit/' + this.id, isErasable: true, } : null; + this.translate.get(['LORA-GATEWAY-TABLE-ROW.SHOW-OPTIONS']) .subscribe(translations => { - this.dropdownButton.label = translations['LORA-GATEWAY-TABLE-ROW.SHOW-OPTIONS']; - } - ); + if (this.dropdownButton) { + this.dropdownButton.label = translations['LORA-GATEWAY-TABLE-ROW.SHOW-OPTIONS']; + } + }); } onDeleteGateway() { From 73054c3cc2420e10500c86d5b022011228b5e224 Mon Sep 17 00:00:00 2001 From: nlg Date: Wed, 11 May 2022 08:42:01 +0200 Subject: [PATCH 4/9] Fixes for gateway admin role --- src/app/admin/permission/permission.model.ts | 1 - .../gateway-detail/gateway-detail.component.ts | 3 ++- .../organisation-dropdown.component.html | 14 ++++++++------ .../organisation-dropdown.component.ts | 2 ++ 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/app/admin/permission/permission.model.ts b/src/app/admin/permission/permission.model.ts index b80ef7fd0..ab7690b91 100644 --- a/src/app/admin/permission/permission.model.ts +++ b/src/app/admin/permission/permission.model.ts @@ -38,7 +38,6 @@ export enum PermissionType { OrganizationGatewayAdmin = 'OrganizationGatewayAdmin', OrganizationApplicationAdmin = 'OrganizationApplicationAdmin', Read = 'Read', - OrganizationPermission = 'OrganizationPermission', OrganizationApplicationPermissions = 'OrganizationApplicationPermissions', } diff --git a/src/app/gateway/gateway-detail/gateway-detail.component.ts b/src/app/gateway/gateway-detail/gateway-detail.component.ts index ca34e8e79..cb7ad4548 100644 --- a/src/app/gateway/gateway-detail/gateway-detail.component.ts +++ b/src/app/gateway/gateway-detail/gateway-detail.component.ts @@ -35,7 +35,7 @@ export class GatewayDetailComponent implements OnInit, OnDestroy, AfterViewInit private deleteDialogSubscription: Subscription; public dropdownButton: DropdownButton; isLoadingResults = true; - canEdit: boolean; + canEdit: boolean; constructor( private gatewayService: ChirpstackGatewayService, @@ -79,6 +79,7 @@ export class GatewayDetailComponent implements OnInit, OnDestroy, AfterViewInit this.gatewayService.get(id).subscribe((result: any) => { result.gateway.tagsString = JSON.stringify(result.gateway.tags); this.gateway = result.gateway; + this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.GatewayWrite, this.gateway.internalOrganizationId); this.gateway.canEdit = this.canEdit; this.gatewayStats = result.stats; this.gatewayStats.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()); diff --git a/src/app/navbar/organisation-dropdown/organisation-dropdown.component.html b/src/app/navbar/organisation-dropdown/organisation-dropdown.component.html index b119f3b7d..7e1dccfea 100644 --- a/src/app/navbar/organisation-dropdown/organisation-dropdown.component.html +++ b/src/app/navbar/organisation-dropdown/organisation-dropdown.component.html @@ -19,12 +19,14 @@ -
  • - - {{'NAV.DEVICE-MODEL' | translate}} - - -
  • +
    diff --git a/src/app/admin/permission/permission-detail/permission-detail.component.ts b/src/app/admin/permission/permission-detail/permission-detail.component.ts index 072668ce8..4d276a65d 100644 --- a/src/app/admin/permission/permission-detail/permission-detail.component.ts +++ b/src/app/admin/permission/permission-detail/permission-detail.component.ts @@ -3,7 +3,7 @@ import { ActivatedRoute, Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { PermissionService } from '@app/admin/permission/permission.service'; import { Subscription } from 'rxjs'; -import { PermissionResponse } from '../permission.model'; +import { PermissionResponse, PermissionType } from '../permission.model'; import { BackButton } from '@shared/models/back-button.model'; import { QuickActionButton } from '@shared/models/quick-action-button.model'; import { UserResponse } from '@app/admin/users/user.model'; @@ -46,6 +46,7 @@ export class PermissionDetailComponent implements OnInit, OnChanges { users: UserResponse[]; dropdownButton: DropdownButton; canEdit: boolean; + showApplicationTable = false; constructor( public translate: TranslateService, @@ -87,6 +88,12 @@ export class PermissionDetailComponent implements OnInit, OnChanges { .subscribe((response) => { this.permission = response; this.users = response.users; + this.showApplicationTable = this.meService.hasPermissions( + response, + PermissionType.Read, + PermissionType.OrganizationApplicationAdmin, + PermissionType.GlobalAdmin + ); this.isLoadingResults = false; }); } diff --git a/src/app/admin/permission/permission-edit/permission-edit.component.html b/src/app/admin/permission/permission-edit/permission-edit.component.html index f110c567d..3ea99186e 100644 --- a/src/app/admin/permission/permission-edit/permission-edit.component.html +++ b/src/app/admin/permission/permission-edit/permission-edit.component.html @@ -21,13 +21,18 @@
    * - + [placeholder]="'PERMISSION.EDIT.TYPE-PLACEHOLDER' | translate" + [compareWith]="compareLevels" + [multiple]="true"> + + {{'PERMISSION-TYPE.' + level.type | translate}} + +
    @@ -43,7 +48,7 @@
    -
    +
    *
    diff --git a/src/app/admin/users/accept-user/accept-user.component.ts b/src/app/admin/users/accept-user/accept-user.component.ts index 0fd839df7..0bc83102c 100644 --- a/src/app/admin/users/accept-user/accept-user.component.ts +++ b/src/app/admin/users/accept-user/accept-user.component.ts @@ -4,6 +4,7 @@ import { ActivatedRoute, Router } from '@angular/router'; import { PermissionRequestAcceptUser, PermissionType, + PermissionTypes, } from '@app/admin/permission/permission.model'; import { TranslateService } from '@ngx-translate/core'; import { ErrorMessageService } from '@shared/error-message.service'; @@ -29,6 +30,12 @@ export class AcceptUserComponent implements OnInit { organizationId: number; public formFailedSubmit = false; errorMessages: any; + allowedLevels: PermissionTypes[] = [ + { type: PermissionType.OrganizationUserAdmin }, + { type: PermissionType.OrganizationApplicationAdmin }, + { type: PermissionType.OrganizationGatewayAdmin }, + { type: PermissionType.Read }, + ]; constructor( private userService: UserService, @@ -37,7 +44,8 @@ export class AcceptUserComponent implements OnInit { private route: ActivatedRoute, private errorMessageService: ErrorMessageService, private permissionService: PermissionService - ) {} + ) { + } ngOnInit(): void { this.userId = +this.route.snapshot.paramMap.get('user-id'); @@ -64,14 +72,6 @@ export class AcceptUserComponent implements OnInit { }); } - allowedLevels() { - return [ - PermissionType.OrganizationAdmin, - PermissionType.Write, - PermissionType.Read, - ]; - } - private showError(err: HttpErrorResponse) { const result = this.errorMessageService.handleErrorMessageWithFields(err); this.errorFields = result.errorFields; diff --git a/src/app/admin/users/new-kombit-user-page/new-user.component.ts b/src/app/admin/users/new-kombit-user-page/new-user.component.ts index 74875da6f..79fcfac9e 100644 --- a/src/app/admin/users/new-kombit-user-page/new-user.component.ts +++ b/src/app/admin/users/new-kombit-user-page/new-user.component.ts @@ -89,11 +89,13 @@ export class NewUserComponent implements OnInit { onSubmit(): void { this.resetErrors(); - const createNewKombitUserDTO = this.mapToDto(this.createNewKombitUserFromFrontend); - + const createNewKombitUserDTO = this.mapToDto( + this.createNewKombitUserFromFrontend + ); + this.userService.updateNewKombit(createNewKombitUserDTO).subscribe( () => { - this.router.navigate(['/dashboard']); + this.router.navigate(['/applications']); }, (error: HttpErrorResponse) => { this.handleError(error); @@ -102,18 +104,18 @@ export class NewUserComponent implements OnInit { ); } - private mapToDto(frontendModel: CreateNewKombitUserFromFrontend): CreateNewKombitUserDto { + private mapToDto( + frontendModel: CreateNewKombitUserFromFrontend + ): CreateNewKombitUserDto { const createNewKombitUserDTO = new CreateNewKombitUserDto(); createNewKombitUserDTO.email = frontendModel.email; createNewKombitUserDTO.requestedOrganizationIds = []; frontendModel.requestedOrganizations.forEach((organization) => { - createNewKombitUserDTO.requestedOrganizationIds.push( - organization.id - ); + createNewKombitUserDTO.requestedOrganizationIds.push(organization.id); }); - return createNewKombitUserDTO; + return createNewKombitUserDTO; } public compare( diff --git a/src/app/applications/applications-list/applications-list.component.html b/src/app/applications/applications-list/applications-list.component.html index f6db0922a..269d2c931 100644 --- a/src/app/applications/applications-list/applications-list.component.html +++ b/src/app/applications/applications-list/applications-list.component.html @@ -1,16 +1,3 @@ -<<<<<<< HEAD - - -
    -
    -
    -
    - -
    -
    -
    -=======
    @@ -41,5 +28,4 @@

    {{'WELCOME-DIALOG.NO-ACCESS' | translate}}

    ->>>>>>> stage
    diff --git a/src/app/applications/applications-list/applications-list.component.ts b/src/app/applications/applications-list/applications-list.component.ts index efa1896a6..d8889c0fa 100644 --- a/src/app/applications/applications-list/applications-list.component.ts +++ b/src/app/applications/applications-list/applications-list.component.ts @@ -51,12 +51,13 @@ export class ApplicationsListComponent implements OnInit { } ngOnInit(): void { - this.translate.get(['TITLE.APPLICATION']) - .subscribe(translations => { - this.titleService.setTitle(translations['TITLE.APPLICATION']); - }); + this.translate.get(['TITLE.APPLICATION']).subscribe((translations) => { + this.titleService.setTitle(translations['TITLE.APPLICATION']); + }); this.organizationId = this.globalService.getSelectedOrganisationId(); - this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); + this.canEdit = this.meService.hasAccessToTargetOrganization( + OrganizationAccessScope.ApplicationWrite + ); // Authenticate user this.verifyUserAndInit(); @@ -73,7 +74,8 @@ export class ApplicationsListComponent implements OnInit { ]) .toPromise() .then((translations) => { - this.unauthorizedMessage = translations['WELCOME-DIALOG.NO-JOB-ACCESS']; + this.unauthorizedMessage = + translations['WELCOME-DIALOG.NO-JOB-ACCESS']; this.kombitError = translations['WELCOME-DIALOG.KOMBIT-LOGIN-ERROR']; this.noAccess = translations['WELCOME-DIALOG.USER-INACTIVE']; this.titleService.setTitle(translations['TITLE.FRONTPAGE']); @@ -84,15 +86,15 @@ export class ApplicationsListComponent implements OnInit { if (jwt) { this.authService.setSession(jwt); - const userInfo = await this.sharedVariableService.setUserInfo(); + const userInfo = await this.sharedVariableService.setUserInfo(); if (userInfo.user.email) { this.router.navigate(['/new-user'], { state: { fromKombit: true }, }); - } else { - // Clear the URL from the parameter - this.router.navigate(['/applications']); - } + } else { + // Clear the URL from the parameter + this.router.navigate(['/applications']); + } } else { const error = params['error']; if (error) { @@ -116,7 +118,7 @@ export class ApplicationsListComponent implements OnInit { } const userInfo = await this.sharedVariableService.setUserInfo(); - this.isGlobalAdmin = this.sharedVariableService.isGlobalAdmin(); + this.isGlobalAdmin = this.meService.hasGlobalAdmin(); const hasSeenWelcomeScreen = this.userMinimalService.getHasSeenWelcomeScreen(); this.hasSomePermission = this.sharedVariableService.getHasAnyPermission(); @@ -135,7 +137,7 @@ export class ApplicationsListComponent implements OnInit { maxWidth: '60vw', data: { hasSomePermission: this.hasSomePermission, - } as WelcomeDialogModel + } as WelcomeDialogModel, }); } diff --git a/src/app/applications/iot-devices/iot-device-detail/iot-device-detail.component.html b/src/app/applications/iot-devices/iot-device-detail/iot-device-detail.component.html index 84e28b26f..3f3d22faf 100644 --- a/src/app/applications/iot-devices/iot-device-detail/iot-device-detail.component.html +++ b/src/app/applications/iot-devices/iot-device-detail/iot-device-detail.component.html @@ -64,7 +64,7 @@
    - +
    From 8a3091382f1276cb60d566b1d59a3e14166e48bd Mon Sep 17 00:00:00 2001 From: Aram Al-Sabti Date: Wed, 18 May 2022 17:24:54 +0200 Subject: [PATCH 8/9] Update accept kombit to use group instead of level --- .../permission-edit.component.html | 2 +- src/app/admin/permission/permission.model.ts | 2 +- .../accept-user/accept-user.component.html | 31 +++++--------- .../accept-user/accept-user.component.ts | 41 +++++++++++++++++-- 4 files changed, 49 insertions(+), 27 deletions(-) diff --git a/src/app/admin/permission/permission-edit/permission-edit.component.html b/src/app/admin/permission/permission-edit/permission-edit.component.html index 3ea99186e..cbf16ea1c 100644 --- a/src/app/admin/permission/permission-edit/permission-edit.component.html +++ b/src/app/admin/permission/permission-edit/permission-edit.component.html @@ -25,7 +25,7 @@ required [formControl]="permissionLevelsCtrl" [(value)]="permission.levels" - [ngClass]="{'is-invalid' : formFailedSubmit && errorFields.includes('organizationId'), 'is-valid' : formFailedSubmit && !errorFields.includes('organizationId')}" + [ngClass]="{'is-invalid' : formFailedSubmit && errorFields.includes('level'), 'is-valid' : formFailedSubmit && !errorFields.includes('level')}" [placeholder]="'PERMISSION.EDIT.TYPE-PLACEHOLDER' | translate" [compareWith]="compareLevels" [multiple]="true"> diff --git a/src/app/admin/permission/permission.model.ts b/src/app/admin/permission/permission.model.ts index e581a2f2d..ea0bb414a 100644 --- a/src/app/admin/permission/permission.model.ts +++ b/src/app/admin/permission/permission.model.ts @@ -14,7 +14,7 @@ export class PermissionRequest { export class PermissionRequestAcceptUser { organizationId: number; userId: number; - level: PermissionType; + permissionIds: number[]; } export interface PermissionResponse { diff --git a/src/app/admin/users/accept-user/accept-user.component.html b/src/app/admin/users/accept-user/accept-user.component.html index ae57253fc..69e7c61a5 100644 --- a/src/app/admin/users/accept-user/accept-user.component.html +++ b/src/app/admin/users/accept-user/accept-user.component.html @@ -27,28 +27,17 @@

    'PERMISSION.EDIT.TYPE' | translate }}* - + [formControl]="permissionsCtrl" + [(value)]="permission.permissionIds" + [ngClass]="{'is-invalid' : formFailedSubmit && errorFields.includes('permissionIds'), 'is-valid' : formFailedSubmit && !errorFields.includes('permissionIds')}" + [placeholder]="'PERMISSION.EDIT.TYPE-PLACEHOLDER' | translate" + [multiple]="true"> + + {{ permission.name }} + +

    -
    +

    {{ 'PERMISSION.DETAIL.APPLICATIONS' | translate }}

    - - + +
    diff --git a/src/app/admin/permission/permission-detail/permission-detail.component.ts b/src/app/admin/permission/permission-detail/permission-detail.component.ts index 4d276a65d..e13ec9a13 100644 --- a/src/app/admin/permission/permission-detail/permission-detail.component.ts +++ b/src/app/admin/permission/permission-detail/permission-detail.component.ts @@ -114,4 +114,13 @@ export class PermissionDetailComponent implements OnInit, OnChanges { this.router.navigate(['edit-permission'], { relativeTo: this.route }); } + isApplicationAdmin () { + if (this.permission) { + if (this.permission.type.some(perm => perm.type === PermissionType.OrganizationApplicationAdmin)) { + return true; + } + } + + return false; + } }