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