Bug 1413 Domains don't appear in create project/user dropdown using Keystone and...
[osm/NG-UI.git] / src / services / SharedService.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 Provider for Shared Service
20  */
21 import { HttpErrorResponse, HttpHeaders } from '@angular/common/http';
22 import { EventEmitter, Injectable, Output } from '@angular/core';
23 import { FormArray, FormGroup } from '@angular/forms';
24 import { Router } from '@angular/router';
25 import { TranslateService } from '@ngx-translate/core';
26 import {
27     CONSTANTNUMBER,
28     DOMAINS,
29     ERRORDATA,
30     FILESETTINGS,
31     GETAPIURLHEADER,
32     PACKAGEINFO,
33     PAGERSMARTTABLE,
34     SMARTTABLECLASS,
35     TARSETTINGS,
36     TYPESECTION
37 } from 'CommonModel';
38 import { environment } from 'environment';
39 import * as HttpStatus from 'http-status-codes';
40 import * as untar from 'js-untar';
41 import * as pako from 'pako';
42 import { RestService } from 'RestService';
43 import { Observable } from 'rxjs';
44 import { map } from 'rxjs/operators';
45 import { isNullOrUndefined } from 'util';
46
47 /** This is added globally by the tar.js library */
48 // tslint:disable-next-line: no-any
49 declare const Tar: any;
50
51 /**
52  * An Injectable is a class adorned with the @Injectable decorator function.
53  * @Injectable takes a metadata object that tells Angular how to compile and run module code
54  */
55 @Injectable({
56     providedIn: 'root'
57 })
58 /** Exporting a class @exports SharedService */
59 export class SharedService {
60     /** call the parent using event information @private */
61     @Output() public dataEvent: EventEmitter<{}> = new EventEmitter<{}>();
62
63     /** Variables to hold regexp pattern for URL */
64     // tslint:disable-next-line: max-line-length
65     public REGX_URL_PATTERN: RegExp = new RegExp(/^(http?|ftp|https):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.[a-zA-Z0-9]{2,15})(:((6553[0-5])|(655[0-2][0-9])|(65[0-4][0-9]{2})|(6[0-4][0-9]{3})|([1-5][0-9]{4})|([0-5]{0,5})|([0-9]{1,4})))*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/);
66
67     /** Variables to hold regexp pattern for IP Address */
68     public REGX_IP_PATTERN: RegExp = new RegExp(/^(?:(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(?!$)|$)){4}$/);
69
70     /** Variables to hold regexp pattern for Port Number */
71     // tslint:disable-next-line: max-line-length
72     public REGX_PORT_PATTERN: RegExp = new RegExp(/^((6553[0-5])|(655[0-2][0-9])|(65[0-4][0-9]{2})|(6[0-4][0-9]{3})|([1-5][0-9]{4})|([0-5]{0,5})|([0-9]{1,4}))$/);
73
74     /** Variables to hold regexp pattern for DPID */
75     public REGX_DPID_PATTERN: RegExp = new RegExp(/^[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){7}$/);
76
77     /** Variable to hold regexp pattern for password */
78     // tslint:disable-next-line: max-line-length
79     public REGX_PASSWORD_PATTERN: RegExp = new RegExp(/^.*(?=.{8,})((?=.*[!@#$%^&*()\-_=+{};:,<.>]){1})(?=.*\d)((?=.*[a-z]){1})((?=.*[A-Z]){1}).*$/);
80
81     /** Variables to hold maxlength for the description @public */
82     public MAX_LENGTH_DESCRIPTION: number = 500;
83
84     /** Variables to hold maxlength for the name @public */
85     public MAX_LENGTH_NAME: number = 50;
86
87     /** FormGroup instance added to the form @ html @public */
88     public formGroup: FormGroup;
89
90     /** Controls the go to top button on scroll  @public */
91     public showGotoTop: boolean;
92
93     /** Holds OSM Version value @public */
94     public osmVersion: string;
95
96     /** express number for time manupulation -2 */
97     private epochTimeMinus2: number = -2;
98
99     /** express number for time manupulation 1000 */
100     private epochTime1000: number = 1000;
101
102     /** Random string generator length */
103     private randomStringLength: number = 4;
104
105     /** Instance of the rest service @private */
106     private restService: RestService;
107
108     /** Service holds the router information @private */
109     private router: Router;
110
111     /** Random color string generator length @private */
112     private colorStringLength: number = 256;
113
114     /** Check for the root directory @private */
115     private directoryCount: number = 2;
116
117     /** Contains tranlsate instance @private */
118     private translateService: TranslateService;
119
120     constructor(restService: RestService, router: Router, translateService: TranslateService) {
121         this.restService = restService;
122         this.router = router;
123         this.translateService = translateService;
124     }
125
126     /** convert epoch time function @public */
127     public convertEpochTime(unixtimestamp: number): string {
128         if (!isNullOrUndefined(unixtimestamp)) {
129             const monthsArr: string[] = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
130                 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
131             const date: Date = new Date(unixtimestamp * this.epochTime1000);
132             const year: number = date.getFullYear();
133             const month: string = monthsArr[date.getMonth()];
134             const day: number = date.getDate();
135             const hours: number = date.getHours();
136             const minutes: string = '0' + date.getMinutes();
137             const seconds: string = '0' + date.getSeconds();
138             return month + '-' + day + '-' + year + ' ' + hours + ':' + minutes.substr(this.epochTimeMinus2) + ':'
139                 + seconds.substr(this.epochTimeMinus2);
140         }
141         return this.translateService.instant('NODATE');
142     }
143
144     /** Download Files function @public */
145     public downloadFiles(name: string, binaryData: Blob[], filetype: string): void {
146         const downloadLink: HTMLAnchorElement = document.createElement('a');
147         downloadLink.href = window.URL.createObjectURL(new Blob(binaryData, { type: filetype }));
148         if (name !== undefined) {
149             if (window.navigator.msSaveOrOpenBlob) {
150                 window.navigator.msSaveBlob(new Blob(binaryData, { type: filetype }), 'OSM_Export_' + name + '.tar.gz');
151             } else {
152                 downloadLink.setAttribute('download', 'OSM_Export_' + name + '.tar.gz');
153                 document.body.appendChild(downloadLink);
154                 downloadLink.click();
155             }
156         }
157     }
158
159     /** Call this method after delete perform action is completed in the ng-smart-table data @public */
160     public callData(): void {
161         this.dataEvent.emit();
162     }
163
164     /** Generate random string @public */
165     public randomString(): string {
166         const chars: string = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
167         let result: string = '';
168         // tslint:disable-next-line:no-increment-decrement
169         for (let randomStringRef: number = this.randomStringLength; randomStringRef > 0; --randomStringRef) {
170             result += chars[Math.floor(Math.random() * chars.length)];
171         }
172         return result;
173     }
174
175     /** Function to read uploaded file String @public */
176     public async getFileString(files: FileList, fileType: string): Promise<string | ArrayBuffer> {
177         const reader: FileReader = new FileReader();
178         return new Promise<string | ArrayBuffer>((resolve: Function, reject: Function): void => {
179             if (this.vaildataFileInfo(files[0], fileType)) {
180                 this.readFileContent(reader, files[0], fileType);
181             } else {
182                 reject('typeError');
183             }
184             reader.onload = (): void => {
185                 if (reader.result === null) {
186                     reject('contentError');
187                 }
188                 resolve(reader.result);
189             };
190             reader.onerror = (event: Event): void => {
191                 reject('contentError');
192             };
193         });
194     }
195
196     /** Method to handle tar and tar.gz file for shared YAML file content @public */
197     public async targzFile(packageInfo: PACKAGEINFO): Promise<string | ArrayBuffer> {
198         return new Promise<string | ArrayBuffer>((resolve: Function, reject: Function): void => {
199             const httpOptions: GETAPIURLHEADER = this.getHttpOptions();
200             let apiUrl: string = '';
201             apiUrl = packageInfo.packageType === 'nsd' ? environment.NSDESCRIPTORS_URL + '/' + packageInfo.id + '/nsd_content' :
202                 environment.VNFPACKAGES_URL + '/' + packageInfo.id + '/package_content';
203             this.restService.getResource(apiUrl, httpOptions).subscribe((response: ArrayBuffer): void => {
204                 try {
205                     // tslint:disable-next-line: no-any
206                     const tar: any = new Tar();
207                     const originalInput: Uint8Array = pako.inflate(response, { to: 'Uint8Array' });
208                     untar(originalInput.buffer).then((extractedFiles: TARSETTINGS[]): void => {
209                         const getFoldersFiles: {}[] = extractedFiles;
210                         const folderNameStr: string = extractedFiles[0].name;
211                         getFoldersFiles.forEach((value: TARSETTINGS): void => {
212                             const fileValueObj: FILESETTINGS = this.createFileValueObject(value);
213                             const getRootFolder: string[] = value.name.split('/');
214                             if (value.name.startsWith(folderNameStr) &&
215                                 (value.name.endsWith('.yaml') || value.name.endsWith('.yml')) &&
216                                 getRootFolder.length === this.directoryCount) {
217                                 tar.append(value.name, packageInfo.descriptor, fileValueObj);
218                             } else {
219                                 if (value.type !== 'L') {
220                                     tar.append(value.name, new Uint8Array(value.buffer), fileValueObj);
221                                 }
222                             }
223                         });
224                         const out: Uint8Array = tar.out;
225                         const originalOutput: Uint8Array = pako.gzip(out);
226                         resolve(originalOutput.buffer);
227                     }, (err: string): void => {
228                         reject('');
229                     });
230                 } catch (e) {
231                     reject('');
232                 }
233             }, (error: HttpErrorResponse): void => {
234                 if (error.status === HttpStatus.NOT_FOUND || error.status === HttpStatus.UNAUTHORIZED) {
235                     this.router.navigateByUrl('404', { skipLocationChange: true }).catch();
236                 } else {
237                     this.restService.handleError(error, 'get');
238                     reject('');
239                 }
240             });
241         });
242     }
243
244     /** Method to return the file information @public */
245     public createFileValueObject(value: TARSETTINGS): FILESETTINGS {
246         return {
247             type: value.type,
248             linkname: value.linkname,
249             owner: value.uname,
250             group: value.gname
251         };
252     }
253
254     /** Method to check given string is JSON or not @public */
255     public checkJson(jsonString: string): boolean {
256         jsonString = jsonString.replace(/'/g, '"');
257         try {
258             JSON.parse(jsonString);
259         } catch (e) {
260             return false;
261         }
262         return true;
263     }
264
265     /** Clean the form before submit @public */
266     public cleanForm(formGroup: FormGroup, formName?: String): void {
267         Object.keys(formGroup.controls).forEach((key: string) => {
268             if ((!isNullOrUndefined((formGroup.get(key) as FormArray | FormGroup).controls)) && key !== 'config') {
269                 // tslint:disable-next-line: no-shadowed-variable
270                 for (const { item, index } of (formGroup.get(key).value).map((item: {}, index: number) => ({ item, index }))) {
271                     const newFormGroup: FormGroup = (formGroup.get(key) as FormArray).controls[index] as FormGroup;
272                     this.cleanForm(newFormGroup);
273                 }
274             } else if (formGroup.get(key).value !== undefined && formGroup.get(key).value !== null && key !== 'config') {
275                 if (!Array.isArray(formGroup.get(key).value)) {
276                     if (typeof formGroup.get(key).value === 'string') {
277                         formGroup.get(key).setValue(formGroup.get(key).value.trim());
278                     }
279                 }
280             } else if (key === 'config' && formName === 'vim') {
281                 const newFormGroup: FormGroup = formGroup.get(key) as FormGroup;
282                 this.cleanForm(newFormGroup);
283             }
284         });
285     }
286
287     /** Method to return the config of pager value for ngSmarttable @public */
288     public paginationPagerConfig(): PAGERSMARTTABLE {
289         return {
290             display: true,
291             perPage: environment.paginationNumber
292         };
293     }
294
295     /** Method to return the class for the table for ngSmarttable @public */
296     public tableClassConfig(): SMARTTABLECLASS {
297         return {
298             class: 'table list-data'
299         };
300     }
301
302     /** Method to return all languages name and its code @public */
303     public languageCodeList(): {}[] {
304         return [
305             { code: 'en', language: 'English' },
306             { code: 'es', language: 'Spanish' },
307             { code: 'pt', language: 'Portuguese' },
308             { code: 'de', language: 'German' }
309         ];
310     }
311
312     /** Fetch OSM Version @public */
313     public fetchOSMVersion(): void {
314         this.restService.getResource(environment.OSM_VERSION_URL).subscribe((res: { version: string }): void => {
315             const version: string[] = res.version.split('+');
316             if (!isNullOrUndefined(version[0])) {
317                 this.osmVersion = version[0];
318             } else {
319                 this.osmVersion = null;
320             }
321         }, (error: ERRORDATA): void => {
322             this.osmVersion = null;
323             this.restService.handleError(error, 'get');
324         });
325     }
326
327     /** Random RGB color code generator @public */
328     public generateColor(): string {
329         const x: number = Math.floor(Math.random() * this.colorStringLength);
330         const y: number = Math.floor(Math.random() * this.colorStringLength);
331         const z: number = Math.floor(Math.random() * this.colorStringLength);
332         return 'rgb(' + x + ',' + y + ',' + z + ')';
333     }
334
335     /** Add custom name/tag to the dropdown @public */
336     public addCustomTag(tag: string): string {
337         return tag;
338     }
339
340     /** Fetch file extension @public */
341     public fetchFileExtension(fileInfo: FileList): string {
342         return fileInfo[0].name.substring(fileInfo[0].name.lastIndexOf('.') + 1);
343     }
344
345     /** Get domain name @private */
346     public getDomainName(): Observable<TYPESECTION[]> {
347         return this.restService.getResource(environment.DOMAIN_URL).pipe(map((domains: DOMAINS): TYPESECTION[] => {
348             const domainList: TYPESECTION[] = [];
349             try {
350                 let domainNames: string[] = [];
351                 if (!isNullOrUndefined(domains.project_domain_name)) {
352                     domainNames = domainNames.concat(domains.project_domain_name.split(','));
353                 }
354                 if (!isNullOrUndefined(domains.user_domain_name)) {
355                     domainNames = domainNames.concat(domains.user_domain_name.split(','));
356                 }
357                 domainNames = Array.from(new Set(domainNames));
358                 if (domainNames.length > 0) {
359                     domainNames.forEach((domainName: string): void => {
360                         if (!domainName.endsWith(':ro')) {
361                             domainList.push({ title: domainName, value: domainName });
362                         }
363                     });
364                 }
365                 return domainList;
366             } catch (e) {
367                 return domainList;
368             }
369         }));
370     }
371
372     /** Method to validate file extension and size @private */
373     private vaildataFileInfo(fileInfo: File, fileType: string): boolean {
374         const extension: string = fileInfo.name.substring(fileInfo.name.lastIndexOf('.') + 1);
375         const packageSize: number = CONSTANTNUMBER.oneMB * environment.packageSize;
376         if (fileType === 'yaml' && (extension.toLowerCase() === 'yaml' || extension.toLowerCase() === 'yml')
377             && fileInfo.size <= packageSize) {
378             return true;
379         } else if (extension.toLowerCase() === fileType && fileInfo.size <= packageSize) {
380             return true;
381         }
382         return false;
383     }
384
385     /** Method to read file content based on type @private */
386     private readFileContent(reader: FileReader, fileInfo: File, fileType: string): void {
387         if (fileType === 'gz') {
388             reader.readAsArrayBuffer(fileInfo);
389         } else {
390             reader.readAsText(fileInfo);
391         }
392     }
393
394     /** Method to handle http options @public */
395     private getHttpOptions(): GETAPIURLHEADER {
396         return {
397             headers: new HttpHeaders({
398                 Accept: 'application/gzip, application/json',
399                 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
400             }),
401             responseType: 'arraybuffer'
402         };
403     }
404 }