| @@ -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(); | |||
| } | |||
| } | |||
| @@ -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; | |||
| } | |||
| @@ -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}[] = [ | |||
| @@ -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<void> { | |||
| MenuService, | |||
| AuthGuard, | |||
| AuthService, | |||
| SessionService, | |||
| WebSocketService, | |||
| LoanSummaryService, | |||
| LoanSingleService, | |||
| @@ -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<any>, next: HttpHandler): Observable<HttpEvent<any>> { | |||
| 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); | |||
| } | |||
| } | |||
| @@ -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); | |||
| @@ -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 + '")'; | |||
| } | |||
| } | |||
| @@ -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<RewardByUserModel[]>(this.auth.getUrl('user-reward/' + this.selectedBrokerId )).subscribe( | |||
| this.http.get<RewardByUserModel[]>(this.config.getUrl('user-reward/' + this.selectedBrokerId )).subscribe( | |||
| rsp => { | |||
| rsp.forEach(v => { | |||
| this.gridData.push(new RewardByUserModel(v)); | |||
| @@ -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 => { | |||
| @@ -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) + ')'; | |||
| } | |||
| @@ -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; | |||
| @@ -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<UserModel>) { | |||
| super(payload); | |||
| this.Role = payload.Role || 'People' as UserRoles; | |||
| this.Login = payload.Login || ''; | |||
| this.Broker = new BrokerModel(payload); | |||
| } | |||
| } | |||
| @@ -0,0 +1,15 @@ | |||
| export class WsLoginEventModel{ | |||
| T: string; | |||
| Mid: string; | |||
| Sid: string; | |||
| Uid: string; | |||
| Role: string; | |||
| constructor( payload: Partial<WsLoginEventModel>) { | |||
| this.T = payload.T || ''; | |||
| this.Mid = payload.Mid || ''; | |||
| this.Sid = payload.Sid || ''; | |||
| this.Uid = payload.Uid || ''; | |||
| this.Role = payload.Uid || ''; | |||
| } | |||
| } | |||
| @@ -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{ | |||
| @@ -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() ; | |||
| } | |||
| } | |||
| } | |||
| @@ -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 { | |||
| @@ -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 { | |||
| @@ -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 { | |||
| @@ -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 <ApiV1LoginResponse>(); | |||
| 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<ApiV1LoginResponse>(this.apiUrl + 'login', {u: email, p: password}).subscribe( | |||
| this.http.post<ApiV1LoginResponse>(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<boolean> { | |||
| return this.http.get<boolean>(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; | |||
| } | |||
| } | |||
| @@ -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 <ApiV1LoginResponse>(); | |||
| 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 | |||
| }); | |||
| } | |||
| } | |||
| @@ -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 { | |||
| @@ -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<string>{ | |||
| public ws: WebSocket; | |||
| private url: string; | |||
| private observer: Subscriber<string>; | |||
| public createObservableSocket(url: string): Observable<string> { | |||
| this.url = url; | |||
| const ret = new Observable<string> ( observer => { | |||
| this.observer = observer; | |||
| }); | |||
| private readonly url: string; | |||
| public LoginEvent: Subject<WsLoginEventModel>; | |||
| constructor(private config: AppConfig) { | |||
| super(); | |||
| this.url = config.apiWsUrl; | |||
| this.startWebsocket(); | |||
| return ret; | |||
| this.LoginEvent = new Subject<WsLoginEventModel>(); | |||
| } | |||
| // 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<string> { | |||
| // this.url = url; | |||
| // const ret = new Observable<string> ( 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); | |||
| @@ -13,21 +13,12 @@ | |||
| server="https://sc5016.biukop.com.au:8080/" | |||
| version="0.9.1" | |||
| > | |||
| eyJTZXJ2ZXIiOiJodHRwczpcL1wvYzUwMTYuYml1a29wLmNvbS5h | |||
| dTo4MDgwXC9hcGlcL3YxXC8iLCJTb2NrZXQiOiJ3c3M6XC9cL2M1 | |||
| MDE2LmJpdWtvcC5jb20uYXU6ODA4MFwvYXBpXC92MVwvd3MifQ== | |||
| eyJTZXJ2ZXIiOiJodHRwczpcL1wvYzUwMTYuYml1a29wLmNvbS5hd | |||
| To4MDgwXC9hcGlcL3YxXC8iLCJTb2NrZXQiOiJ3c3M6XC9cL2M1MD | |||
| E2LmJpdWtvcC5jb20uYXU6ODA4MFwvYXBpXC92MVwvd3MiLCJTZXN | |||
| zaW9uS2V5Ijoic2siLCJWZXJzaW9uIjoyMDIxfQ== | |||
| </script> | |||
| <app-root></app-root> | |||
| <script id="config-svr2021" type="text/biukop-config" | |||
| server="https://svr2021.lawipac.com:8080/" | |||
| version="0.9.1" | |||
| > | |||
| eyJTZXJ2ZXIiOiAiaHR0cHM6Ly9zdnIyMDIxLmxhd2lwYWMuY29tO | |||
| jgwODAvYXBpL3YxLyIsICJTb2NrZXQiOiAid3NzOi8vc3ZyMjAyMS | |||
| 5sYXdpcGFjLmNvbTo4MDgwL2FwaS92MS93cyJ9 | |||
| </script> | |||
| </body> | |||
| </html> | |||