diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 641595f..88900f9 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -6,6 +6,8 @@ import { AuthService } from './service/auth.service'; import { MenuService } from './service/menu.service'; import {WebSocketService} from './websocket'; +import {AppConfig} from './app.config'; +import {Title} from '@angular/platform-browser'; @Component({ selector: 'app-root', @@ -14,15 +16,27 @@ import {WebSocketService} from './websocket'; encapsulation: ViewEncapsulation.None }) export class AppComponent implements OnInit , OnDestroy { - title = 'SFM broker'; - private menutItemSub: Subscription; + title = 'SFM Advanced Loan management'; + private menuItemSub: Subscription; @ViewChild('loanEditComponent', {static: true}) loanEdit: LoanEditComponent; - constructor(private menuService: MenuService, private authService: AuthService, private wsService: WebSocketService){ - wsService.createObservableSocket(this.authService.apiWsUrl) - .subscribe(m => { - console.log('websocket server send this :', m); - }); + webSocketSubscription: Subscription; + wsLoginSub: Subscription; + + constructor(private menuService: MenuService, + private authService: AuthService, + private config: AppConfig, + private wsService: WebSocketService, + private titleService: Title){ + this.webSocketSubscription = wsService.subscribe(m => { + console.log('websocket server send this :', m); + }); + + this.wsLoginSub = this.wsService.LoginEvent.subscribe( m => { + console.log('login event ', m); + }); + + this.titleService.setTitle(this.title); } // tslint:disable-next-line:typedef @@ -33,7 +47,7 @@ export class AppComponent implements OnInit , OnDestroy { } listenToMenuEvent(): void { - this.menutItemSub = this.menuService.itemClicked.subscribe( + this.menuItemSub = this.menuService.itemClicked.subscribe( (item:any) =>{ // console.log("emit on select : " + item.text); if ( item.popup === 'loanEdit'){ @@ -45,9 +59,9 @@ export class AppComponent implements OnInit , OnDestroy { } - // tslint:disable-next-line:typedef - ngOnDestroy() { - + ngOnDestroy(): void { + this.webSocketSubscription.unsubscribe(); + this.wsLoginSub.unsubscribe(); } } diff --git a/src/app/app.config.model.ts b/src/app/app.config.model.ts index ba38fca..fa9409a 100644 --- a/src/app/app.config.model.ts +++ b/src/app/app.config.model.ts @@ -2,4 +2,6 @@ export class AppConfigModel { Server = 'https://c5016.biukop.com.au:8080/api/v1/'; Socket = 'ws://c5016.biukop.com.au:8080/api/v1/'; + SessionStorageKey = 'sk'; + Version = 2021; } diff --git a/src/app/app.config.ts b/src/app/app.config.ts index 95b1b41..802cd29 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -9,12 +9,16 @@ export class AppConfig { static config: AppConfigModel; static debugConfig: AppConfigModel = { Server: 'https://svr2021.lawipac.com:8080/api/v1/', - Socket: 'wss://svr2021.lawipac.com:8080/api/v1/ws' + Socket: 'wss://svr2021.lawipac.com:8080/api/v1/ws', + SessionStorageKey: 'sk', + Version: 2021 }; static productionConfig: AppConfigModel = { Server: 'https://c5016.biukop.com.au:8080/api/v1/', - Socket: 'wss://c5016.biukop.com.au:8080/api/v1/ws' + Socket: 'wss://c5016.biukop.com.au:8080/api/v1/ws', + SessionStorageKey : 'sk', + Version: 2021 }; constructor(private http: HttpClient) {} @@ -55,6 +59,10 @@ export class AppConfig { return AppConfig.config.Socket; } + public get storageKey(): string{ + return AppConfig.config.SessionStorageKey; + } + public getUrl(key: string): string{ const s = this.apiUrl + key; const kvPair: {key: string, value: string}[] = [ diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 942bc5b..cfe1641 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -111,6 +111,7 @@ import { PDFExportModule } from '@progress/kendo-angular-pdf-export'; import { RewardSelectComponent } from './reward-select/reward-select.component'; import { RewardsAllComponent } from './rewards-all/rewards-all.component'; import { SinglePayoutRewardsListComponent } from './single-payout-rewards-list/single-payout-rewards-list.component'; +import {SessionService} from './service/session.service'; @@ -233,6 +234,7 @@ export function initializeApp(appConfig: AppConfig): () => Promise { MenuService, AuthGuard, AuthService, + SessionService, WebSocketService, LoanSummaryService, LoanSingleService, diff --git a/src/app/auth/auth-http-interceptor.service.ts b/src/app/auth/auth-http-interceptor.service.ts index e17622b..72b27e3 100644 --- a/src/app/auth/auth-http-interceptor.service.ts +++ b/src/app/auth/auth-http-interceptor.service.ts @@ -1,25 +1,25 @@ import {Injectable} from '@angular/core'; import {HttpEvent, HttpEventType, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse} from '@angular/common/http'; import {Observable} from 'rxjs'; -import {AuthService} from '../service/auth.service'; import {tap} from 'rxjs/operators'; +import {SessionService} from '../service/session.service'; @Injectable() export class AuthHttpInterceptor implements HttpInterceptor { - constructor(private auth: AuthService) { + constructor(private ss: SessionService) { } intercept(req: HttpRequest, next: HttpHandler): Observable> { let h = req.headers; - if (this.auth.loggedIn.hasValidSession()) { - h = h.set('Biukop-Session', this.auth.loggedIn.session); + if (this.ss.loggedIn.hasValidSession()) { + h = h.set('Biukop-Session', this.ss.loggedIn.session); } - if (this.auth.loggedIn.hasValidMachineId()) { - h = h.set('Biukop-Mid', this.auth.loggedIn.machineId); + if (this.ss.loggedIn.hasValidMachineId()) { + h = h.set('Biukop-Mid', this.ss.loggedIn.machineId); } const authReq = req.clone({ @@ -32,9 +32,9 @@ export class AuthHttpInterceptor implements HttpInterceptor { if (event.type === HttpEventType.Response){ const bs = event.headers.get('biukop-session'); if (bs !== undefined){ - if ( this.auth.loggedIn.session !== bs ){ - this.auth.loggedIn.session = bs; - this.auth.saveSessionInfo(); + if ( this.ss.loggedIn.session !== bs ){ + this.ss.loggedIn.session = bs; + this.ss.saveSessionInfo(); console.log('switch session:' , bs); } } diff --git a/src/app/auth/auth.component.ts b/src/app/auth/auth.component.ts index ac0aa1a..535e894 100644 --- a/src/app/auth/auth.component.ts +++ b/src/app/auth/auth.component.ts @@ -5,6 +5,7 @@ import { NotificationService } from '@progress/kendo-angular-notification'; import { Subscription } from 'rxjs'; import { AuthService } from '../service/auth.service'; import {ApiV1LoginResponse} from '../models/api-v1-login-response'; +import {SessionService} from '../service/session.service'; @Component({ selector: 'app-auth', @@ -20,11 +21,12 @@ export class AuthComponent implements OnInit, OnDestroy{ email: new FormControl('admin@supercredit.com.au', Validators.email) }); - constructor(private authService: AuthService, private router: Router, private notificationService: NotificationService) { } + constructor(private authService: AuthService, private ss: SessionService, + private router: Router, private notificationService: NotificationService) { } ngOnInit(): void { this.authService.logout(); - this.loginSub = this.authService.loginSuccess.subscribe( + this.loginSub = this.ss.loginSuccess.subscribe( responseData => { // console.log(responseData); this.onLogin(responseData); diff --git a/src/app/broker-loan-list/broker-loan-list.component.ts b/src/app/broker-loan-list/broker-loan-list.component.ts index 88c70d9..68fd3b9 100644 --- a/src/app/broker-loan-list/broker-loan-list.component.ts +++ b/src/app/broker-loan-list/broker-loan-list.component.ts @@ -1,10 +1,9 @@ import {Component, Input, OnInit} from '@angular/core'; -import {BrokerModel} from '../models/broker.model'; -import {LoanModel} from '../models/loan.model'; import {LoanSummaryService} from '../service/loan_summary.service'; import {CompositeFilterDescriptor, SortDescriptor} from '@progress/kendo-data-query'; -import {AuthService} from '../service/auth.service'; import {PeopleModel} from '../models/people.model'; +import {AppConfig} from '../app.config'; +import {SessionService} from '../service/session.service'; @Component({ selector: 'app-broker-loan-list', @@ -16,11 +15,11 @@ export class BrokerLoanListComponent implements OnInit { @Input() public broker: PeopleModel = PeopleModel.EmptyNew(); public brokerLoans: LoanSummaryService; - constructor( private lss: LoanSummaryService, private auth: AuthService) { } + constructor( private lss: LoanSummaryService, private ss: SessionService, private config: AppConfig) { } ngOnInit(): void { this.brokerLoans = this.lss; - this.broker = this.auth.loggedIn.User; + this.broker = this.ss.loggedIn.User; this.loadData(); } @@ -31,7 +30,7 @@ export class BrokerLoanListComponent implements OnInit { } private photoURL(peopleId: any): string { - const url = this.auth.getUrl('avatar/') + peopleId; + const url = this.config.getUrl('avatar/') + peopleId; return 'url("' + url + '")'; } } diff --git a/src/app/broker-reward/broker-reward.component.ts b/src/app/broker-reward/broker-reward.component.ts index 7c20404..3876fff 100644 --- a/src/app/broker-reward/broker-reward.component.ts +++ b/src/app/broker-reward/broker-reward.component.ts @@ -3,6 +3,8 @@ import {HttpClient} from '@angular/common/http'; import {AuthService} from '../service/auth.service'; import {RewardByUserModel} from '../models/reward-by-user.model'; import {DataResult, GroupDescriptor, process} from '@progress/kendo-data-query'; +import {SessionService} from '../service/session.service'; +import {AppConfig} from '../app.config'; @Component({ selector: 'app-broker-reward', @@ -18,7 +20,7 @@ export class BrokerRewardComponent implements OnInit { public groups: GroupDescriptor[] = [{ field: 'Description' }, { field: 'Item' } ]; public gridView: DataResult; - constructor(private http: HttpClient, private auth: AuthService ) { } + constructor(private http: HttpClient, private ss: SessionService, private config: AppConfig ) { } ngOnInit(): void { this.loading = true; @@ -29,13 +31,13 @@ export class BrokerRewardComponent implements OnInit { this.gridData = []; // avoid loading everything when used with admin user - if ( this.auth.loggedIn.role === 'admin' && this.selectedBrokerId === '' ) { + if ( this.ss.loggedIn.role === 'admin' && this.selectedBrokerId === '' ) { this.loading = false; return ; } // load a single user - this.http.get(this.auth.getUrl('user-reward/' + this.selectedBrokerId )).subscribe( + this.http.get(this.config.getUrl('user-reward/' + this.selectedBrokerId )).subscribe( rsp => { rsp.forEach(v => { this.gridData.push(new RewardByUserModel(v)); diff --git a/src/app/client-loan-list/client-loan-list.component.ts b/src/app/client-loan-list/client-loan-list.component.ts index 7e1cfff..2b8162d 100644 --- a/src/app/client-loan-list/client-loan-list.component.ts +++ b/src/app/client-loan-list/client-loan-list.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core'; import {LoanModel} from '../models/loan.model'; import {LoanSingleService} from '../service/loan.single.service'; import {AuthService} from '../service/auth.service'; +import {SessionService} from '../service/session.service'; @Component({ selector: 'app-client-loan-list', @@ -12,10 +13,10 @@ export class ClientLoanListComponent implements OnInit { public Loans: LoanModel[] =[]; - constructor(private ls: LoanSingleService, private auth: AuthService) { } + constructor(private ls: LoanSingleService, private ss: SessionService) { } ngOnInit(): void { - this.ls.getLoanByClient(this.auth.loggedIn.User.Id).subscribe( + this.ls.getLoanByClient(this.ss.loggedIn.User.Id).subscribe( resp => { this.Loans = []; resp.forEach( v => { diff --git a/src/app/client-profile/client-profile.component.ts b/src/app/client-profile/client-profile.component.ts index 003a07d..04f08a4 100644 --- a/src/app/client-profile/client-profile.component.ts +++ b/src/app/client-profile/client-profile.component.ts @@ -6,6 +6,7 @@ import {PeopleService} from '../service/people.service'; import {FileInfo, FileRestrictions, FileSelectComponent, SelectEvent} from '@progress/kendo-angular-upload'; import {BrokerModel} from '../models/broker.model'; import {AppConfig} from '../app.config'; +import {SessionService} from '../service/session.service'; @Component({ selector: 'app-client-profile', @@ -24,14 +25,14 @@ export class ClientProfileComponent implements OnInit { public opened = false; // dialog box public Message = ''; // dialog message - constructor(private auth: AuthService, private ps: PeopleService) { + constructor(private ss: SessionService, private config: AppConfig, private ps: PeopleService) { this.avatarUrl = 'url("' + location.origin + './assets/img/avatar.png' + '")'; } ngOnInit(): void { - this.User = this.auth.loggedIn.User; - this.avatarUrl = 'url(' + this.auth.getUrl('avatar/' + this.User.Id) + ')'; + this.User = this.ss.loggedIn.User; + this.avatarUrl = 'url(' + this.config.getUrl('avatar/' + this.User.Id) + ')'; } diff --git a/src/app/models/api-v1-login-response.ts b/src/app/models/api-v1-login-response.ts index fca6fa9..fa3b965 100644 --- a/src/app/models/api-v1-login-response.ts +++ b/src/app/models/api-v1-login-response.ts @@ -13,7 +13,7 @@ export class ApiV1LoginResponse { public sessionExpire: number, // unix timestamp public role: string, public User: PeopleModel, - public UserExtra?: UserExtraModel // extra user informaiton + public UserExtra?: UserExtraModel // extra user information ) { this.login = login; this.machineId = machineId; diff --git a/src/app/models/user.model.ts b/src/app/models/user.model.ts new file mode 100644 index 0000000..aae87d6 --- /dev/null +++ b/src/app/models/user.model.ts @@ -0,0 +1,24 @@ +import {PeopleModel} from './people.model'; +import {BrokerModel} from './broker.model'; + +export enum UserRoles { + Unknown = 'Unknown', + People = 'People', + Broker = 'Broker', + Beneficiary = 'Beneficiary', + Admin = 'admin', + Accountant = 'accountant', + Super = 'super', +} + +export class UserModel extends PeopleModel{ + Role: UserRoles; + Broker?: BrokerModel; + Login: string; + constructor(payload: Partial) { + super(payload); + this.Role = payload.Role || 'People' as UserRoles; + this.Login = payload.Login || ''; + this.Broker = new BrokerModel(payload); + } +} diff --git a/src/app/models/websocket/ws.login.event.model.ts b/src/app/models/websocket/ws.login.event.model.ts new file mode 100644 index 0000000..1c296bb --- /dev/null +++ b/src/app/models/websocket/ws.login.event.model.ts @@ -0,0 +1,15 @@ + +export class WsLoginEventModel{ + T: string; + Mid: string; + Sid: string; + Uid: string; + Role: string; + constructor( payload: Partial) { + this.T = payload.T || ''; + this.Mid = payload.Mid || ''; + this.Sid = payload.Sid || ''; + this.Uid = payload.Uid || ''; + this.Role = payload.Uid || ''; + } +} diff --git a/src/app/profile/broker-profile/broker-profile.component.ts b/src/app/profile/broker-profile/broker-profile.component.ts index 50b1c93..6432467 100644 --- a/src/app/profile/broker-profile/broker-profile.component.ts +++ b/src/app/profile/broker-profile/broker-profile.component.ts @@ -6,6 +6,7 @@ import {BrokerModel} from '../../models/broker.model'; import {MessageBoxComponent} from '../../message-box/message-box.component'; import {UserExtraModel} from '../../models/user-extra.model'; import {PeopleModel} from '../../models/people.model'; +import {SessionService} from '../../service/session.service'; @@ -20,10 +21,10 @@ export class BrokerProfileComponent implements OnInit { @ViewChild('messageBox', {static: true})msgBox: MessageBoxComponent; public isAdmin = false; - constructor( private auth: AuthService, private ps: PeopleService) { } + constructor( private ss: SessionService, private ps: PeopleService) { } ngOnInit(): void { - this.isAdmin = this.auth.isAdmin(); + this.isAdmin = this.ss.isAdmin(); } public save(brokerForm: NgForm): void{ diff --git a/src/app/profile/change-password/change-password.component.ts b/src/app/profile/change-password/change-password.component.ts index fda4c18..accc440 100644 --- a/src/app/profile/change-password/change-password.component.ts +++ b/src/app/profile/change-password/change-password.component.ts @@ -3,6 +3,7 @@ import {FormControl, FormGroup} from '@angular/forms'; import {AuthService} from '../../service/auth.service'; import {PeopleService} from '../../service/people.service'; import {MessageBoxComponent} from '../../message-box/message-box.component'; +import {SessionService} from '../../service/session.service'; @Component({ selector: 'app-change-password', @@ -21,11 +22,11 @@ export class ChangePasswordComponent implements OnInit { NewPass: new FormControl(), NewPass1: new FormControl(), }); - constructor(private auth: AuthService, private ps: PeopleService) { } + constructor(private ss: SessionService, private ps: PeopleService) { } ngOnInit(): void { - if (this.auth.isAdmin() && this.PeopleId !== '' && !this.auth.isCurrentUser(this.PeopleId)) { - this.isAdmin = this.auth.isAdmin(); + if (this.ss.isAdmin() && this.PeopleId !== '' && !this.ss.isCurrentUser(this.PeopleId)) { + this.isAdmin = this.ss.isAdmin(); } } public hidePass(): void{ @@ -56,10 +57,10 @@ export class ChangePasswordComponent implements OnInit { } public canChangePassword(): boolean { - if ( this.auth.isCurrentUser(this.PeopleId) ) { - return this.auth.isUser() || this.auth.isBroker() || this.auth.isAdmin(); + if ( this.ss.isCurrentUser(this.PeopleId) ) { + return this.ss.isUser() || this.ss.isBroker() || this.ss.isAdmin(); }else{ - return this.auth.isAdmin() ; + return this.ss.isAdmin() ; } } } diff --git a/src/app/profile/people-profile/people-profile.component.ts b/src/app/profile/people-profile/people-profile.component.ts index 1eaf264..f2eb547 100644 --- a/src/app/profile/people-profile/people-profile.component.ts +++ b/src/app/profile/people-profile/people-profile.component.ts @@ -5,6 +5,8 @@ import {AuthService} from '../../service/auth.service'; import {PeopleService} from '../../service/people.service'; import {NgForm} from '@angular/forms'; import {PeopleModel} from '../../models/people.model'; +import {SessionService} from '../../service/session.service'; +import {AppConfig} from '../../app.config'; @Component({ selector: 'app-people-profile', @@ -23,15 +25,15 @@ export class PeopleProfileComponent implements OnInit { @ViewChild('messagebox', {static: true}) msgBox: MessageBoxComponent; @ViewChild('fileSelect', {static: true}) fs: FileSelectComponent; - constructor(private auth: AuthService, private ps: PeopleService) { } + constructor(private ss: SessionService, private config: AppConfig, private ps: PeopleService) { } ngOnInit(): void { - if (this.auth.isAdmin() && !this.auth.isCurrentUser(this.People.Id)) { + if (this.ss.isAdmin() && !this.ss.isCurrentUser(this.People.Id)) { // }else{ - this.People = this.auth.loggedIn.User; + this.People = this.ss.loggedIn.User; } - this.avatarUrl = 'url(' + this.auth.getUrl('avatar/' + this.People.Id) + ')'; + this.avatarUrl = 'url(' + this.config.getUrl('avatar/' + this.People.Id) + ')'; } onDialogClose(status: string): void { @@ -72,8 +74,8 @@ export class PeopleProfileComponent implements OnInit { } this.ps.savePeople(this.People).subscribe( () => { this.msgBox.Show('Updated successfully '); - if ( this.auth.loggedIn.User.Id === this.People.Id ) { - this.auth.UpdatePeopleInfo(this.People); + if ( this.ss.loggedIn.User.Id === this.People.Id ) { + this.ss.UpdatePeopleInfo(this.People); } peopleForm.form.markAsPristine(); }, err => { @@ -86,14 +88,14 @@ export class PeopleProfileComponent implements OnInit { ppl => { this.People.Copy(ppl); this.newPeople.emit(this.People); - this.avatarUrl = 'url(' + this.auth.getUrl('avatar/' + this.People.Id) + ')'; + this.avatarUrl = 'url(' + this.config.getUrl('avatar/' + this.People.Id) + ')'; } ); } public PeopleChanged(ppl: PeopleModel): void { console.log(this); - this.avatarUrl = 'url(' + this.auth.getUrl('avatar/' + this.People.Id) + ')'; + this.avatarUrl = 'url(' + this.config.getUrl('avatar/' + this.People.Id) + ')'; } public startSelectAvatar(): void { diff --git a/src/app/profile/profile.component.ts b/src/app/profile/profile.component.ts index be806c7..ea1dfee 100644 --- a/src/app/profile/profile.component.ts +++ b/src/app/profile/profile.component.ts @@ -11,6 +11,7 @@ import {PeopleModel} from '../models/people.model'; import {UserExtraModel} from '../models/user-extra.model'; import {MessageBoxComponent} from '../message-box/message-box.component'; import {setTime} from '@progress/kendo-angular-dateinputs/dist/es2015/util'; +import {SessionService} from '../service/session.service'; @Component({ selector: 'app-profile', @@ -56,7 +57,7 @@ export class ProfileComponent implements OnInit { public isValidPeople = true; public isValidBroker = true; - constructor(private auth: AuthService, private ps: PeopleService, private actRoute: ActivatedRoute) { } + constructor(private auth: AuthService, private ss: SessionService, private ps: PeopleService, private actRoute: ActivatedRoute) { } ngOnInit(): void { const id = this.actRoute.snapshot.params.id; @@ -64,17 +65,17 @@ export class ProfileComponent implements OnInit { this.PeopleId = id; } - if (this.auth.isAdmin() && this.PeopleId !== '' ){ + if (this.ss.isAdmin() && this.PeopleId !== '' ){ if (this.PeopleId === 'start-new-people' ){ return; - }else if (this.PeopleId !== '' && !this.auth.isCurrentUser(this.PeopleId)) { // admin editing someone else + }else if (this.PeopleId !== '' && !this.ss.isCurrentUser(this.PeopleId)) { // admin editing someone else this.loadOtherPeople(); } }else { // edit himself - this.role = this.auth.loggedIn.role; - this.PeopleId = this.auth.loggedIn.User.Id; - this.People = this.auth.loggedIn.User; - this.UserExtra = this.auth.loggedIn.UserExtra; + this.role = this.ss.loggedIn.role; + this.PeopleId = this.ss.loggedIn.User.Id; + this.People = this.ss.loggedIn.User; + this.UserExtra = this.ss.loggedIn.UserExtra; } this.updateShowHide(); } @@ -117,7 +118,7 @@ export class ProfileComponent implements OnInit { private updateShowHide(): void { this.resetShowHide(); - this.editOtherPeople = ! this.auth.isCurrentUser(this.PeopleId); + this.editOtherPeople = ! this.ss.isCurrentUser(this.PeopleId); if ( this.editOtherPeople ) { this.showAdminTool = this.isAdmin() && this.People.Id !== '' ; if ( this.showAdminTool ){ @@ -163,17 +164,17 @@ export class ProfileComponent implements OnInit { // the user who performs this edit action public isAdmin(): boolean { - return this.auth.isAdmin(); + return this.ss.isAdmin(); } // the user who performs this edit action public isBroker(): boolean { - return this.auth.isBroker(); + return this.ss.isBroker(); } // the user who performs this edit action public isUser(): boolean { - return this.auth.isUser(); + return this.ss.isUser(); } public deletePeople(): void { diff --git a/src/app/profile/user-profile/user-profile.component.ts b/src/app/profile/user-profile/user-profile.component.ts index 0e40d43..40067ed 100644 --- a/src/app/profile/user-profile/user-profile.component.ts +++ b/src/app/profile/user-profile/user-profile.component.ts @@ -7,6 +7,7 @@ import {MessageBoxComponent} from '../../message-box/message-box.component'; import {PeopleService} from '../../service/people.service'; import {asyncValidatorLoginAvailable} from '../../validator/unique.login.validator'; import {PeopleModel} from '../../models/people.model'; +import {SessionService} from '../../service/session.service'; @Component({ selector: 'app-user-profile', @@ -23,18 +24,18 @@ export class UserProfileComponent implements OnInit { public UserForm: FormGroup; - constructor(private auth: AuthService, private http: HttpClient, private ps: PeopleService) { } + constructor(private auth: AuthService, private ss: SessionService, private http: HttpClient) { } ngOnInit(): void { - this.showAdmin = this.auth.isAdmin(); - this.isCurrentUser = this.auth.isCurrentUser(this.People.Id); + this.showAdmin = this.ss.isAdmin(); + this.isCurrentUser = this.ss.isCurrentUser(this.People.Id); - if (this.auth.isAdmin() && !this.auth.isCurrentUser(this.People.Id)) { + if (this.ss.isAdmin() && !this.ss.isCurrentUser(this.People.Id)) { // edit other people, }else{ - this.People.Id = this.auth.loggedIn.User.Id; - this.UserExtra = this.auth.loggedIn.UserExtra; + this.People.Id = this.ss.loggedIn.User.Id; + this.UserExtra = this.ss.loggedIn.UserExtra; } this.UserForm = new FormGroup({ Login: new FormControl({value: this.UserExtra.Login, disabled: ! this.showAdmin }, @@ -62,7 +63,7 @@ export class UserProfileComponent implements OnInit { } public currentUserIsAdmin(): boolean { - return this.auth.loggedIn.role === 'admin'; + return this.ss.loggedIn.role === 'admin'; } public canEditUser(): boolean { diff --git a/src/app/service/auth.service.ts b/src/app/service/auth.service.ts index 2e006e2..006a998 100644 --- a/src/app/service/auth.service.ts +++ b/src/app/service/auth.service.ts @@ -6,29 +6,23 @@ import {PeopleModel} from '../models/people.model'; import {UserExtraModel} from '../models/user-extra.model'; import {Observable} from 'rxjs'; import {AppConfig} from '../app.config'; +import {SessionService} from './session.service'; @Injectable() export class AuthService { - public apiUrl = ''; - public apiWsUrl = ''; - - public loggedIn = ApiV1LoginResponse.EmptyNew(); - loginSuccess = new EventEmitter (); constructor( private http: HttpClient , private router: Router, - private config: AppConfig) { - this.apiUrl = config.apiUrl; - this.apiWsUrl = config.apiWsUrl; - } + private ss: SessionService, + private config: AppConfig) { } public AutoLogin(): void { - const sfm: ApiV1LoginResponse = JSON.parse(localStorage.getItem('sfm')); + const sfm: ApiV1LoginResponse = JSON.parse(localStorage.getItem(this.config.storageKey)); if (!sfm) { console.log('no auto login'); return; } - this.loggedIn = new ApiV1LoginResponse( + this.ss.loggedIn = new ApiV1LoginResponse( sfm.login, sfm.machineId, sfm.session, @@ -38,16 +32,14 @@ export class AuthService { ); if ( sfm.UserExtra !== undefined ) { - this.loggedIn.UserExtra = new UserExtraModel(sfm.UserExtra); + this.ss.loggedIn.UserExtra = new UserExtraModel(sfm.UserExtra); } - - this.loginSuccess.emit(this.loggedIn); - // console.log ( 'auto login emit events', this.loggedIn); + this.ss.loginSuccess.emit(this.ss.loggedIn); } isAuthenticated(): boolean { - return this.loggedIn.login; + return this.ss.loggedIn.login; } allowEditLoan(): boolean{ @@ -55,103 +47,55 @@ export class AuthService { } saveSessionInfo(): void { - localStorage.setItem('sfm', JSON.stringify(this.loggedIn)); - localStorage.setItem('mid', this.loggedIn.machineId); + localStorage.setItem(this.config.storageKey, JSON.stringify(this.ss.loggedIn)); + localStorage.setItem('mid', this.ss.loggedIn.machineId); } login(email: string, password: string): void { - this.http.post(this.apiUrl + 'login', {u: email, p: password}).subscribe( + this.http.post(this.config.apiUrl + 'login', {u: email, p: password}).subscribe( responseData => { - this.loggedIn.session = responseData['Biukop-Session']; - this.loggedIn.login = responseData.login; - this.loggedIn.machineId = responseData['Biukop-Mid']; - this.loggedIn.sessionExpire = responseData.sessionExpire; - this.loggedIn.role = responseData.role; + this.ss.loggedIn.session = responseData['Biukop-Session']; + this.ss.loggedIn.login = responseData.login; + this.ss.loggedIn.machineId = responseData['Biukop-Mid']; + this.ss.loggedIn.sessionExpire = responseData.sessionExpire; + this.ss.loggedIn.role = responseData.role; if ( responseData.User !== undefined) { - this.loggedIn.User = new PeopleModel(responseData.User); + this.ss.loggedIn.User = new PeopleModel(responseData.User); if (responseData.UserExtra !== undefined ) { - this.loggedIn.UserExtra = new UserExtraModel(responseData.UserExtra); + this.ss.loggedIn.UserExtra = new UserExtraModel(responseData.UserExtra); }else{ - this.loggedIn.UserExtra = UserExtraModel.EmptyNew(); + this.ss.loggedIn.UserExtra = UserExtraModel.EmptyNew(); } }else{ - this.loggedIn.User = PeopleModel.EmptyNew(); + this.ss.loggedIn.User = PeopleModel.EmptyNew(); } this.saveSessionInfo(); - this.loginSuccess.emit(responseData); + this.ss.loginSuccess.emit(responseData); }, error => { - this.loggedIn = ApiV1LoginResponse.EmptyNew(); + this.ss.loggedIn = ApiV1LoginResponse.EmptyNew(); console.log('login error', error); - this.loginSuccess.emit(this.loggedIn); + this.ss.loginSuccess.emit(this.ss.loggedIn); } ); } logout(): void { - this.loggedIn = ApiV1LoginResponse.EmptyNew(); - localStorage.removeItem('sfm'); - this.loginSuccess.emit(this.loggedIn); - this.router.navigate(['/login']).then(r => { - console.log('prepare to log back in'); - } ); - this.http.post(`${this.apiUrl}logout`, '').subscribe( - resp => { - console.log('successfully logout from server'); - }, - event => { - console.log('error logout from server', event); - } - ); + this.ss.logout(); } public getUrl(key: string): string{ return this.config.getUrl(key); - // const s = this.apiUrl + key; - // const kvPair: {key: string, value: string}[] = [ - // {key: 'login', value: this.apiUrl + 'login'}, - // {key: 'logout', value: this.apiUrl + 'logout'} - // ]; - // - // kvPair.forEach( item => { - // if ( item.key === key) { - // return item.value; - // } - // }); - // - // // not found if arrive here - // return s; } - public UpdatePeopleInfo(people: PeopleModel): void{ - this.loggedIn.User.Display = people.Display; - this.loggedIn.User.First = people.First; - this.loggedIn.User.Last = people.Last; - this.saveSessionInfo(); - } public LoginAvailable(v: string): Observable { return this.http.get(this.getUrl('login-available/' + v)); } - public isAdmin(): boolean { - return this.loggedIn.role === 'admin'; - } - - public isBroker(): boolean { - return this.loggedIn.role === 'broker'; - } - - public isUser(): boolean { - return this.loggedIn.login === true; - } - - public isCurrentUser(id: string): boolean { - return this.loggedIn.login === true && this.loggedIn.User !== undefined && this.loggedIn.User.Id === id; - } } diff --git a/src/app/service/session.service.ts b/src/app/service/session.service.ts new file mode 100644 index 0000000..fafdfdb --- /dev/null +++ b/src/app/service/session.service.ts @@ -0,0 +1,75 @@ +import {EventEmitter, Injectable} from '@angular/core'; +import {AppConfig} from '../app.config'; +import {ApiV1LoginResponse} from '../models/api-v1-login-response'; +import {PeopleModel} from '../models/people.model'; +import {HttpClient} from '@angular/common/http'; +import {Router} from '@angular/router'; +import {NotificationService} from '@progress/kendo-angular-notification'; + +@Injectable() +export class SessionService { + public loggedIn = ApiV1LoginResponse.EmptyNew(); + loginSuccess = new EventEmitter (); + + + constructor(private config: AppConfig, private http: HttpClient, private router: Router, private ns: NotificationService){ } + + public saveSessionInfo(): void { + localStorage.setItem(this.config.storageKey, JSON.stringify(this.loggedIn)); + localStorage.setItem('mid', this.loggedIn.machineId); + } + + public isAdmin(): boolean { + return this.loggedIn.role === 'admin'; + } + + public isBroker(): boolean { + return this.loggedIn.role === 'broker'; + } + + public isUser(): boolean { + return this.loggedIn.login === true; + } + + public isCurrentUser(id: string): boolean { + return this.loggedIn.login === true && this.loggedIn.User !== undefined && this.loggedIn.User.Id === id; + } + + public UpdatePeopleInfo(people: PeopleModel): void{ + this.loggedIn.User.Display = people.Display; + this.loggedIn.User.First = people.First; + this.loggedIn.User.Last = people.Last; + this.saveSessionInfo(); + } + + logout(): void { + if ( !this.loggedIn.login ){ + return; + } + this.loggedIn = ApiV1LoginResponse.EmptyNew(); + localStorage.removeItem(this.config.storageKey); + this.loginSuccess.emit(this.loggedIn); + this.router.navigate(['/login']).then(r => { + this.show(); + } ); + this.http.post(`${this.config.apiUrl}logout`, '').subscribe( + resp => { + console.log('successfully logout from server'); + }, + event => { + console.log('error logout from server', event); + } + ); + } + + public show(): void { + this.ns.show({ + content: 'Successfully logged out', + cssClass: 'button-notification', + animation: { type: 'slide', duration: 400 }, + position: { horizontal: 'center', vertical: 'top' }, + type: { style: 'info', icon: true }, + hideAfter : 2000 + }); + } +} diff --git a/src/app/top-bar/top-bar.component.ts b/src/app/top-bar/top-bar.component.ts index c93166e..00fb58f 100644 --- a/src/app/top-bar/top-bar.component.ts +++ b/src/app/top-bar/top-bar.component.ts @@ -5,6 +5,7 @@ import {brokerMenuItems, mainMenuItems, peopleMenuItems, userMenuItems} from '.. import {ApiV1LoginResponse} from '../models/api-v1-login-response'; import {Subscription} from 'rxjs'; import {PeopleModel} from '../models/people.model'; +import {SessionService} from '../service/session.service'; @Component({ @@ -24,6 +25,7 @@ export class TopBarComponent implements OnInit , OnDestroy { public opened = false; constructor(private menuService: MenuService, + private ss: SessionService, private authService: AuthService) { } @@ -32,15 +34,15 @@ export class TopBarComponent implements OnInit , OnDestroy { } public initAndSubLogin(): void{ - this.login = this.authService.loggedIn.login; - this.LoggedInUser = this.authService.loggedIn.User; + this.login = this.ss.loggedIn.login; + this.LoggedInUser = this.ss.loggedIn.User; - this.selectMenuShow(this.authService.loggedIn.role); + this.selectMenuShow(this.ss.loggedIn.role); - this.loginSub = this.authService.loginSuccess.subscribe( + this.loginSub = this.ss.loginSuccess.subscribe( (rsp: ApiV1LoginResponse) => { this.login = rsp.login; - this.LoggedInUser = this.authService.loggedIn.User; + this.LoggedInUser = this.ss.loggedIn.User; this.selectMenuShow(rsp.role); } ); @@ -101,7 +103,7 @@ export class TopBarComponent implements OnInit , OnDestroy { } public loggedInUserAvatar(): string { - return this.authService.getUrl('avatar/') + this.authService.loggedIn.User.Id; + return this.authService.getUrl('avatar/') + this.ss.loggedIn.User.Id; } public profile(): void { diff --git a/src/app/websocket.ts b/src/app/websocket.ts index 6762aaf..61dfd2c 100644 --- a/src/app/websocket.ts +++ b/src/app/websocket.ts @@ -1,48 +1,64 @@ import { Injectable } from '@angular/core'; -import {Observable, Subscriber} from 'rxjs'; +import {Observable, Subject, Subscriber} from 'rxjs'; +import {AppConfig} from './app.config'; +import {WsLoginEventModel} from './models/websocket/ws.login.event.model'; @Injectable() -export class WebSocketService { +export class WebSocketService extends Subject{ public ws: WebSocket; - private url: string; - private observer: Subscriber; - - public createObservableSocket(url: string): Observable { - this.url = url; - const ret = new Observable ( observer => { - this.observer = observer; - }); + private readonly url: string; + public LoginEvent: Subject; + + constructor(private config: AppConfig) { + super(); + this.url = config.apiWsUrl; this.startWebsocket(); - return ret; + this.LoginEvent = new Subject(); } - // tslint:disable-next-line:typedef - public onMessage(event){ - this.observer.next(event.data); + private startWebsocket(): void { + console.log('starting websocket now..', this.url); + this.ws = new WebSocket(this.url); + this.ws.onmessage = this.onMessage.bind(this); + this.ws.onerror = this.onError.bind(this); + this.ws.onclose = this.onClose.bind(this); } - // tslint:disable-next-line:typedef - public onError(event){ + // public createObservableSocket(url: string): Observable { + // this.url = url; + // const ret = new Observable ( observer => { + // this.observer = observer; + // }); + // this.startWebsocket(); + // return ret; + // } + + + public onMessage(event): void{ + super.next(event.data); + try { + const e = JSON.parse(event.data); + if ( e.T === 'login' || e.T === 'logout' ){ + this.LoginEvent.next(new WsLoginEventModel(e)); + } + }catch (e) { + console.log(e); + } + } + + public onError(event): void{ console.log('on error ', event); } - // tslint:disable-next-line:typedef - public onClose(event){ - console.log('websocket closed.. reconnect in 1s ..'); + public onClose(event): void{ + console.log('websocket closed.. reconnect in 1s ..', event); setTimeout(() => { this.startWebsocket(); } , 1000); } - // tslint:disable-next-line:typedef - public startWebsocket() { - console.log('starting websocket now..', this.url); - this.ws = new WebSocket(this.url); - this.ws.onmessage = this.onMessage.bind(this); - this.ws.onerror = this.onError.bind(this); - this.ws.onclose = this.onClose.bind(this); - } + public sendMessage(message: any): void { this.ws.send(message); diff --git a/src/index.html b/src/index.html index 29c3e61..7164e21 100644 --- a/src/index.html +++ b/src/index.html @@ -13,21 +13,12 @@ server="https://sc5016.biukop.com.au:8080/" version="0.9.1" > - eyJTZXJ2ZXIiOiJodHRwczpcL1wvYzUwMTYuYml1a29wLmNvbS5h - dTo4MDgwXC9hcGlcL3YxXC8iLCJTb2NrZXQiOiJ3c3M6XC9cL2M1 - MDE2LmJpdWtvcC5jb20uYXU6ODA4MFwvYXBpXC92MVwvd3MifQ== + eyJTZXJ2ZXIiOiJodHRwczpcL1wvYzUwMTYuYml1a29wLmNvbS5hd + To4MDgwXC9hcGlcL3YxXC8iLCJTb2NrZXQiOiJ3c3M6XC9cL2M1MD + E2LmJpdWtvcC5jb20uYXU6ODA4MFwvYXBpXC92MVwvd3MiLCJTZXN + zaW9uS2V5Ijoic2siLCJWZXJzaW9uIjoyMDIxfQ== - - -