UNPKG

anonymous-student

Version:

Anonymous student is used to retrieve and save information from our website users.

147 lines (119 loc) 5.44 kB
import { IEventAggregationService, ISubscriber } from "@studyportals/event-aggregation-service-interface"; import { WebsocketServiceReadyEvent } from '@studyportals/student-interfaces'; import { IStudent, StudentField } from '@studyportals/studentdomain'; import { StudentRepositoryStateType } from '../../../interfaces/enumerations'; import { AnonymousStudentProfileUpdated } from '../../../interfaces/events'; import { CatchReportAsyncException } from '../../decorators/error-decorators'; import { AnonymousStudentEventBroadcaster } from '../anonymous-student-event-broadcaster'; import { LastStateChangeHash, StudentClient } from '../interfaces/student-client'; import { IStudentProfileChanged } from '../student-profile-changed.inferface'; import { LocalStudentClient } from './local-student-client'; import { StudentAPIClient } from './student-api-client'; export class CachedStudentClient implements StudentClient, ISubscriber<WebsocketServiceReadyEvent | IStudentProfileChanged> { private localStateHashes: LastStateChangeHash[]; constructor( private studentAPIClient: StudentAPIClient, private localStudentClient: LocalStudentClient, private eventAggregationService: IEventAggregationService, private anonymousStudentEventBroadcaster: AnonymousStudentEventBroadcaster ) { this.eventAggregationService.subscribeTo(WebsocketServiceReadyEvent.EventType, this, true); this.localStateHashes = []; } @CatchReportAsyncException public async notify(event: WebsocketServiceReadyEvent | IStudentProfileChanged): Promise<void> { if (event.eventType === WebsocketServiceReadyEvent.EventType) { this.handleWebsocketServiceReadyEvent(event as WebsocketServiceReadyEvent); } if (event.eventType === 'StudentProfileChanged') { await this.handleWebsocketEvent(event as IStudentProfileChanged); } } private handleWebsocketServiceReadyEvent(event: WebsocketServiceReadyEvent): void { event.webSocketService.subscribeToWebSocketEvent('StudentProfileChanged', this); } private async handleWebsocketEvent(event: IStudentProfileChanged): Promise<void> { const changes: IStudent = this.transformStudentProfileChangedEventIntoStudentData(event); const timestamp: Date = new Date(event.eventTimestamp); const isLocalUpdate: boolean = this.localStateHashes.includes(event.updated?.[StudentField.LAST_STATE_CHANGE_HASH]); await this.updateDataFromEvent(changes); const anonymousEvent = new AnonymousStudentProfileUpdated( timestamp, StudentRepositoryStateType.ONLINE, changes, isLocalUpdate ); this.anonymousStudentEventBroadcaster.broadcastProfileUpdatedEvent(anonymousEvent); } private isForceUpdateField(studentField: StudentField): boolean { return [ StudentField.DISCIPLINES, StudentField.INTERESTS_COUNTRIES, StudentField.INTERESTS_DISCIPLINES, StudentField.TUITION_BUDGET, StudentField.LIVING_BUDGET, StudentField.ATTENDANCE ].includes(studentField); } private async updateDataFromEvent(studentData: IStudent): Promise<void> { const studentFieldsWithPartialData: StudentField[] = []; Object.keys(studentData).forEach((studentField: StudentField) => { if (studentData[studentField] instanceof Object || this.isForceUpdateField(studentField)) { studentFieldsWithPartialData.push(studentField); } }); const studentDataForObjects = await this.studentAPIClient.getData(studentFieldsWithPartialData); await this.localStudentClient.setData({ ...studentData, ...studentDataForObjects }); } private transformStudentProfileChangedEventIntoStudentData(event: IStudentProfileChanged): IStudent { const changes: IStudent = {}; if (event.updated) { Object.keys(event.updated).forEach((key) => { changes[key] = event.updated[key]; }); } if (event.deleted) { Object.keys(event.deleted).forEach((key) => { changes[key] = undefined; }); } return changes; } public async addToCollection(type: StudentField, items: any[]): Promise<void> { const lastStateChangeHash = await this.studentAPIClient.addToCollection(type, items); if (lastStateChangeHash) { this.localStateHashes.push(lastStateChangeHash); } await this.localStudentClient.addToCollection(type, items); } public async removeFromCollection(type: StudentField, items: any[]): Promise<void> { const lastStateChangeHash = await this.studentAPIClient.removeFromCollection(type, items); if (lastStateChangeHash) { this.localStateHashes.push(lastStateChangeHash); } await this.localStudentClient.removeFromCollection(type, items); } public async getData(studentFields: StudentField[]): Promise<IStudent> { const localData = await this.localStudentClient.getData(studentFields); const localKeys = Object.keys(localData); const missingFields = studentFields.filter((field) => { return !localKeys.includes(field); }); if (missingFields.length > 0) { const remoteData = await this.studentAPIClient.getData(missingFields); await this.localStudentClient.setData(remoteData); return { ...localData, ...remoteData }; } return localData; } public async setData(studentData: IStudent): Promise<void> { const lastStateChangeHash = await this.studentAPIClient.setData(studentData); if (lastStateChangeHash) { this.localStateHashes.push(lastStateChangeHash); } await this.localStudentClient.setData(studentData); } public clearCache(): void { return this.localStudentClient.cleanUp(); } }