| /* |
| Copyright 2020 TATA ELXSI |
| |
| Licensed under the Apache License, Version 2.0 (the 'License'); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| |
| Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) |
| */ |
| /** |
| * @file Provider for Shared Service |
| */ |
| import { HttpErrorResponse, HttpHeaders } from '@angular/common/http'; |
| import { EventEmitter, Injectable, Output } from '@angular/core'; |
| import { FormArray, FormGroup } from '@angular/forms'; |
| import { Router } from '@angular/router'; |
| import { TranslateService } from '@ngx-translate/core'; |
| import { |
| CONSTANTNUMBER, |
| DOMAINS, |
| ERRORDATA, |
| FILESETTINGS, |
| GETAPIURLHEADER, |
| PACKAGEINFO, |
| PAGERSMARTTABLE, |
| SMARTTABLECLASS, |
| TARSETTINGS, |
| TYPESECTION |
| } from 'CommonModel'; |
| import { environment } from 'environment'; |
| import * as HttpStatus from 'http-status-codes'; |
| import * as untar from 'js-untar'; |
| import { ActiveToast, ToastrService } from 'ngx-toastr'; |
| import * as pako from 'pako'; |
| import { RestService } from 'RestService'; |
| import { Observable } from 'rxjs'; |
| import { map } from 'rxjs/operators'; |
| |
| /** This is added globally by the tar.js library */ |
| // eslint-disable-next-line @typescript-eslint/no-explicit-any |
| declare const Tar: any; |
| |
| /** |
| * An Injectable is a class adorned with the @Injectable decorator function. |
| * @Injectable takes a metadata object that tells Angular how to compile and run module code |
| */ |
| @Injectable({ |
| providedIn: 'root' |
| }) |
| /** Exporting a class @exports SharedService */ |
| export class SharedService { |
| /** call the parent using event information @private */ |
| @Output() public dataEvent: EventEmitter<{}> = new EventEmitter<{}>(); |
| |
| /** Variables to hold regexp pattern for URL */ |
| 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.,?'\\+&%$#=~_-]+))*$/); |
| |
| /** Variables to hold regexp pattern for IP Address */ |
| public REGX_IP_PATTERN: RegExp = new RegExp(/^(?:(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(?!$)|$)){4}$/); |
| |
| /** Variables to hold regexp pattern for Port Number */ |
| 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}))$/); |
| |
| /** Variables to hold regexp pattern for DPID */ |
| public REGX_DPID_PATTERN: RegExp = new RegExp(/^[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){7}$/); |
| |
| /** Variable to hold regexp pattern for password */ |
| public REGX_PASSWORD_PATTERN: RegExp = new RegExp(/^.*(?=.{8,})((?=.*[!@#$%^&*()\-_=+{};:,<.>]){1})(?=.*\d)((?=.*[a-z]){1})((?=.*[A-Z]){1}).*$/); |
| |
| /** Variables to hold regexp pattern for Latitude */ |
| public REGX_LAT_PATTERN: RegExp = new RegExp(/^(\+|-)?(?:90(?:(?:\.0{1,6})?)|(?:[0-9]|[1-8][0-9])(?:(?:\.[0-9]{1,15})?))$/); |
| |
| /** Variables to hold regexp pattern for Longitude */ |
| 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})?))$/); |
| |
| /** Variables to hold maxlength for the description @public */ |
| // eslint-disable-next-line @typescript-eslint/no-magic-numbers |
| public MAX_LENGTH_DESCRIPTION: number = 500; |
| |
| /** Variables to hold maxlength for the name @public */ |
| // eslint-disable-next-line @typescript-eslint/no-magic-numbers |
| public MAX_LENGTH_NAME: number = 50; |
| |
| /** FormGroup instance added to the form @ html @public */ |
| public formGroup: FormGroup; |
| |
| /** Controls the go to top button on scroll @public */ |
| public showGotoTop: boolean; |
| |
| /** Holds OSM Version value @public */ |
| public osmVersion: string; |
| |
| /** Holds Last Login Toaster Message @public */ |
| public lastLoginMessage: string; |
| |
| /** Holds Failed Attempts Toaster Message @public */ |
| public failedAttemptsMessage: string; |
| |
| /** Holds No Of Days Toaster Message @public */ |
| public daysMessage: string; |
| |
| /** express number for time manupulation -2 */ |
| // eslint-disable-next-line @typescript-eslint/no-magic-numbers |
| private epochTimeMinus2: number = -2; |
| |
| /** express number for time manupulation 1000 */ |
| // eslint-disable-next-line @typescript-eslint/no-magic-numbers |
| private epochTime1000: number = 1000; |
| |
| /** express number for time manupulation 60 */ |
| // eslint-disable-next-line @typescript-eslint/no-magic-numbers |
| private epochTime60: number = 60; |
| |
| /** express number for time manupulation 24 */ |
| // eslint-disable-next-line @typescript-eslint/no-magic-numbers |
| private epochTime24: number = 24; |
| |
| /** Random string generator length */ |
| // eslint-disable-next-line @typescript-eslint/no-magic-numbers |
| private randomStringLength: number = 4; |
| |
| /** express number for rgb manipulation */ |
| // eslint-disable-next-line @typescript-eslint/no-magic-numbers |
| private colourHour: number = 10; |
| |
| /** express number for rgb manipulation*/ |
| // eslint-disable-next-line @typescript-eslint/no-magic-numbers |
| private colourMin: number = 5; |
| |
| /** Instance of the rest service @private */ |
| private restService: RestService; |
| |
| /** Service holds the router information @private */ |
| private router: Router; |
| |
| /** Check for the root directory @private */ |
| // eslint-disable-next-line @typescript-eslint/no-magic-numbers |
| private directoryCount: number = 2; |
| |
| /** express number for time manupulation 1000 */ |
| private toasterSettings: {} = { |
| enableHtml: true, |
| closeButton: true, |
| timeOut: 2000 |
| }; |
| |
| /** Contains tranlsate instance @private */ |
| private translateService: TranslateService; |
| |
| /** Contains toaster instance @private */ |
| private toaster: ToastrService; |
| |
| constructor(restService: RestService, router: Router, translateService: TranslateService, toaster: ToastrService) { |
| this.restService = restService; |
| this.router = router; |
| this.translateService = translateService; |
| this.toaster = toaster; |
| } |
| |
| /** convert epoch time function @public */ |
| public convertEpochTime(unixtimestamp: number): string { |
| if (!isNullOrUndefined(unixtimestamp)) { |
| const monthsArr: string[] = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', |
| 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; |
| const date: Date = new Date(unixtimestamp * this.epochTime1000); |
| const year: number = date.getFullYear(); |
| const month: string = monthsArr[date.getMonth()]; |
| const day: number = date.getDate(); |
| const hours: number = date.getHours(); |
| const minutes: string = '0' + date.getMinutes(); |
| const seconds: string = '0' + date.getSeconds(); |
| // eslint-disable-next-line deprecation/deprecation |
| return month + '-' + day + '-' + year + ' ' + hours + ':' + minutes.substr(this.epochTimeMinus2) + ':' |
| // eslint-disable-next-line deprecation/deprecation |
| + seconds.substr(this.epochTimeMinus2); |
| } |
| return this.translateService.instant('NODATE'); |
| } |
| |
| /** convert epoch time function to No of days @public */ |
| public converEpochToDays(date: string): number { |
| if (!isNullOrUndefined(date)) { |
| const today: Date = new Date(); |
| const accountDate: Date = new Date(date); |
| const toasterDate: number = (accountDate.getTime() - |
| today.getTime()) / this.epochTime1000 / this.epochTime60 / this.epochTime60 / this.epochTime24; |
| if (toasterDate >= 0 || toasterDate < 1) { |
| return Math.round(toasterDate); |
| } |
| return Math.floor(toasterDate); |
| } |
| return this.translateService.instant('N/A'); |
| } |
| |
| /** show toaster for password & account expiry @public */ |
| public showToaster(lastLogin: string, failedAttempts: string, passwordNoOfDays: string, |
| accountNoOfDays: string, passwordExpireMessage: string, accountExpireMessage: string, |
| passwordMessage: string, accountMessage: string): ActiveToast<string> { |
| this.lastLoginMessage = this.translateService.instant('PAGE.LOGIN.LASTACCESS'); |
| this.failedAttemptsMessage = this.translateService.instant('PAGE.LOGIN.FAILED'); |
| return this.toaster.info(this.lastLoginMessage + ':' + ' ' + lastLogin + |
| '</br>' + this.failedAttemptsMessage + ':' + ' ' + failedAttempts + |
| '</br>' + passwordExpireMessage + ' ' + passwordNoOfDays + ' ' + passwordMessage + |
| '</br>' + accountExpireMessage + ' ' + accountNoOfDays + ' ' + accountMessage, |
| this.translateService.instant('PAGE.LOGIN.LOGINHISTORY'), this.toasterSettings); |
| } |
| |
| /** show toaster for password expiry @public */ |
| public passwordToaster(lastLogin: string, failedAttempts: string, passwordNoOfDays: string, |
| passwordExpireMessage: string, passwordMessage: string): ActiveToast<string> { |
| this.lastLoginMessage = this.translateService.instant('PAGE.LOGIN.LASTACCESS'); |
| this.failedAttemptsMessage = this.translateService.instant('PAGE.LOGIN.FAILED'); |
| return this.toaster.info(this.lastLoginMessage + ':' + ' ' + lastLogin + |
| '</br>' + this.failedAttemptsMessage + ':' + ' ' + failedAttempts + |
| '</br>' + passwordExpireMessage + ' ' + passwordNoOfDays + ' ' + passwordMessage, |
| this.translateService.instant('PAGE.LOGIN.LOGINHISTORY'), this.toasterSettings); |
| } |
| |
| /** show toaster for account expiry @public */ |
| public accountToaster(lastLogin: string, failedAttempts: string, |
| accountNoOfDays: string, accountExpireMessage: string, accountMessage: string): ActiveToast<string> { |
| this.lastLoginMessage = this.translateService.instant('PAGE.LOGIN.LASTACCESS'); |
| this.failedAttemptsMessage = this.translateService.instant('PAGE.LOGIN.FAILED'); |
| return this.toaster.info(this.lastLoginMessage + ':' + ' ' + lastLogin + |
| '</br>' + this.failedAttemptsMessage + ':' + ' ' + failedAttempts + |
| '</br>' + accountExpireMessage + ' ' + accountNoOfDays + ' ' + accountMessage, |
| this.translateService.instant('PAGE.LOGIN.LOGINHISTORY'), this.toasterSettings); |
| } |
| |
| /** Download Files function @public */ |
| public downloadFiles(name: string, binaryData: Blob[], filetype: string): void { |
| const downloadLink: HTMLAnchorElement = document.createElement('a'); |
| downloadLink.href = window.URL.createObjectURL(new Blob(binaryData, { type: filetype })); |
| if (name !== undefined) { |
| // eslint-disable-next-line @typescript-eslint/no-explicit-any |
| const newVariable: any = window.navigator; |
| if (newVariable.msSaveOrOpenBlob) { |
| newVariable.msSaveBlob(new Blob(binaryData, { type: filetype }), 'OSM_Export_' + name + '.tar.gz'); |
| } else { |
| downloadLink.setAttribute('download', 'OSM_Export_' + name + '.tar.gz'); |
| document.body.appendChild(downloadLink); |
| downloadLink.click(); |
| } |
| } |
| } |
| |
| /** Call this method after delete perform action is completed in the ng-smart-table data @public */ |
| public callData(): void { |
| this.dataEvent.emit(); |
| } |
| |
| /** Generate random string @public */ |
| public randomString(): string { |
| let result: string = ''; |
| for (let randomStringRef: number = this.randomStringLength; randomStringRef > 0; --randomStringRef) { |
| result += new Date().getSeconds(); |
| } |
| return result; |
| } |
| |
| /** Function to read uploaded file String @public */ |
| public async getFileString(files: FileList, fileType: string): Promise<string | ArrayBuffer> { |
| const reader: FileReader = new FileReader(); |
| return new Promise<string | ArrayBuffer>((resolve: Function, reject: Function): void => { |
| if (this.vaildataFileInfo(files[0], fileType)) { |
| this.readFileContent(reader, files[0], fileType); |
| } else { |
| reject('typeError'); |
| } |
| reader.onload = (): void => { |
| if (reader.result === null) { |
| reject('contentError'); |
| } |
| resolve(reader.result); |
| }; |
| reader.onerror = (event: Event): void => { |
| reject('contentError'); |
| }; |
| }); |
| } |
| |
| /** Method to handle tar and tar.gz file for shared YAML file content @public */ |
| public async targzFile(packageInfo: PACKAGEINFO): Promise<string | ArrayBuffer> { |
| return new Promise<string | ArrayBuffer>((resolve: Function, reject: Function): void => { |
| const httpOptions: GETAPIURLHEADER = this.getHttpOptions(); |
| let apiUrl: string = ''; |
| apiUrl = packageInfo.packageType === 'nsd' ? environment.NSDESCRIPTORS_URL + '/' + packageInfo.id + '/nsd_content' : |
| environment.VNFPACKAGES_URL + '/' + packageInfo.id + '/package_content'; |
| this.restService.getResource(apiUrl, httpOptions).subscribe((response: ArrayBuffer): void => { |
| try { |
| // eslint-disable-next-line @typescript-eslint/no-explicit-any |
| const tar: any = new Tar(); |
| const originalInput: Uint8Array = pako.inflate(response, { to: 'Uint8Array' }); |
| untar(originalInput.buffer).then((extractedFiles: TARSETTINGS[]): void => { |
| const getFoldersFiles: {}[] = extractedFiles; |
| const folderNameStr: string = extractedFiles[0].name; |
| getFoldersFiles.forEach((value: TARSETTINGS): void => { |
| const fileValueObj: FILESETTINGS = this.createFileValueObject(value); |
| const getRootFolder: string[] = value.name.split('/'); |
| if (value.name.startsWith(folderNameStr) && |
| (value.name.endsWith('.yaml') || value.name.endsWith('.yml')) && |
| getRootFolder.length === this.directoryCount) { |
| tar.append(value.name, packageInfo.descriptor, fileValueObj); |
| } else { |
| if (value.type !== 'L') { |
| tar.append(value.name, new Uint8Array(value.buffer), fileValueObj); |
| } |
| } |
| }); |
| const out: Uint8Array = tar.out; |
| const originalOutput: Uint8Array = pako.gzip(out); |
| resolve(originalOutput.buffer); |
| }, (err: string): void => { |
| reject(''); |
| }); |
| } catch (e) { |
| reject(''); |
| } |
| }, (error: HttpErrorResponse): void => { |
| if (error.status === HttpStatus.NOT_FOUND || error.status === HttpStatus.UNAUTHORIZED) { |
| this.router.navigateByUrl('404', { skipLocationChange: true }).catch((): void => { |
| // Catch Navigation Error |
| }); |
| } else { |
| this.restService.handleError(error, 'get'); |
| reject(''); |
| } |
| }); |
| }); |
| } |
| |
| /** Method to return the file information @public */ |
| public createFileValueObject(value: TARSETTINGS): FILESETTINGS { |
| return { |
| type: value.type, |
| linkname: value.linkname, |
| owner: value.uname, |
| group: value.gname |
| }; |
| } |
| |
| /** Method to check given string is JSON or not @public */ |
| public checkJson(jsonString: string): boolean { |
| jsonString = jsonString.replace(/'/g, '"'); |
| try { |
| JSON.parse(jsonString); |
| } catch (e) { |
| return false; |
| } |
| return true; |
| } |
| |
| /** Clean the form before submit @public */ |
| public cleanForm(formGroup: FormGroup, formName?: String): void { |
| Object.keys(formGroup.controls).forEach((key: string) => { |
| if ((!isNullOrUndefined((formGroup.get(key) as FormArray | FormGroup).controls)) && key !== 'config') { |
| // eslint-disable-next-line @typescript-eslint/no-shadow |
| for (const { item, index } of (formGroup.get(key).value).map((item: {}, index: number) => ({ item, index }))) { |
| // eslint-disable-next-line security/detect-object-injection |
| const newFormGroup: FormGroup = (formGroup.get(key) as FormArray).controls[index] as FormGroup; |
| this.cleanForm(newFormGroup); |
| } |
| } else if (formGroup.get(key).value !== undefined && formGroup.get(key).value !== null && key !== 'config') { |
| if (!Array.isArray(formGroup.get(key).value)) { |
| if (typeof formGroup.get(key).value === 'string') { |
| formGroup.get(key).setValue(formGroup.get(key).value.trim()); |
| } |
| } |
| } else if (key === 'config' && formName === 'vim') { |
| const newFormGroup: FormGroup = formGroup.get(key) as FormGroup; |
| this.cleanForm(newFormGroup); |
| } |
| }); |
| } |
| |
| /** Method to return the config of pager value for ngSmarttable @public */ |
| public paginationPagerConfig(): PAGERSMARTTABLE { |
| return { |
| display: true, |
| perPage: environment.paginationNumber |
| }; |
| } |
| |
| /** Method to return the class for the table for ngSmarttable @public */ |
| public tableClassConfig(): SMARTTABLECLASS { |
| return { |
| class: 'table list-data' |
| }; |
| } |
| |
| /** Method to return all languages name and its code @public */ |
| public languageCodeList(): {}[] { |
| return [ |
| { code: 'en', language: 'English' }, |
| { code: 'es', language: 'Spanish' }, |
| { code: 'pt', language: 'Portuguese' }, |
| { code: 'de', language: 'German' } |
| ]; |
| } |
| |
| /** Fetch OSM Version @public */ |
| public fetchOSMVersion(): void { |
| this.restService.getResource(environment.OSM_VERSION_URL).subscribe((res: { version: string }): void => { |
| const version: string[] = res.version.split('+'); |
| if (!isNullOrUndefined(version[0])) { |
| this.osmVersion = version[0]; |
| sessionStorage.setItem('version', version[0]); |
| } else { |
| this.osmVersion = null; |
| } |
| }, (error: ERRORDATA): void => { |
| this.osmVersion = null; |
| this.restService.handleError(error, 'get'); |
| }); |
| } |
| |
| /** Random RGB color code generator @public */ |
| public generateColor(): string { |
| const x: number = Math.floor((new Date().getHours()) * this.colourHour); |
| const y: number = Math.floor((new Date().getMinutes()) * this.colourMin); |
| const z: number = Math.floor((new Date().getSeconds()) * this.colourMin); |
| return 'rgb(' + x + ',' + y + ',' + z + ')'; |
| } |
| |
| /** Add custom name/tag to the dropdown @public */ |
| public addCustomTag(tag: string): string { |
| return tag; |
| } |
| |
| /** Fetch file extension @public */ |
| public fetchFileExtension(fileInfo: FileList): string { |
| return fileInfo[0].name.substring(fileInfo[0].name.lastIndexOf('.') + 1); |
| } |
| |
| /** Get domain name @private */ |
| public getDomainName(): Observable<TYPESECTION[]> { |
| return this.restService.getResource(environment.DOMAIN_URL).pipe(map((domains: DOMAINS): TYPESECTION[] => { |
| const domainList: TYPESECTION[] = []; |
| try { |
| let domainNames: string[] = []; |
| if (!isNullOrUndefined(domains.project_domain_name)) { |
| domainNames = domainNames.concat(domains.project_domain_name.split(',')); |
| } |
| if (!isNullOrUndefined(domains.user_domain_name)) { |
| domainNames = domainNames.concat(domains.user_domain_name.split(',')); |
| } |
| domainNames = Array.from(new Set(domainNames)); |
| if (domainNames.length > 0) { |
| domainNames.forEach((domainName: string): void => { |
| if (!domainName.endsWith(':ro')) { |
| domainList.push({ title: domainName, value: domainName }); |
| } |
| }); |
| } |
| return domainList; |
| } catch (e) { |
| return domainList; |
| } |
| })); |
| } |
| |
| /** Sorting the list based on date @public */ |
| public compareFunction = (dir: number, a: string, b: string): number => { |
| const first: number = new Date(a).getTime(); |
| const second: number = new Date(b).getTime(); |
| if (first < second) { |
| return -1 * dir; |
| } |
| if (first > second) { |
| return dir; |
| } |
| return 0; |
| }; |
| |
| /** Method to validate file extension and size @private */ |
| private vaildataFileInfo(fileInfo: File, fileType: string): boolean { |
| const extension: string = fileInfo.name.substring(fileInfo.name.lastIndexOf('.') + 1); |
| const packageSize: number = CONSTANTNUMBER.oneMB * environment.packageSize; |
| if (fileType === 'yaml' && (extension.toLowerCase() === 'yaml' || extension.toLowerCase() === 'yml') |
| && fileInfo.size <= packageSize) { |
| return true; |
| } else if (extension.toLowerCase() === fileType && fileInfo.size <= packageSize) { |
| return true; |
| } |
| return false; |
| } |
| |
| /** Method to read file content based on type @private */ |
| private readFileContent(reader: FileReader, fileInfo: File, fileType: string): void { |
| if (fileType === 'gz') { |
| reader.readAsArrayBuffer(fileInfo); |
| } else { |
| reader.readAsText(fileInfo); |
| } |
| } |
| |
| /** Method to handle http options @public */ |
| private getHttpOptions(): GETAPIURLHEADER { |
| return { |
| headers: new HttpHeaders({ |
| Accept: 'application/gzip, application/json', |
| 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' |
| }), |
| responseType: 'arraybuffer' |
| }; |
| } |
| } |
| |
| /** Method to handle null or undefined @public */ |
| // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types |
| export const isNullOrUndefined = (data: any): boolean => data === null || data === undefined; |
| |