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 { 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';
33 /** This is added globally by the tar.js library */
34 // tslint:disable-next-line: no-any
35 declare const Tar: any;
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
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<{}>();
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.,?'\\+&%$#=~_-]+))*$/);
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}$/);
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}))$/);
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}$/);
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}).*$/);
67 /** FormGroup instance added to the form @ html @public */
68 public formGroup: FormGroup;
70 /** Controls the go to top button on scroll @public */
71 public showGotoTop: boolean;
73 /** Holds OSM Version value @public */
74 public osmVersion: string;
76 /** express number for time manupulation -2 */
77 private epochTimeMinus2: number = -2;
79 /** express number for time manupulation 1000 */
80 private epochTime1000: number = 1000;
82 /** Random string generator length */
83 private randomStringLength: number = 4;
85 /** Instance of the rest service @private */
86 private restService: RestService;
88 /** Service holds the router information @private */
89 private router: Router;
91 /** Check for the root directory @private */
92 private directoryCount: number = 2;
94 constructor(restService: RestService, router: Router) {
95 this.restService = restService;
99 /** convert epoch time function @public */
100 public convertEpochTime(unixtimestamp: number): string {
101 const monthsArr: string[] = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
102 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
103 const date: Date = new Date(unixtimestamp * this.epochTime1000);
104 const year: number = date.getFullYear();
105 const month: string = monthsArr[date.getMonth()];
106 const day: number = date.getDate();
107 const hours: number = date.getHours();
108 const minutes: string = '0' + date.getMinutes();
109 const seconds: string = '0' + date.getSeconds();
110 return month + '-' + day + '-' + year + ' ' + hours + ':' + minutes.substr(this.epochTimeMinus2) + ':'
111 + seconds.substr(this.epochTimeMinus2);
114 /** Download Files function @public */
115 public downloadFiles(shortName: string, binaryData: Blob[], filetype: string): void {
116 const downloadLink: HTMLAnchorElement = document.createElement('a');
117 downloadLink.href = window.URL.createObjectURL(new Blob(binaryData, { type: filetype }));
118 if (shortName !== undefined) {
119 if (window.navigator.msSaveOrOpenBlob) {
120 window.navigator.msSaveBlob(new Blob(binaryData, { type: filetype }), 'OSM_Export_' + shortName + '.tar.gz');
122 downloadLink.setAttribute('download', 'OSM_Export_' + shortName + '.tar.gz');
123 document.body.appendChild(downloadLink);
124 downloadLink.click();
129 /** Call this method after delete perform action is completed in the ng-smart-table data @public */
130 public callData(): void {
131 this.dataEvent.emit();
134 /** Generate random string @public */
135 public randomString(): string {
136 const chars: string = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
137 let result: string = '';
138 // tslint:disable-next-line:no-increment-decrement
139 for (let randomStringRef: number = this.randomStringLength; randomStringRef > 0; --randomStringRef) {
140 result += chars[Math.floor(Math.random() * chars.length)];
144 /** Function to read uploaded file String @public */
145 public async getFileString(files: FileList, fileType: string): Promise<string | ArrayBuffer> {
146 const reader: FileReader = new FileReader();
147 return new Promise<string | ArrayBuffer>((resolve: Function, reject: Function): void => {
148 if (this.vaildataFileInfo(files[0], fileType)) {
149 this.readFileContent(reader, files[0], fileType);
153 reader.onload = (): void => {
154 if (reader.result === null) {
155 reject('contentError');
157 resolve(reader.result);
159 reader.onerror = (event: Event): void => {
160 reject('contentError');
164 /** Method to handle tar and tar.gz file for shared YAML file content @public */
165 public async targzFile(packageInfo: PACKAGEINFO): Promise<string | ArrayBuffer> {
166 return new Promise<string | ArrayBuffer>((resolve: Function, reject: Function): void => {
167 const httpOptions: GETAPIURLHEADER = this.getHttpOptions();
168 let apiUrl: string = '';
169 apiUrl = packageInfo.packageType === 'nsd' ? environment.NSDESCRIPTORS_URL + '/' + packageInfo.id + '/nsd_content' :
170 environment.VNFPACKAGES_URL + '/' + packageInfo.id + '/package_content';
171 this.restService.getResource(apiUrl, httpOptions).subscribe((response: ArrayBuffer) => {
173 // tslint:disable-next-line: no-any
174 const tar: any = new Tar();
175 const originalInput: Uint8Array = pako.inflate(response, { to: 'Uint8Array' });
176 untar(originalInput.buffer).then((extractedFiles: TARSETTINGS[]) => {
177 const getFoldersFiles: {}[] = extractedFiles;
178 const folderNameStr: string = extractedFiles[0].name;
179 getFoldersFiles.forEach((value: TARSETTINGS) => {
180 const getRootFolder: string[] = value.name.split('/');
181 if (value.name.startsWith(folderNameStr) &&
182 (value.name.endsWith('.yaml') || value.name.endsWith('.yml')) &&
183 getRootFolder.length === this.directoryCount) {
184 tar.append(value.name, packageInfo.descriptor, { type: value.type });
186 if (value.type !== 'L') {
187 tar.append(value.name, new Uint8Array(value.buffer), { type: value.type });
191 const out: Uint8Array = tar.out;
192 const originalOutput: Uint8Array = pako.gzip(out);
193 resolve(originalOutput.buffer);
194 }, (err: string) => {
200 }, (error: HttpErrorResponse) => {
201 if (error.status === HttpStatus.NOT_FOUND || error.status === HttpStatus.UNAUTHORIZED) {
202 this.router.navigateByUrl('404', { skipLocationChange: true }).catch();
204 this.restService.handleError(error, 'get');
210 /** Method to check given string is JSON or not @public */
211 public checkJson(jsonString: string): boolean {
212 jsonString = jsonString.replace(/'/g, '"');
214 JSON.parse(jsonString);
220 /** Clean the form before submit @public */
221 public cleanForm(formGroup: FormGroup): void {
222 Object.keys(formGroup.controls).forEach((key: string) => {
223 if ((!isNullOrUndefined((formGroup.get(key) as FormArray | FormGroup).controls)) && key !== 'vimconfig') {
224 // tslint:disable-next-line: no-shadowed-variable
225 for (const { item, index } of (formGroup.get(key).value).map((item: {}, index: number) => ({ item, index }))) {
226 const newFormGroup: FormGroup = (formGroup.get(key) as FormArray).controls[index] as FormGroup;
227 this.cleanForm(newFormGroup);
229 } else if (formGroup.get(key).value !== undefined && formGroup.get(key).value !== null && key !== 'vimconfig') {
230 if (!Array.isArray(formGroup.get(key).value)) {
231 if (typeof formGroup.get(key).value === 'string') {
232 formGroup.get(key).setValue(formGroup.get(key).value.trim());
235 } else if (key === 'vimconfig') {
236 const newFormGroup: FormGroup = formGroup.get(key) as FormGroup;
237 this.cleanForm(newFormGroup);
241 /** Method to return the config of pager value for ngSmarttable @public */
242 public paginationPagerConfig(): PAGERSMARTTABLE {
245 perPage: environment.paginationNumber
248 /** Method to return the class for the table for ngSmarttable @public */
249 public tableClassConfig(): SMARTTABLECLASS {
251 class: 'table list-data'
254 /** Method to return all languages name and its code @public */
255 public languageCodeList(): {}[] {
257 { code: 'en', language: 'English' },
258 { code: 'es', language: 'Spanish' },
259 { code: 'pt', language: 'Portuguese' },
260 { code: 'de', language: 'German' }
263 /** Fetch OSM Version @public */
264 public fetchOSMVersion(): void {
265 this.restService.getResource(environment.OSM_VERSION_URL).subscribe((res: { version: string }) => {
266 const version: string[] = res.version.split('+');
267 if (!isNullOrUndefined(version[0])) {
268 this.osmVersion = version[0];
270 this.osmVersion = null;
272 }, (error: ERRORDATA) => {
273 this.osmVersion = null;
274 this.restService.handleError(error, 'get');
277 /** Method to validate file extension and size @private */
278 private vaildataFileInfo(fileInfo: File, fileType: string): boolean {
279 const extension: string = fileInfo.name.substring(fileInfo.name.lastIndexOf('.') + 1);
280 const packageSize: number = CONSTANTNUMBER.oneMB * environment.packageSize;
281 if (extension.toLowerCase() === fileType && fileInfo.size <= packageSize) {
286 /** Method to read file content based on type @private */
287 private readFileContent(reader: FileReader, fileInfo: File, fileType: string): void {
288 if (fileType === 'gz') {
289 reader.readAsArrayBuffer(fileInfo);
291 reader.readAsText(fileInfo);
294 /** Method to handle http options @public */
295 private getHttpOptions(): GETAPIURLHEADER {
297 headers: new HttpHeaders({
298 Accept: 'application/gzip, application/json',
299 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
301 responseType: 'arraybuffer'