Fix Bug 2294: Incorrect notification in update descriptor
[osm/NG-UI.git] / src / app / roles / roles-create-edit / RolesCreateEditComponent.ts
1 /*
2  Copyright 2020 TATA ELXSI
3
4  Licensed under the Apache License, Version 2.0 (the 'License');
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7
8   http://www.apache.org/licenses/LICENSE-2.0
9
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15
16  Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
17 */
18 /**
19  * @file Roles Create and Edit Component
20  */
21 import { isNullOrUndefined } from 'util';
22 import { HttpClient, HttpHeaders } from '@angular/common/http';
23 import { Component, Injector, Input, OnInit } from '@angular/core';
24 import { FormBuilder, FormGroup, Validators } from '@angular/forms';
25 import { ActivatedRoute, Router } from '@angular/router';
26 import { TranslateService } from '@ngx-translate/core';
27 import { NotifierService } from 'angular-notifier';
28 import { APIURLHEADER, ERRORDATA } from 'CommonModel';
29 import { environment } from 'environment';
30 import * as jsonpath from 'jsonpath';
31 import { RestService } from 'RestService';
32 import { Permission, PermissionGroup, RoleConfig, RoleData } from 'RolesModel';
33 import { SharedService } from 'SharedService';
34
35 /**
36  * Creating component
37  * @Component takes RolesCreateEditComponent.html as template url
38  */
39 @Component({
40   selector: 'app-roles-create-edit',
41   templateUrl: './RolesCreateEditComponent.html',
42   styleUrls: ['./RolesCreateEditComponent.scss']
43 })
44 /** Exporting a class @exports RolesCreateEditComponent */
45 export class RolesCreateEditComponent implements OnInit {
46   /** To inject services @public */
47   public injector: Injector;
48
49   /** contains role permissions from config file @public */
50   public rolePermissions: {}[];
51
52   /** contains role form group information @public */
53   public roleForm: FormGroup;
54
55   /** Instance of the rest service @public */
56   public restService: RestService;
57
58   /** Check the loading results for loader status @public */
59   public isLoadingResults: boolean = false;
60
61   /** Give the message for the loading @public */
62   public message: string = 'PLEASEWAIT';
63
64   /** Instance to check role form submitted status @public */
65   public submitted: boolean = false;
66
67   /** Contains role create or edit value @public */
68   public getRoleType: string;
69
70   /** Contains view selection value either text or preview @public */
71   public viewMode: string = 'text';
72
73   /** Contains current permissions data @private */
74   private currentPermissions: string;
75
76   /** Contains current role name @private */
77   private currentRoleName: string;
78
79   /** Contains modified role name @private */
80   private modifiedRoleName: string;
81
82   /** Contains role id value @private */
83   private roleRef: string;
84
85   /** Notifier service to popup notification @private */
86   private notifierService: NotifierService;
87
88   /** Contains tranlsate instance @private */
89   private translateService: TranslateService;
90
91   /** contians form builder module @private */
92   private formBuilder: FormBuilder;
93
94   /** Contains all methods related to shared @private */
95   private sharedService: SharedService;
96
97   /** Controls the header form @private */
98   private headers: HttpHeaders;
99
100   /** Varaibles to hold http client @private */
101   private httpClient: HttpClient;
102
103   /** Holds the instance of activatedRoute of router service @private */
104   private activatedRoute: ActivatedRoute;
105
106   /** Holds the instance of roter service @private */
107   private router: Router;
108
109   constructor(injector: Injector) {
110     this.injector = injector;
111     this.restService = this.injector.get(RestService);
112     this.notifierService = this.injector.get(NotifierService);
113     this.translateService = this.injector.get(TranslateService);
114     this.formBuilder = this.injector.get(FormBuilder);
115     this.sharedService = this.injector.get(SharedService);
116     this.httpClient = this.injector.get(HttpClient);
117     this.activatedRoute = this.injector.get(ActivatedRoute);
118     this.router = this.injector.get(Router);
119   }
120
121   /** Lifecyle Hooks the trigger before component is instantiate @public */
122   public ngOnInit(): void {
123     this.headers = new HttpHeaders({
124       'Content-Type': 'application/json',
125       Accept: 'application/json',
126       'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
127     });
128     this.roleForm = this.formBuilder.group({
129       roleName: ['', [Validators.required]],
130       permissions: ['']
131     });
132     this.getRolePermissions();
133   }
134
135   /** Get role permission information based on action @public */
136   public getRolePermissions(): void {
137     this.isLoadingResults = true;
138     this.loadPermissions().then((response: RoleConfig) => {
139       this.rolePermissions = response.rolePermissions;
140       if (this.activatedRoute.snapshot.url[0].path === 'create') {
141         this.getRoleType = 'Add';
142         this.isLoadingResults = false;
143       } else {
144         this.getRoleType = 'Edit';
145         this.getRoleData();
146       }
147     }).catch(() => {
148       // Empty Block
149     });
150   }
151
152   /** Check Role Create or Edit and proceed action @public */
153   public roleCheck(): void {
154     this.submitted = true;
155     if (!this.roleForm.valid) {
156       const errorIp: Element = document.querySelector('.ng-invalid[formControlName]');
157       if (errorIp) {
158         errorIp.scrollIntoView({ behavior: 'smooth', block: 'center' });
159       }
160     } else {
161       if (this.getRoleType === 'Add') {
162         this.createRole();
163       } else {
164         this.editRole();
165       }
166     }
167   }
168
169   /** Convenience getter for easy access to form fields */
170   get f(): FormGroup['controls'] { return this.roleForm.controls; }
171
172   /** Create role @private  */
173   public createRole(): void {
174     const apiURLHeader: APIURLHEADER = {
175       url: environment.ROLES_URL,
176       httpOptions: { headers: this.headers }
177     };
178     let permissionData: Object = {};
179     this.sharedService.cleanForm(this.roleForm);
180     if (!this.roleForm.invalid) {
181       if (this.viewMode === 'preview') {
182         this.isLoadingResults = true;
183         permissionData = this.generatePermissions();
184         this.roleCreateAPI(apiURLHeader, permissionData);
185       } else {
186         if (this.checkPermission()) {
187           this.isLoadingResults = true;
188           permissionData = this.roleForm.value.permissions !== '' ? JSON.parse(this.roleForm.value.permissions) : {};
189           this.roleCreateAPI(apiURLHeader, permissionData);
190         }
191       }
192     }
193   }
194
195   /** Method to handle role create API call @public */
196   public roleCreateAPI(apiURLHeader: APIURLHEADER, permissionData: {}): void {
197     const postData: {} = {
198       name: this.roleForm.value.roleName,
199       permissions: !isNullOrUndefined(permissionData) ? permissionData : {}
200     };
201     this.restService.postResource(apiURLHeader, postData).subscribe(() => {
202       this.notifierService.notify('success', this.translateService.instant('PAGE.ROLES.CREATEDSUCCESSFULLY'));
203       this.router.navigate(['/roles/details']).catch((): void => {
204         // Catch Navigation Error
205       });
206     }, (error: ERRORDATA) => {
207       this.isLoadingResults = false;
208       this.restService.handleError(error, 'post');
209     });
210   }
211
212   /** Edit role  @private  */
213   public editRole(): void {
214     const apiURLHeader: APIURLHEADER = {
215       url: environment.ROLES_URL + '/' + this.roleRef,
216       httpOptions: { headers: this.headers }
217     };
218     this.modifiedRoleName = this.roleForm.value.roleName;
219     let permissionData: Object = {};
220     this.sharedService.cleanForm(this.roleForm);
221     if (!this.roleForm.invalid) {
222       if (this.viewMode === 'preview') {
223         permissionData = this.generatePermissions();
224         this.roleEditAPI(apiURLHeader, permissionData);
225       } else {
226         if (this.checkPermission()) {
227           permissionData = this.roleForm.value.permissions !== '' ? JSON.parse(this.roleForm.value.permissions) : {};
228           this.roleEditAPI(apiURLHeader, permissionData);
229         }
230       }
231     }
232   }
233
234   /** Method to handle role edit API call */
235   public roleEditAPI(apiURLHeader: APIURLHEADER, permissionData: {}): void {
236     if ((JSON.stringify(permissionData, null, '\t') === this.currentPermissions) && (this.modifiedRoleName === this.currentRoleName)) {
237       this.notifierService.notify('warning', this.translateService.instant('PAGE.TOPOLOGY.DATAEMPTY'));
238       return;
239     }
240     this.isLoadingResults = true;
241     const postData: {} = {
242       name: this.roleForm.value.roleName,
243       permissions: !isNullOrUndefined(permissionData) ? permissionData : {}
244     };
245     this.restService.patchResource(apiURLHeader, postData).subscribe(() => {
246       this.notifierService.notify('success', this.translateService.instant('PAGE.ROLES.UPDATEDSUCCESSFULLY'));
247       this.router.navigate(['/roles/details']).catch((): void => {
248         // Catch Navigation Error
249       });
250     }, (error: ERRORDATA) => {
251       this.isLoadingResults = false;
252       this.restService.handleError(error, 'patch');
253     });
254   }
255
256   /** Method to handle toggle role view selection @public */
257   public viewSelection(): void {
258     if (this.viewMode === 'text' && this.checkPermission()) {
259       this.loadPermissions().then((response: RoleConfig) => {
260         this.rolePermissions = response.rolePermissions;
261         const permissions: {} = this.roleForm.value.permissions !== '' ? JSON.parse(this.roleForm.value.permissions) : {};
262         this.filterRoleData(permissions);
263         this.viewMode = 'preview';
264       }).catch(() => {
265         // Empty Block
266       });
267     } else {
268       const rolePermission: {} = this.generatePermissions();
269       if (Object.keys(rolePermission).length !== 0) {
270         this.roleForm.patchValue({ permissions: JSON.stringify(rolePermission, null, '\t') });
271       }
272       this.viewMode = 'text';
273     }
274   }
275
276   /** Generate role permission post data @private */
277   private generatePermissions(): Object {
278     const permissions: Object = {};
279     this.rolePermissions.forEach((permissionGroup: PermissionGroup) => {
280       if (!isNullOrUndefined(permissionGroup)) {
281         permissionGroup.permissions.forEach((permission: Permission) => {
282           if (!isNullOrUndefined(permission.value) && permission.value !== 'NA') {
283             permissions[permission.operation] = permission.value;
284           }
285         });
286       }
287     });
288     return permissions;
289   }
290
291   /** Validation method for check permission json string @private */
292   private checkPermission(): boolean {
293     if (this.roleForm.value.permissions) {
294       if (!this.sharedService.checkJson(this.roleForm.value.permissions)) {
295         this.notifierService.notify('error', this.translateService.instant('PAGE.ROLES.ROLEJSONERROR'));
296         return false;
297       } else {
298         this.roleForm.value.permissions = this.roleForm.value.permissions.replace(/'/g, '"');
299         const rolePermission: {} = JSON.parse(this.roleForm.value.permissions);
300         for (const key of Object.keys(rolePermission)) {
301           // eslint-disable-next-line security/detect-object-injection
302           if (typeof rolePermission[key] !== 'boolean') {
303             this.notifierService.notify('error', this.translateService.instant('PAGE.ROLES.ROLEKEYERROR', { roleKey: key }));
304             return false;
305           }
306         }
307       }
308     }
309     return true;
310   }
311
312   /** Get role data from NBI based on ID and apply filter @private */
313   private getRoleData(): void {
314     this.roleRef = this.activatedRoute.snapshot.paramMap.get('id');
315     if (!isNullOrUndefined(this.roleRef)) {
316       this.restService.getResource(environment.ROLES_URL + '/' + this.roleRef).subscribe((data: RoleData) => {
317         this.roleForm.setValue({ roleName: data.name, permissions: JSON.stringify(data.permissions, null, '\t') });
318         this.filterRoleData(data.permissions);
319         this.isLoadingResults = false;
320         this.currentRoleName = data.name;
321         this.currentPermissions = JSON.stringify(data.permissions, null, '\t');
322       }, (error: ERRORDATA) => {
323         this.router.navigate(['/roles/details']).catch((): void => {
324           // Catch Navigation Error
325         });
326         this.restService.handleError(error, 'get');
327       });
328     }
329   }
330
331   /** Method to filter role data @private */
332   private filterRoleData(permissions: {}): void {
333     Object.keys(permissions).forEach((permission: string) => {
334       jsonpath.apply(this.rolePermissions, '$..permissions[?(@.operation == "' + permission + '")]', (response: Permission) => {
335         if (response.operation === permission) {
336           // eslint-disable-next-line security/detect-object-injection
337           response.value = permissions[permission];
338         }
339         return response;
340       });
341     });
342   }
343
344   /** Method to load the role permission Json file @private */
345   private async loadPermissions(): Promise<Object> {
346     const jsonFile: string = environment.PERMISSIONS_CONFIG_FILE + '?cb=' + new Date().getTime();
347     return new Promise<Object>((resolve: Function, reject: Function): void => {
348       this.httpClient.get(jsonFile).subscribe((response: Response) => {
349         resolve(response);
350       }, (error: {}) => {
351         reject();
352       });
353     });
354   }
355 }