anonymous-student
Version:
Anonymous student is used to retrieve and save information from our website users.
147 lines (119 loc) • 5.44 kB
text/typescript
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 = [];
}
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();
}
}