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 { 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';
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';
47 /** This is added globally by the tar.js library */
48 // tslint:disable-next-line: no-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 // 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.,?'\\+&%$#=~_-]+))*$/);
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}$/);
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}))$/);
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}$/);
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}).*$/);
81 /** Variables to hold regexp pattern for Latitude */
82 public REGX_LAT_PATTERN: RegExp = new RegExp(/^(\+|-)?(?:90(?:(?:\.0{1,6})?)|(?:[0-9]|[1-8][0-9])(?:(?:\.[0-9]{1,15})?))$/);
84 /** Variables to hold regexp pattern for Longitude */
85 // tslint:disable-next-line: max-line-length
86 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})?))$/);
88 /** Variables to hold maxlength for the description @public */
89 public MAX_LENGTH_DESCRIPTION: number = 500;
91 /** Variables to hold maxlength for the name @public */
92 public MAX_LENGTH_NAME: number = 50;
94 /** FormGroup instance added to the form @ html @public */
95 public formGroup: FormGroup;
97 /** Controls the go to top button on scroll @public */
98 public showGotoTop: boolean;
100 /** Holds OSM Version value @public */
101 public osmVersion: string;
103 /** express number for time manupulation -2 */
104 private epochTimeMinus2: number = -2;
106 /** express number for time manupulation 1000 */
107 private epochTime1000: number = 1000;
109 /** Random string generator length */
110 private randomStringLength: number = 4;
112 /** Instance of the rest service @private */
113 private restService: RestService;
115 /** Service holds the router information @private */
116 private router: Router;
118 /** Random color string generator length @private */
119 private colorStringLength: number = 256;
121 /** Check for the root directory @private */
122 private directoryCount: number = 2;
124 /** Contains tranlsate instance @private */
125 private translateService: TranslateService;
127 constructor(restService: RestService, router: Router, translateService: TranslateService) {
128 this.restService = restService;
129 this.router = router;
130 this.translateService = translateService;
133 /** convert epoch time function @public */
134 public convertEpochTime(unixtimestamp: number): string {
135 if (!isNullOrUndefined(unixtimestamp)) {
136 const monthsArr: string[] = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
137 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
138 const date: Date = new Date(unixtimestamp * this.epochTime1000);
139 const year: number = date.getFullYear();
140 const month: string = monthsArr[date.getMonth()];
141 const day: number = date.getDate();
142 const hours: number = date.getHours();
143 const minutes: string = '0' + date.getMinutes();
144 const seconds: string = '0' + date.getSeconds();
145 return month + '-' + day + '-' + year + ' ' + hours + ':' + minutes.substr(this.epochTimeMinus2) + ':'
146 + seconds.substr(this.epochTimeMinus2);
148 return this.translateService.instant('NODATE');
151 /** Download Files function @public */
152 public downloadFiles(name: string, binaryData: Blob[], filetype: string): void {
153 const downloadLink: HTMLAnchorElement = document.createElement('a');
154 downloadLink.href = window.URL.createObjectURL(new Blob(binaryData, { type: filetype }));
155 if (name !== undefined) {
156 if (window.navigator.msSaveOrOpenBlob) {
157 window.navigator.msSaveBlob(new Blob(binaryData, { type: filetype }), 'OSM_Export_' + name + '.tar.gz');
159 downloadLink.setAttribute('download', 'OSM_Export_' + name + '.tar.gz');
160 document.body.appendChild(downloadLink);
161 downloadLink.click();
166 /** Call this method after delete perform action is completed in the ng-smart-table data @public */
167 public callData(): void {
168 this.dataEvent.emit();
171 /** Generate random string @public */
172 public randomString(): string {
173 const chars: string = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
174 let result: string = '';
175 // tslint:disable-next-line:no-increment-decrement
176 for (let randomStringRef: number = this.randomStringLength; randomStringRef > 0; --randomStringRef) {
177 result += chars[Math.floor(Math.random() * chars.length)];
182 /** Function to read uploaded file String @public */
183 public async getFileString(files: FileList, fileType: string): Promise<string | ArrayBuffer> {
184 const reader: FileReader = new FileReader();
185 return new Promise<string | ArrayBuffer>((resolve: Function, reject: Function): void => {
186 if (this.vaildataFileInfo(files[0], fileType)) {
187 this.readFileContent(reader, files[0], fileType);
191 reader.onload = (): void => {
192 if (reader.result === null) {
193 reject('contentError');
195 resolve(reader.result);
197 reader.onerror = (event: Event): void => {
198 reject('contentError');
203 /** Method to handle tar and tar.gz file for shared YAML file content @public */
204 public async targzFile(packageInfo: PACKAGEINFO): Promise<string | ArrayBuffer> {
205 return new Promise<string | ArrayBuffer>((resolve: Function, reject: Function): void => {
206 const httpOptions: GETAPIURLHEADER = this.getHttpOptions();
207 let apiUrl: string = '';
208 apiUrl = packageInfo.packageType === 'nsd' ? environment.NSDESCRIPTORS_URL + '/' + packageInfo.id + '/nsd_content' :
209 environment.VNFPACKAGES_URL + '/' + packageInfo.id + '/package_content';
210 this.restService.getResource(apiUrl, httpOptions).subscribe((response: ArrayBuffer): void => {
212 // tslint:disable-next-line: no-any
213 const tar: any = new Tar();
214 const originalInput: Uint8Array = pako.inflate(response, { to: 'Uint8Array' });
215 untar(originalInput.buffer).then((extractedFiles: TARSETTINGS[]): void => {
216 const getFoldersFiles: {}[] = extractedFiles;
217 const folderNameStr: string = extractedFiles[0].name;
218 getFoldersFiles.forEach((value: TARSETTINGS): void => {
219 const fileValueObj: FILESETTINGS = this.createFileValueObject(value);
220 const getRootFolder: string[] = value.name.split('/');
221 if (value.name.startsWith(folderNameStr) &&
222 (value.name.endsWith('.yaml') || value.name.endsWith('.yml')) &&
223 getRootFolder.length === this.directoryCount) {
224 tar.append(value.name, packageInfo.descriptor, fileValueObj);
226 if (value.type !== 'L') {
227 tar.append(value.name, new Uint8Array(value.buffer), fileValueObj);
231 const out: Uint8Array = tar.out;
232 const originalOutput: Uint8Array = pako.gzip(out);
233 resolve(originalOutput.buffer);
234 }, (err: string): void => {
240 }, (error: HttpErrorResponse): void => {
241 if (error.status === HttpStatus.NOT_FOUND || error.status === HttpStatus.UNAUTHORIZED) {
242 this.router.navigateByUrl('404', { skipLocationChange: true }).catch();
244 this.restService.handleError(error, 'get');
251 /** Method to return the file information @public */
252 public createFileValueObject(value: TARSETTINGS): FILESETTINGS {
255 linkname: value.linkname,
261 /** Method to check given string is JSON or not @public */
262 public checkJson(jsonString: string): boolean {
263 jsonString = jsonString.replace(/'/g, '"');
265 JSON.parse(jsonString);
272 /** Clean the form before submit @public */
273 public cleanForm(formGroup: FormGroup, formName?: String): void {
274 Object.keys(formGroup.controls).forEach((key: string) => {
275 if ((!isNullOrUndefined((formGroup.get(key) as FormArray | FormGroup).controls)) && key !== 'config') {
276 // tslint:disable-next-line: no-shadowed-variable
277 for (const { item, index } of (formGroup.get(key).value).map((item: {}, index: number) => ({ item, index }))) {
278 const newFormGroup: FormGroup = (formGroup.get(key) as FormArray).controls[index] as FormGroup;
279 this.cleanForm(newFormGroup);
281 } else if (formGroup.get(key).value !== undefined && formGroup.get(key).value !== null && key !== 'config') {
282 if (!Array.isArray(formGroup.get(key).value)) {
283 if (typeof formGroup.get(key).value === 'string') {
284 formGroup.get(key).setValue(formGroup.get(key).value.trim());
287 } else if (key === 'config' && formName === 'vim') {
288 const newFormGroup: FormGroup = formGroup.get(key) as FormGroup;
289 this.cleanForm(newFormGroup);
294 /** Method to return the config of pager value for ngSmarttable @public */
295 public paginationPagerConfig(): PAGERSMARTTABLE {
298 perPage: environment.paginationNumber
302 /** Method to return the class for the table for ngSmarttable @public */
303 public tableClassConfig(): SMARTTABLECLASS {
305 class: 'table list-data'
309 /** Method to return all languages name and its code @public */
310 public languageCodeList(): {}[] {
312 { code: 'en', language: 'English' },
313 { code: 'es', language: 'Spanish' },
314 { code: 'pt', language: 'Portuguese' },
315 { code: 'de', language: 'German' }
319 /** Fetch OSM Version @public */
320 public fetchOSMVersion(): void {
321 this.restService.getResource(environment.OSM_VERSION_URL).subscribe((res: { version: string }): void => {
322 const version: string[] = res.version.split('+');
323 if (!isNullOrUndefined(version[0])) {
324 this.osmVersion = version[0];
326 this.osmVersion = null;
328 }, (error: ERRORDATA): void => {
329 this.osmVersion = null;
330 this.restService.handleError(error, 'get');
334 /** Random RGB color code generator @public */
335 public generateColor(): string {
336 const x: number = Math.floor(Math.random() * this.colorStringLength);
337 const y: number = Math.floor(Math.random() * this.colorStringLength);
338 const z: number = Math.floor(Math.random() * this.colorStringLength);
339 return 'rgb(' + x + ',' + y + ',' + z + ')';
342 /** Add custom name/tag to the dropdown @public */
343 public addCustomTag(tag: string): string {
347 /** Fetch file extension @public */
348 public fetchFileExtension(fileInfo: FileList): string {
349 return fileInfo[0].name.substring(fileInfo[0].name.lastIndexOf('.') + 1);
352 /** Get domain name @private */
353 public getDomainName(): Observable<TYPESECTION[]> {
354 return this.restService.getResource(environment.DOMAIN_URL).pipe(map((domains: DOMAINS): TYPESECTION[] => {
355 const domainList: TYPESECTION[] = [];
357 let domainNames: string[] = [];
358 if (!isNullOrUndefined(domains.project_domain_name)) {
359 domainNames = domainNames.concat(domains.project_domain_name.split(','));
361 if (!isNullOrUndefined(domains.user_domain_name)) {
362 domainNames = domainNames.concat(domains.user_domain_name.split(','));
364 domainNames = Array.from(new Set(domainNames));
365 if (domainNames.length > 0) {
366 domainNames.forEach((domainName: string): void => {
367 if (!domainName.endsWith(':ro')) {
368 domainList.push({ title: domainName, value: domainName });
379 /** Method to validate file extension and size @private */
380 private vaildataFileInfo(fileInfo: File, fileType: string): boolean {
381 const extension: string = fileInfo.name.substring(fileInfo.name.lastIndexOf('.') + 1);
382 const packageSize: number = CONSTANTNUMBER.oneMB * environment.packageSize;
383 if (fileType === 'yaml' && (extension.toLowerCase() === 'yaml' || extension.toLowerCase() === 'yml')
384 && fileInfo.size <= packageSize) {
386 } else if (extension.toLowerCase() === fileType && fileInfo.size <= packageSize) {
392 /** Method to read file content based on type @private */
393 private readFileContent(reader: FileReader, fileInfo: File, fileType: string): void {
394 if (fileType === 'gz') {
395 reader.readAsArrayBuffer(fileInfo);
397 reader.readAsText(fileInfo);
401 /** Method to handle http options @public */
402 private getHttpOptions(): GETAPIURLHEADER {
404 headers: new HttpHeaders({
405 Accept: 'application/gzip, application/json',
406 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
408 responseType: 'arraybuffer'