2 Copyright 2020 TATA ELXSI
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
8 http://www.apache.org/licenses/LICENSE-2.0
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.
16 Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
19 * @file Provider for Shared Service
21 import { isNullOrUndefined } from 'util';
22 import { HttpErrorResponse, HttpHeaders } from '@angular/common/http';
23 import { EventEmitter, Injectable, Output } from '@angular/core';
24 import { FormArray, FormGroup } from '@angular/forms';
25 import { Router } from '@angular/router';
26 import { TranslateService } from '@ngx-translate/core';
39 import { environment } from 'environment';
40 import * as HttpStatus from 'http-status-codes';
41 import * as untar from 'js-untar';
42 import * as pako from 'pako';
43 import { RestService } from 'RestService';
44 import { Observable } from 'rxjs';
45 import { map } from 'rxjs/operators';
47 /** This is added globally by the tar.js library */
48 // eslint-disable-next-line @typescript-eslint/no-explicit-any
49 declare const Tar: any;
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
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<{}>();
63 /** Variables to hold regexp pattern for URL */
64 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 /** Variables to hold regexp pattern for IP Address */
67 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 /** Variables to hold regexp pattern for Port Number */
70 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}))$/);
72 /** Variables to hold regexp pattern for DPID */
73 public REGX_DPID_PATTERN: RegExp = new RegExp(/^[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){7}$/);
75 /** Variable to hold regexp pattern for password */
76 public REGX_PASSWORD_PATTERN: RegExp = new RegExp(/^.*(?=.{8,})((?=.*[!@#$%^&*()\-_=+{};:,<.>]){1})(?=.*\d)((?=.*[a-z]){1})((?=.*[A-Z]){1}).*$/);
78 /** Variables to hold regexp pattern for Latitude */
79 public REGX_LAT_PATTERN: RegExp = new RegExp(/^(\+|-)?(?:90(?:(?:\.0{1,6})?)|(?:[0-9]|[1-8][0-9])(?:(?:\.[0-9]{1,15})?))$/);
81 /** Variables to hold regexp pattern for Longitude */
82 public REGX_LONG_PATTERN: RegExp = new RegExp(/^(\+|-)?(?:180(?:(?:\.0{1,6})?)|(?:[0-9]|[1-9][0-9]|1[0-7][0-9])(?:(?:\.[0-9]{1,15})?))$/);
84 /** Variables to hold maxlength for the description @public */
85 // eslint-disable-next-line @typescript-eslint/no-magic-numbers
86 public MAX_LENGTH_DESCRIPTION: number = 500;
88 /** Variables to hold maxlength for the name @public */
89 // eslint-disable-next-line @typescript-eslint/no-magic-numbers
90 public MAX_LENGTH_NAME: number = 50;
92 /** FormGroup instance added to the form @ html @public */
93 public formGroup: FormGroup;
95 /** Controls the go to top button on scroll @public */
96 public showGotoTop: boolean;
98 /** Holds OSM Version value @public */
99 public osmVersion: string;
101 /** express number for time manupulation -2 */
102 // eslint-disable-next-line @typescript-eslint/no-magic-numbers
103 private epochTimeMinus2: number = -2;
105 /** express number for time manupulation 1000 */
106 // eslint-disable-next-line @typescript-eslint/no-magic-numbers
107 private epochTime1000: number = 1000;
109 /** Random string generator length */
110 // eslint-disable-next-line @typescript-eslint/no-magic-numbers
111 private randomStringLength: number = 4;
113 /** Instance of the rest service @private */
114 private restService: RestService;
116 /** Service holds the router information @private */
117 private router: Router;
119 /** Random color string generator length @private */
120 // eslint-disable-next-line @typescript-eslint/no-magic-numbers
121 private colorStringLength: number = 256;
123 /** Check for the root directory @private */
124 // eslint-disable-next-line @typescript-eslint/no-magic-numbers
125 private directoryCount: number = 2;
127 /** Contains tranlsate instance @private */
128 private translateService: TranslateService;
130 constructor(restService: RestService, router: Router, translateService: TranslateService) {
131 this.restService = restService;
132 this.router = router;
133 this.translateService = translateService;
136 /** convert epoch time function @public */
137 public convertEpochTime(unixtimestamp: number): string {
138 if (!isNullOrUndefined(unixtimestamp)) {
139 const monthsArr: string[] = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
140 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
141 const date: Date = new Date(unixtimestamp * this.epochTime1000);
142 const year: number = date.getFullYear();
143 const month: string = monthsArr[date.getMonth()];
144 const day: number = date.getDate();
145 const hours: number = date.getHours();
146 const minutes: string = '0' + date.getMinutes();
147 const seconds: string = '0' + date.getSeconds();
148 // eslint-disable-next-line deprecation/deprecation
149 return month + '-' + day + '-' + year + ' ' + hours + ':' + minutes.substr(this.epochTimeMinus2) + ':'
150 // eslint-disable-next-line deprecation/deprecation
151 + seconds.substr(this.epochTimeMinus2);
153 return this.translateService.instant('NODATE');
156 /** Download Files function @public */
157 public downloadFiles(name: string, binaryData: Blob[], filetype: string): void {
158 const downloadLink: HTMLAnchorElement = document.createElement('a');
159 downloadLink.href = window.URL.createObjectURL(new Blob(binaryData, { type: filetype }));
160 if (name !== undefined) {
161 // eslint-disable-next-line @typescript-eslint/no-explicit-any
162 const newVariable: any = window.navigator;
163 if (newVariable.msSaveOrOpenBlob) {
164 newVariable.msSaveBlob(new Blob(binaryData, { type: filetype }), 'OSM_Export_' + name + '.tar.gz');
166 downloadLink.setAttribute('download', 'OSM_Export_' + name + '.tar.gz');
167 document.body.appendChild(downloadLink);
168 downloadLink.click();
173 /** Call this method after delete perform action is completed in the ng-smart-table data @public */
174 public callData(): void {
175 this.dataEvent.emit();
178 /** Generate random string @public */
179 public randomString(): string {
180 const chars: string = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
181 let result: string = '';
182 for (let randomStringRef: number = this.randomStringLength; randomStringRef > 0; --randomStringRef) {
183 result += chars[Math.floor(Math.random() * chars.length)];
188 /** Function to read uploaded file String @public */
189 public async getFileString(files: FileList, fileType: string): Promise<string | ArrayBuffer> {
190 const reader: FileReader = new FileReader();
191 return new Promise<string | ArrayBuffer>((resolve: Function, reject: Function): void => {
192 if (this.vaildataFileInfo(files[0], fileType)) {
193 this.readFileContent(reader, files[0], fileType);
197 reader.onload = (): void => {
198 if (reader.result === null) {
199 reject('contentError');
201 resolve(reader.result);
203 reader.onerror = (event: Event): void => {
204 reject('contentError');
209 /** Method to handle tar and tar.gz file for shared YAML file content @public */
210 public async targzFile(packageInfo: PACKAGEINFO): Promise<string | ArrayBuffer> {
211 return new Promise<string | ArrayBuffer>((resolve: Function, reject: Function): void => {
212 const httpOptions: GETAPIURLHEADER = this.getHttpOptions();
213 let apiUrl: string = '';
214 apiUrl = packageInfo.packageType === 'nsd' ? environment.NSDESCRIPTORS_URL + '/' + packageInfo.id + '/nsd_content' :
215 environment.VNFPACKAGES_URL + '/' + packageInfo.id + '/package_content';
216 this.restService.getResource(apiUrl, httpOptions).subscribe((response: ArrayBuffer): void => {
218 // eslint-disable-next-line @typescript-eslint/no-explicit-any
219 const tar: any = new Tar();
220 const originalInput: Uint8Array = pako.inflate(response, { to: 'Uint8Array' });
221 untar(originalInput.buffer).then((extractedFiles: TARSETTINGS[]): void => {
222 const getFoldersFiles: {}[] = extractedFiles;
223 const folderNameStr: string = extractedFiles[0].name;
224 getFoldersFiles.forEach((value: TARSETTINGS): void => {
225 const fileValueObj: FILESETTINGS = this.createFileValueObject(value);
226 const getRootFolder: string[] = value.name.split('/');
227 if (value.name.startsWith(folderNameStr) &&
228 (value.name.endsWith('.yaml') || value.name.endsWith('.yml')) &&
229 getRootFolder.length === this.directoryCount) {
230 tar.append(value.name, packageInfo.descriptor, fileValueObj);
232 if (value.type !== 'L') {
233 tar.append(value.name, new Uint8Array(value.buffer), fileValueObj);
237 const out: Uint8Array = tar.out;
238 const originalOutput: Uint8Array = pako.gzip(out);
239 resolve(originalOutput.buffer);
240 }, (err: string): void => {
246 }, (error: HttpErrorResponse): void => {
247 if (error.status === HttpStatus.NOT_FOUND || error.status === HttpStatus.UNAUTHORIZED) {
248 this.router.navigateByUrl('404', { skipLocationChange: true }).catch((): void => {
249 // Catch Navigation Error
252 this.restService.handleError(error, 'get');
259 /** Method to return the file information @public */
260 public createFileValueObject(value: TARSETTINGS): FILESETTINGS {
263 linkname: value.linkname,
269 /** Method to check given string is JSON or not @public */
270 public checkJson(jsonString: string): boolean {
271 jsonString = jsonString.replace(/'/g, '"');
273 JSON.parse(jsonString);
280 /** Clean the form before submit @public */
281 public cleanForm(formGroup: FormGroup, formName?: String): void {
282 Object.keys(formGroup.controls).forEach((key: string) => {
283 if ((!isNullOrUndefined((formGroup.get(key) as FormArray | FormGroup).controls)) && key !== 'config') {
284 // eslint-disable-next-line @typescript-eslint/no-shadow
285 for (const { item, index } of (formGroup.get(key).value).map((item: {}, index: number) => ({ item, index }))) {
286 // eslint-disable-next-line security/detect-object-injection
287 const newFormGroup: FormGroup = (formGroup.get(key) as FormArray).controls[index] as FormGroup;
288 this.cleanForm(newFormGroup);
290 } else if (formGroup.get(key).value !== undefined && formGroup.get(key).value !== null && key !== 'config') {
291 if (!Array.isArray(formGroup.get(key).value)) {
292 if (typeof formGroup.get(key).value === 'string') {
293 formGroup.get(key).setValue(formGroup.get(key).value.trim());
296 } else if (key === 'config' && formName === 'vim') {
297 const newFormGroup: FormGroup = formGroup.get(key) as FormGroup;
298 this.cleanForm(newFormGroup);
303 /** Method to return the config of pager value for ngSmarttable @public */
304 public paginationPagerConfig(): PAGERSMARTTABLE {
307 perPage: environment.paginationNumber
311 /** Method to return the class for the table for ngSmarttable @public */
312 public tableClassConfig(): SMARTTABLECLASS {
314 class: 'table list-data'
318 /** Method to return all languages name and its code @public */
319 public languageCodeList(): {}[] {
321 { code: 'en', language: 'English' },
322 { code: 'es', language: 'Spanish' },
323 { code: 'pt', language: 'Portuguese' },
324 { code: 'de', language: 'German' }
328 /** Fetch OSM Version @public */
329 public fetchOSMVersion(): void {
330 this.restService.getResource(environment.OSM_VERSION_URL).subscribe((res: { version: string }): void => {
331 const version: string[] = res.version.split('+');
332 if (!isNullOrUndefined(version[0])) {
333 this.osmVersion = version[0];
335 this.osmVersion = null;
337 }, (error: ERRORDATA): void => {
338 this.osmVersion = null;
339 this.restService.handleError(error, 'get');
343 /** Random RGB color code generator @public */
344 public generateColor(): string {
345 const x: number = Math.floor(Math.random() * this.colorStringLength);
346 const y: number = Math.floor(Math.random() * this.colorStringLength);
347 const z: number = Math.floor(Math.random() * this.colorStringLength);
348 return 'rgb(' + x + ',' + y + ',' + z + ')';
351 /** Add custom name/tag to the dropdown @public */
352 public addCustomTag(tag: string): string {
356 /** Fetch file extension @public */
357 public fetchFileExtension(fileInfo: FileList): string {
358 return fileInfo[0].name.substring(fileInfo[0].name.lastIndexOf('.') + 1);
361 /** Get domain name @private */
362 public getDomainName(): Observable<TYPESECTION[]> {
363 return this.restService.getResource(environment.DOMAIN_URL).pipe(map((domains: DOMAINS): TYPESECTION[] => {
364 const domainList: TYPESECTION[] = [];
366 let domainNames: string[] = [];
367 if (!isNullOrUndefined(domains.project_domain_name)) {
368 domainNames = domainNames.concat(domains.project_domain_name.split(','));
370 if (!isNullOrUndefined(domains.user_domain_name)) {
371 domainNames = domainNames.concat(domains.user_domain_name.split(','));
373 domainNames = Array.from(new Set(domainNames));
374 if (domainNames.length > 0) {
375 domainNames.forEach((domainName: string): void => {
376 if (!domainName.endsWith(':ro')) {
377 domainList.push({ title: domainName, value: domainName });
388 /** Method to validate file extension and size @private */
389 private vaildataFileInfo(fileInfo: File, fileType: string): boolean {
390 const extension: string = fileInfo.name.substring(fileInfo.name.lastIndexOf('.') + 1);
391 const packageSize: number = CONSTANTNUMBER.oneMB * environment.packageSize;
392 if (fileType === 'yaml' && (extension.toLowerCase() === 'yaml' || extension.toLowerCase() === 'yml')
393 && fileInfo.size <= packageSize) {
395 } else if (extension.toLowerCase() === fileType && fileInfo.size <= packageSize) {
401 /** Method to read file content based on type @private */
402 private readFileContent(reader: FileReader, fileInfo: File, fileType: string): void {
403 if (fileType === 'gz') {
404 reader.readAsArrayBuffer(fileInfo);
406 reader.readAsText(fileInfo);
410 /** Method to handle http options @public */
411 private getHttpOptions(): GETAPIURLHEADER {
413 headers: new HttpHeaders({
414 Accept: 'application/gzip, application/json',
415 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
417 responseType: 'arraybuffer'