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 maxlength for the description @public */
82 public MAX_LENGTH_DESCRIPTION: number = 500;
84 /** Variables to hold maxlength for the name @public */
85 public MAX_LENGTH_NAME: number = 50;
87 /** FormGroup instance added to the form @ html @public */
88 public formGroup: FormGroup;
90 /** Controls the go to top button on scroll @public */
91 public showGotoTop: boolean;
93 /** Holds OSM Version value @public */
94 public osmVersion: string;
96 /** express number for time manupulation -2 */
97 private epochTimeMinus2: number = -2;
99 /** express number for time manupulation 1000 */
100 private epochTime1000: number = 1000;
102 /** Random string generator length */
103 private randomStringLength: number = 4;
105 /** Instance of the rest service @private */
106 private restService: RestService;
108 /** Service holds the router information @private */
109 private router: Router;
111 /** Random color string generator length @private */
112 private colorStringLength: number = 256;
114 /** Check for the root directory @private */
115 private directoryCount: number = 2;
117 /** Contains tranlsate instance @private */
118 private translateService: TranslateService;
120 constructor(restService: RestService, router: Router, translateService: TranslateService) {
121 this.restService = restService;
122 this.router = router;
123 this.translateService = translateService;
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);
141 return this.translateService.instant('NODATE');
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');
152 downloadLink.setAttribute('download', 'OSM_Export_' + name + '.tar.gz');
153 document.body.appendChild(downloadLink);
154 downloadLink.click();
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();
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)];
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);
184 reader.onload = (): void => {
185 if (reader.result === null) {
186 reject('contentError');
188 resolve(reader.result);
190 reader.onerror = (event: Event): void => {
191 reject('contentError');
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 => {
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);
219 if (value.type !== 'L') {
220 tar.append(value.name, new Uint8Array(value.buffer), fileValueObj);
224 const out: Uint8Array = tar.out;
225 const originalOutput: Uint8Array = pako.gzip(out);
226 resolve(originalOutput.buffer);
227 }, (err: string): void => {
233 }, (error: HttpErrorResponse): void => {
234 if (error.status === HttpStatus.NOT_FOUND || error.status === HttpStatus.UNAUTHORIZED) {
235 this.router.navigateByUrl('404', { skipLocationChange: true }).catch();
237 this.restService.handleError(error, 'get');
244 /** Method to return the file information @public */
245 public createFileValueObject(value: TARSETTINGS): FILESETTINGS {
248 linkname: value.linkname,
254 /** Method to check given string is JSON or not @public */
255 public checkJson(jsonString: string): boolean {
256 jsonString = jsonString.replace(/'/g, '"');
258 JSON.parse(jsonString);
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);
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());
280 } else if (key === 'config' && formName === 'vim') {
281 const newFormGroup: FormGroup = formGroup.get(key) as FormGroup;
282 this.cleanForm(newFormGroup);
287 /** Method to return the config of pager value for ngSmarttable @public */
288 public paginationPagerConfig(): PAGERSMARTTABLE {
291 perPage: environment.paginationNumber
295 /** Method to return the class for the table for ngSmarttable @public */
296 public tableClassConfig(): SMARTTABLECLASS {
298 class: 'table list-data'
302 /** Method to return all languages name and its code @public */
303 public languageCodeList(): {}[] {
305 { code: 'en', language: 'English' },
306 { code: 'es', language: 'Spanish' },
307 { code: 'pt', language: 'Portuguese' },
308 { code: 'de', language: 'German' }
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];
319 this.osmVersion = null;
321 }, (error: ERRORDATA): void => {
322 this.osmVersion = null;
323 this.restService.handleError(error, 'get');
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 + ')';
335 /** Add custom name/tag to the dropdown @public */
336 public addCustomTag(tag: string): string {
340 /** Fetch file extension @public */
341 public fetchFileExtension(fileInfo: FileList): string {
342 return fileInfo[0].name.substring(fileInfo[0].name.lastIndexOf('.') + 1);
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[] = [];
350 let domainNames: string[] = [];
351 if (!isNullOrUndefined(domains.project_domain_name)) {
352 domainNames = domainNames.concat(domains.project_domain_name.split(','));
354 if (!isNullOrUndefined(domains.user_domain_name)) {
355 domainNames = domainNames.concat(domains.user_domain_name.split(','));
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 });
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) {
379 } else if (extension.toLowerCase() === fileType && fileInfo.size <= packageSize) {
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);
390 reader.readAsText(fileInfo);
394 /** Method to handle http options @public */
395 private getHttpOptions(): GETAPIURLHEADER {
397 headers: new HttpHeaders({
398 Accept: 'application/gzip, application/json',
399 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
401 responseType: 'arraybuffer'