Initiate angular project with firebase and base components

This commit is contained in:
Mathieu Sanchez 2019-05-21 11:29:32 +09:00
parent fb83703c54
commit aa073c1b77
20 changed files with 639 additions and 62 deletions

134
package-lock.json generated
View File

@ -1356,7 +1356,6 @@
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
"dev": true,
"optional": true,
"requires": {
"delegates": "^1.0.0",
"readable-stream": "^2.0.6"
@ -2575,8 +2574,7 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
"dev": true,
"optional": true
"dev": true
},
"constants-browserify": {
"version": "1.0.0",
@ -2971,8 +2969,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
"dev": true,
"optional": true
"dev": true
},
"depd": {
"version": "1.1.2",
@ -3290,6 +3287,14 @@
"is-arrayish": "^0.2.1"
}
},
"error-stack-parser": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.2.tgz",
"integrity": "sha512-E1fPutRDdIj/hohG0UpT5mayXNCxXP9d+snxFsPU9X0XgccOumKraa3juDMwTUyi7+Bu5+mCGagjg4IYeNbOdw==",
"requires": {
"stackframe": "^1.0.4"
}
},
"es6-promise": {
"version": "4.2.6",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.6.tgz",
@ -3935,8 +3940,7 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"aproba": {
"version": "1.2.0",
@ -3957,14 +3961,12 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -3979,20 +3981,17 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"core-util-is": {
"version": "1.0.2",
@ -4109,8 +4108,7 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"ini": {
"version": "1.3.5",
@ -4122,7 +4120,6 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -4137,7 +4134,6 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@ -4145,14 +4141,12 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"minipass": {
"version": "2.3.5",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@ -4171,7 +4165,6 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -4252,8 +4245,7 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"object-assign": {
"version": "4.1.1",
@ -4265,7 +4257,6 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@ -4351,8 +4342,7 @@
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"safer-buffer": {
"version": "2.1.2",
@ -4388,7 +4378,6 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -4408,7 +4397,6 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -4452,14 +4440,12 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"yallist": {
"version": "3.0.3",
"bundled": true,
"dev": true,
"optional": true
"dev": true
}
}
},
@ -4468,7 +4454,6 @@
"resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
"integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
"dev": true,
"optional": true,
"requires": {
"graceful-fs": "^4.1.2",
"inherits": "~2.0.0",
@ -4481,7 +4466,6 @@
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
"dev": true,
"optional": true,
"requires": {
"aproba": "^1.0.3",
"console-control-strings": "^1.0.0",
@ -4519,8 +4503,7 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
"integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
"dev": true,
"optional": true
"dev": true
},
"get-stream": {
"version": "3.0.0",
@ -5155,8 +5138,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
"dev": true,
"optional": true
"dev": true
},
"has-value": {
"version": "1.0.0",
@ -5874,8 +5856,7 @@
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
"integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
"dev": true,
"optional": true
"dev": true
},
"is-windows": {
"version": "1.0.2",
@ -6231,6 +6212,11 @@
"dev": true,
"optional": true
},
"js-sha512": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/js-sha512/-/js-sha512-0.8.0.tgz",
"integrity": "sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ=="
},
"js-tokens": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
@ -6511,7 +6497,6 @@
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
"dev": true,
"optional": true,
"requires": {
"graceful-fs": "^4.1.2",
"parse-json": "^2.2.0",
@ -6524,8 +6509,7 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true,
"optional": true
"dev": true
}
}
},
@ -6801,8 +6785,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
"integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
"dev": true,
"optional": true
"dev": true
},
"map-visit": {
"version": "1.0.0",
@ -7079,6 +7062,11 @@
}
}
},
"moment": {
"version": "2.24.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
},
"move-concurrently": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
@ -7427,7 +7415,6 @@
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"dev": true,
"optional": true,
"requires": {
"are-we-there-yet": "~1.1.2",
"console-control-strings": "~1.1.0",
@ -8471,7 +8458,6 @@
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
"integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
"dev": true,
"optional": true,
"requires": {
"load-json-file": "^1.0.0",
"normalize-package-data": "^2.3.2",
@ -8483,7 +8469,6 @@
"resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
"integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
"dev": true,
"optional": true,
"requires": {
"graceful-fs": "^4.1.2",
"pify": "^2.0.0",
@ -8494,8 +8479,7 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true,
"optional": true
"dev": true
}
}
},
@ -8504,7 +8488,6 @@
"resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
"integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
"dev": true,
"optional": true,
"requires": {
"find-up": "^1.0.0",
"read-pkg": "^1.0.0"
@ -8515,7 +8498,6 @@
"resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
"integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
"dev": true,
"optional": true,
"requires": {
"path-exists": "^2.0.0",
"pinkie-promise": "^2.0.0"
@ -8526,7 +8508,6 @@
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
"integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
"dev": true,
"optional": true,
"requires": {
"pinkie-promise": "^2.0.0"
}
@ -9669,6 +9650,45 @@
"safe-buffer": "^5.1.1"
}
},
"stack-generator": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/stack-generator/-/stack-generator-2.0.3.tgz",
"integrity": "sha512-kdzGoqrnqsMxOEuXsXyQTmvWXZmG0f3Ql2GDx5NtmZs59sT2Bt9Vdyq0XdtxUi58q/+nxtbF9KOQ9HkV1QznGg==",
"requires": {
"stackframe": "^1.0.4"
}
},
"stackframe": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.0.4.tgz",
"integrity": "sha512-to7oADIniaYwS3MhtCa/sQhrxidCCQiF/qp4/m5iN3ipf0Y7Xlri0f6eG29r08aL7JYl8n32AF3Q5GYBZ7K8vw=="
},
"stacktrace-gps": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/stacktrace-gps/-/stacktrace-gps-3.0.2.tgz",
"integrity": "sha512-9o+nWhiz5wFnrB3hBHs2PTyYrS60M1vvpSzHxwxnIbtY2q9Nt51hZvhrG1+2AxD374ecwyS+IUwfkHRE/2zuGg==",
"requires": {
"source-map": "0.5.6",
"stackframe": "^1.0.4"
},
"dependencies": {
"source-map": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz",
"integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI="
}
}
},
"stacktrace-js": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/stacktrace-js/-/stacktrace-js-2.0.0.tgz",
"integrity": "sha1-d2ymRqlbxsayuQd2U2p/xyxt21g=",
"requires": {
"error-stack-parser": "^2.0.1",
"stack-generator": "^2.0.1",
"stacktrace-gps": "^3.0.1"
}
},
"static-extend": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
@ -9816,7 +9836,6 @@
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
"integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
"dev": true,
"optional": true,
"requires": {
"is-utf8": "^0.2.0"
}
@ -11156,7 +11175,6 @@
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
"dev": true,
"optional": true,
"requires": {
"string-width": "^1.0.2 || 2"
}

View File

@ -28,7 +28,10 @@
"hammerjs": "^2.0.8",
"rxjs": "~6.3.3",
"tslib": "^1.9.0",
"zone.js": "~0.8.26"
"zone.js": "~0.8.26",
"js-sha512": "latest",
"moment": "latest",
"stacktrace-js": "latest"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.13.0",

View File

@ -1,5 +1,5 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ErrorHandler, NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@ -7,6 +7,8 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AngularFireModule } from '@angular/fire';
import { AngularFireDatabaseModule } from '@angular/fire/database';
import { environment } from '@env/environment';
import { GlobalErrorHandler } from '@app/core/global-error-handler/global-error-handler.service';
import { LogService } from '@app/core/services';
@NgModule({
declarations: [
@ -18,7 +20,13 @@ import { environment } from '@env/environment';
AngularFireModule.initializeApp(environment.firebaseConfig),
AngularFireDatabaseModule,
],
providers: [],
providers: [
LogService,
{
provide: ErrorHandler,
useClass: GlobalErrorHandler
},
],
bootstrap: [ AppComponent ]
})
export class AppModule {

View File

@ -0,0 +1,16 @@
/* tslint:disable:no-unused-variable */
import { inject, TestBed } from '@angular/core/testing';
import { GlobalErrorHandler } from './global-error-handler.service';
describe( 'Service: GlobalErrorHandler', () => {
beforeEach( () => {
TestBed.configureTestingModule( {
providers: [ GlobalErrorHandler ]
} );
} );
it( 'should ...', inject( [ GlobalErrorHandler ], ( service: GlobalErrorHandler ) => {
expect( service ).toBeTruthy();
} ) );
} );

View File

@ -0,0 +1,35 @@
import { ErrorHandler, Injectable, Injector } from '@angular/core';
import * as StackTrace from 'stacktrace-js';
import { LogService } from '@app/core/services';
@Injectable()
export class GlobalErrorHandler extends ErrorHandler {
constructor( private injector: Injector ) {
super();
}
public handleError( error ) {
const logService: LogService = this.injector.get( LogService );
const message = error.message ? error.message : error.toString();
if ( error.status ) {
error = new Error( message );
}
StackTrace.fromError( error ).then( ( stackframes ) => {
const stackString = stackframes
.splice( 0, 10 )
.map( ( sf ) => {
return sf.toString();
} )
.toString();
const errorTraceStr = `Error message: ${ message }. Stack trace: ${ stackString }`;
logService.logError( errorTraceStr );
throw error;
} );
}
}

View File

@ -0,0 +1,2 @@
export * from './storage/storage';
export * from './user/user';

View File

@ -0,0 +1,5 @@
export class Storage {
pageData: object;
sessionData: object;
localData: object;
}

View File

@ -0,0 +1,36 @@
export class User {
timeGetToken: number;
token: string;
dataUser: DataUser;
}
export class DataUser {
firstName: string;
lastName: string;
address: string;
postalCode: string;
city: string;
country: string;
phoneNumber: string;
email: string;
birthday: number;
licenseNumber: string;
licenseValidity: number;
licenseCategories: string[];
constructor() {
this.firstName = null;
this.lastName = null;
this.address = null;
this.postalCode = null;
this.city = null;
this.country = null;
this.phoneNumber = null;
this.email = null;
this.birthday = null;
this.licenseNumber = null;
this.licenseValidity = null;
this.licenseCategories = null;
}
}

View File

@ -0,0 +1,12 @@
import { TestBed } from '@angular/core/testing';
import { AuthService } from './auth.service';
describe( 'AuthService', () => {
beforeEach( () => TestBed.configureTestingModule( {} ) );
it( 'should be created', () => {
const service: AuthService = TestBed.get( AuthService );
expect( service ).toBeTruthy();
} );
} );

View File

@ -0,0 +1,90 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';
import { Router } from '@angular/router';
import * as sha512 from 'js-sha512';
// import * as config from '@assets/config.json';
import { User } from '@app/core/model';
import { StorageService } from '@app/core/services/storage/storage.service';
import { LogService } from '@app/core/services/log/log.service';
@Injectable( { providedIn: 'root' } )
export class AuthService {
public currentUser: Observable<User>;
// public emailRegex = new RegExp( );
private currentUserSubject: BehaviorSubject<User>;
constructor( private http: HttpClient, private router: Router, private stor: StorageService, private looger: LogService ) {
this.currentUserSubject = new BehaviorSubject<User>( stor.getLocal( 'user' ) as User );
this.currentUser = this.currentUserSubject.asObservable();
}
public get currentUserValue(): User {
if ( this.currentUserSubject.value && this.currentUserSubject.value.timeGetToken + 60 * 60 * 1000 < new Date().getTime() ) {
const data = new FormData();
data.append( 'auth_token', this.currentUserSubject.value.token );
// this.http.post<any>( environment.baseUrl + config.url.upauth, data ).subscribe( ( res ) => {
// if ( res.statusCode !== 200 ) {
// this.logout();
// } else {
// this.currentUserSubject.value.timeGetToken = new Date().getTime();
// this.stor.setLocal( 'user', this.currentUserSubject.value );
// }
// } );
}
return this.currentUserSubject.value;
}
public login( username: string, password: string ): any {
const data: FormData = new FormData();
data.append( 'email', username );
data.append( 'password', sha512.sha512( password ) );
// return this.http.post<any>( environment.baseUrl + config.url.auth, data )
// .pipe( map( result => {
// let user = new User();
//
// this.looger.logInfo( result );
// // login successful if there's a jwt token in the response
// if ( result && result.body && result.statusCode === 200 ) {
//
// user.token = result.body;
// user.timeGetToken = new Date().getTime();
//
// // store user details and jwt token in local storage to keep user logged in between page refreshes
// this.stor.setLocal( 'user', user );
// this.currentUserSubject.next( user );
// } else {
// user = result.statusCode;
// }
//
// return user;
// } ) );
}
public logout(): void {
// remove user from local storage to log user out
this.stor.setLocal( 'user' );
this.currentUserSubject.next( null );
this.router.navigate( [ '/login' ] );
}
public createAccount( email: string, password: string, repeat: string ): any {
// const data: FormData = new FormData();
// if ( password === repeat && this.emailRegex.test( email ) ) {
// data.append( 'email', email );
// data.append( 'password', sha512.sha512( password ) );
// return this.http.post( environment.baseUrl + config.url.register, data );
// }
return null;
}
}

View File

@ -0,0 +1,2 @@
export * from './auth/auth.service';
export * from './log/log.service';

View File

@ -0,0 +1,8 @@
export interface LogFields {
userId?: string;
elapsedTime?: number;
requestPath?: string;
environment?: string;
appVersion?: string;
url?: string;
}

View File

@ -0,0 +1,20 @@
/* tslint:disable:no-unused-variable */
import { inject, TestBed } from '@angular/core/testing';
import { LogService } from './log.service';
describe( 'Service: Log', () => {
beforeEach( () => {
TestBed.configureTestingModule( {
imports: [],
providers: [ LogService ]
} );
} );
it(
'should ...',
inject( [ LogService ], ( service: LogService ) => {
expect( service ).toBeTruthy();
} )
);
} );

View File

@ -0,0 +1,63 @@
import { Injectable } from '@angular/core';
import { environment } from '@env/environment';
import { LogFields } from './log-data.interface';
import { Logger } from './logger';
@Injectable( {
providedIn: 'root'
} )
export class LogService {
private logger: Logger;
constructor() {
this.initialize();
}
public initialize() {
this.logger = new Logger( environment.appName );
}
public logHttpInfo( info: any, elapsedTime: number, requestPath: string ) {
// TODO: create and set correlation id
const url = location.href;
const logFields: LogFields = {
environment: environment.env,
// userId: this.userId,
requestPath,
elapsedTime,
url,
};
this.logger.log( 'Information', `${ info }`, logFields );
}
public logError( errorMsg: string ) {
const url = location.href;
const logFields: LogFields = {
environment: environment.env,
// userId: this.userId,
requestPath: '',
elapsedTime: 0,
url: url,
};
this.logger.log( 'Error', errorMsg, logFields );
}
public logInfo( info: any ) {
const url = location.href;
const logFields: LogFields = {
environment: environment.env,
// userId: this.userId,
requestPath: '',
elapsedTime: 0,
url,
};
this.logger.log( 'Information', info, logFields );
}
}

View File

@ -0,0 +1,140 @@
import { environment } from '@env/environment';
import * as moment from 'moment';
import { Subject } from 'rxjs';
import { debounceTime, filter } from 'rxjs/operators';
import { LogFields } from './log-data.interface';
export type LogType = 'Error' | 'Information';
interface LogEntry {
type: LogType;
message: string;
data: LogFields;
}
enum LoggerEvents {
Flush = 1
}
export class Logger {
private readonly APP_FIELD = 'Application';
private readonly ENV_FIELD = 'Environment';
private readonly VERSION_FIELD = 'Version';
private readonly USER_NAME_FIELD = 'UserName';
private readonly ELAPSED_MS_FIELD = 'ElapsedMilliseconds';
private readonly REQUEST_PATH_FIELD = 'RequestPath';
private readonly URL_FIELD = 'Url';
private readonly APP_STATE_FIELD = 'AppState';
private buffer: LogEntry[] = [];
private flush = new Subject<LoggerEvents>();
constructor( private appName: string, private logEndpoint?: string ) {
this.flush
.pipe( debounceTime( 5000 ), filter( ( event ) => event === LoggerEvents.Flush ) )
.subscribe( () => this.flushBuffer() );
}
public log( type: LogType, message: string, data: LogFields ) {
this.buffer.push( {
type,
message,
data
} );
this.flush.next( LoggerEvents.Flush );
}
private flushBuffer() {
const data = this.buffer.splice( 0 );
if ( data.length === 0 ) {
return;
}
const body = data
.map( ( entry ) => this.buildLogString( entry ) )
.reduce( ( sum, entry ) => ( sum += entry ), '' );
if ( !environment.production ) {
// This is nested to make sure we always end up in here when running locally
// as in do not && this to the above if...
// tslint:disable-next-line:no-console
console.log( {
body,
data
} );
} else {
const xobj = new XMLHttpRequest();
// tslint:disable-next-line:no-console
if ( this.logEndpoint ) {
xobj.onerror = ( err ) => console.error( err );
xobj.open( 'POST', this.logEndpoint, true );
xobj.send( body );
}
}
}
private buildLogString( entry: LogEntry ): string {
const index = this.buildIndexChunk();
const body = this.buildBodyChunk( entry );
return `${ index }\n${ body }\n`;
}
private buildIndexChunk() {
const date = moment();
const index = {
index: {
_index: `logstash-${ date.format( 'YYYY.M.D' ) }`,
_type: 'logevent'
}
};
return JSON.stringify( index );
}
private buildBodyChunk( entry: LogEntry ) {
const { type, message, data } = entry;
const level = type;
const date = moment();
const messageTemplate = this.getMessageTemplate();
const fields = this.getFields( data );
const body = {
'@timestamp': `${ date.toISOString() }`,
level,
messageTemplate,
message,
fields
};
return JSON.stringify( body );
}
private getMessageTemplate() {
const fields: string[] = [
this.APP_FIELD,
this.ENV_FIELD,
this.VERSION_FIELD,
this.USER_NAME_FIELD,
this.ELAPSED_MS_FIELD,
this.REQUEST_PATH_FIELD,
this.URL_FIELD,
this.APP_STATE_FIELD
];
const template = fields.map( ( field ) => `{${ field }}` ).join( ' - ' );
return template;
}
private getFields( data: LogFields ) {
return {
[ this.APP_FIELD ]: this.appName,
[ this.ENV_FIELD ]: data.environment,
[ this.VERSION_FIELD ]: data.appVersion,
[ this.USER_NAME_FIELD ]: data.userId,
[ this.ELAPSED_MS_FIELD ]: data.elapsedTime,
[ this.REQUEST_PATH_FIELD ]: data.requestPath,
[ this.URL_FIELD ]: data.url
};
}
}

View File

@ -0,0 +1,12 @@
import { TestBed } from '@angular/core/testing';
import { StorageService } from './storage.service';
describe( 'StorageService', () => {
beforeEach( () => TestBed.configureTestingModule( {} ) );
it( 'should be created', () => {
const service: StorageService = TestBed.get( StorageService );
expect( service ).toBeTruthy();
} );
} );

View File

@ -0,0 +1,103 @@
import { Injectable } from '@angular/core';
import { Storage } from '@app/core/model';
@Injectable()
export class StorageService {
private data: Storage;
constructor() {
const localData = localStorage.getItem( 'c2a' );
const sessionData = sessionStorage.getItem( 'c2a' );
this.data = new Storage();
this.data.pageData = {};
this.data.sessionData = ( sessionData ? JSON.parse( sessionData ) : {} );
this.data.localData = ( localData ? JSON.parse( localData ) : {} );
}
public getLocal( key: string ): string | number | boolean | object {
const value = this.data.localData[ key ];
if ( !value ) {
return null;
}
return value;
}
public getSession( key: string ): string | number | boolean | object {
const value = this.data.sessionData[ key ];
if ( !value ) {
return null;
}
return value;
}
public getPage( key: string ): string | number | boolean | object {
const value = this.data.pageData[ key ];
if ( !value ) {
return null;
}
return value;
}
public setLocal( key: string, value?: any ): void {
let val: string | number | boolean;
if ( typeof value === 'boolean' || 'string' || 'number' || 'object' ) {
val = value;
} else {
val = null;
}
if ( val === null ) {
if ( this.data.localData[ key ] ) {
delete this.data.localData[ key ];
}
} else {
this.data.localData[ key ] = val;
}
localStorage.setItem( 'c2a', JSON.stringify( this.data.localData ) );
}
public setSession( key: string, value?: any ): void {
let val: string | number | boolean;
if ( typeof value === 'boolean' || 'string' || 'number' || 'object' ) {
val = value;
} else {
val = null;
}
if ( val === null ) {
if ( this.data.sessionData[ key ] ) {
delete this.data.sessionData[ key ];
}
} else {
this.data.sessionData[ key ] = val;
}
sessionStorage.setItem( 'c2a', JSON.stringify( this.data.localData ) );
}
public setPage( key: string, value?: any ): void {
let val: string | number | boolean;
if ( typeof value === 'boolean' || 'string' || 'number' || 'object' ) {
val = value;
} else {
val = null;
}
if ( val === null ) {
if ( this.data.pageData[ key ] ) {
delete this.data.pageData[ key ];
}
} else {
this.data.pageData[ key ] = val;
}
}
}

0
src/assets/config.json Normal file
View File

View File

@ -1,5 +1,7 @@
export const environment = {
production: true,
appName: 'DiscoTrip',
production: false,
env: 'production',
firebaseConfig: {
apiKey: 'AIzaSyDe48emSyoXS3WV6vM4GjYiJwdcMhcspqY',
authDomain: 'disco-trip.firebaseapp.com',

View File

@ -3,7 +3,9 @@
// The list of file replacements can be found in `angular.json`.
export const environment = {
appName: 'DiscoTrip',
production: false,
env: 'local',
firebaseConfig: {
apiKey: 'AIzaSyDe48emSyoXS3WV6vM4GjYiJwdcMhcspqY',
authDomain: 'disco-trip.firebaseapp.com',