This commit is contained in:
Peter Maquiran
2024-08-30 12:41:50 +01:00
parent ac7e5ccf5b
commit d6a08c6264
33 changed files with 558 additions and 87 deletions
+11
View File
@@ -142,6 +142,7 @@
"cross-env": "^7.0.3",
"crypto-js": "^4.0.0",
"date-fns": "^2.17.0",
"deep-object-diff": "^1.1.9",
"depd": "^2.0.0",
"dexie": "^4.0.7",
"dompurify": "^3.0.6",
@@ -14652,6 +14653,11 @@
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="
},
"node_modules/deep-object-diff": {
"version": "1.1.9",
"resolved": "https://registry.npmjs.org/deep-object-diff/-/deep-object-diff-1.1.9.tgz",
"integrity": "sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA=="
},
"node_modules/deepmerge": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
@@ -55393,6 +55399,11 @@
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="
},
"deep-object-diff": {
"version": "1.1.9",
"resolved": "https://registry.npmjs.org/deep-object-diff/-/deep-object-diff-1.1.9.tgz",
"integrity": "sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA=="
},
"deepmerge": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+1
View File
@@ -161,6 +161,7 @@
"cross-env": "^7.0.3",
"crypto-js": "^4.0.0",
"date-fns": "^2.17.0",
"deep-object-diff": "^1.1.9",
"depd": "^2.0.0",
"dexie": "^4.0.7",
"dompurify": "^3.0.6",
+30
View File
@@ -0,0 +1,30 @@
import { object, z } from 'zod';
import { MessageEntitySchema } from './message';
import { BaseEntity } from 'src/app/utils/entity';
const DistributionEntitySchema = z.object({
$messageIdMemberId: z.string().optional(),
messageId: z.string(),
memberId: z.number(),
readAt: z.string().nullable(),
deliverAt: z.string().nullable(),
roomId: z.string(),
})
export type IDistribution = z.infer<typeof DistributionEntitySchema>
export class DistributionEntity extends BaseEntity<DistributionEntity>(DistributionEntitySchema) implements IDistribution{
roomId: typeof DistributionEntitySchema._input.roomId
readAt: typeof DistributionEntitySchema._input.readAt
messageId: typeof DistributionEntitySchema._input.messageId
memberId: typeof DistributionEntitySchema._input.memberId
deliverAt: typeof DistributionEntitySchema._input.deliverAt
constructor(data: IDistribution) {
super();
Object.assign(this, data)
}
}
+3 -1
View File
@@ -1,4 +1,5 @@
import { SessionStore } from "src/app/store/session.service";
import { BaseEntity } from "src/app/utils/entity";
import { z } from "zod"
export enum RoomType {
@@ -37,7 +38,7 @@ export const RoomEntitySchema = z.object({
export type IRoomEntity = z.infer<typeof RoomEntitySchema>
export class RoomEntity implements IRoomEntity{
export class RoomEntity extends BaseEntity<RoomEntity>(RoomEntitySchema) implements IRoomEntity{
id: typeof RoomEntitySchema._input.id
roomName: typeof RoomEntitySchema._input.roomName
@@ -48,6 +49,7 @@ export class RoomEntity implements IRoomEntity{
members: typeof RoomEntitySchema._input.members
constructor(data: IRoomEntity) {
super();
Object.assign(this, data)
if(data.roomType == RoomType.Direct) {
this.setName()
@@ -14,7 +14,7 @@ export class GetRoomListMapper{
id: roomData.chatRoom.id,
roomName: roomData.chatRoom.roomName,
roomType: roomData.chatRoom.roomType,
members: [roomData.chatRoom.user1, roomData.chatRoom.user2].filter((e) => e?.wxUserId).map((b) => ({
members: [ roomData.chatRoom.user2, roomData.chatRoom.user1].filter((e) => e?.wxUserId).map((b) => ({
id: '',
isAdmin: false,
joinAt: '',
@@ -0,0 +1,7 @@
import { BoldTable } from "src/app/infra/database/dexie/instance/chat/schema/bold";
import { DexieRepository } from "src/app/infra/repository/dexie/dexie-repository.service";
export abstract class IBoldLocalRepository extends DexieRepository<BoldTable, BoldTable> implements IBoldLocalRepository {
}
@@ -0,0 +1,9 @@
import { DistributionTable, DistributionTableSchema } from "src/app/infra/database/dexie/instance/chat/schema/destribution";
import { chatDatabase } from "src/app/infra/database/dexie/service";
import { DexieRepository } from "src/app/infra/repository/dexie/dexie-repository.service";
export abstract class IDistributionLocalRepository extends DexieRepository<DistributionTable, DistributionTable> implements IDistributionLocalRepository {
}
@@ -0,0 +1,11 @@
import { EntityTable } from 'Dexie';
import { z } from 'zod';
export const BoldTableSchema = z.object({
roomId: z.string(),
bold: z.number()
})
export type BoldTable = z.infer<typeof BoldTableSchema>
export type DexieBoldTable = EntityTable<BoldTable, 'roomId'>;
export const BoldTableColumn = 'roomId, bold'
@@ -2,12 +2,14 @@ import { EntityTable } from 'Dexie';
import { z } from 'zod';
export const DistributionTableSchema = z.object({
$id: z.string(),
$messageIdMemberId: z.string().optional(),
messageId: z.string(),
memberId: z.number(),
readAt: z.string().nullable(),
deliverAt: z.string().nullable()
deliverAt: z.string().nullable(),
roomId: z.string(),
})
export type DistributionTable = z.infer<typeof DistributionTableSchema>
export type DexieDistributionTable = EntityTable<DistributionTable, '$id'>;
export const DistributionTableColumn = '++$id, messageId, memberId, readAt, deliverAt'
export type DexieDistributionTable = EntityTable<DistributionTable, '$messageIdMemberId'>;
export const DistributionTableColumn = '$messageIdMemberId, messageId, memberId, readAt, deliverAt, roomId'
+7 -1
View File
@@ -6,6 +6,8 @@ import { DexieRoomsTable, RoomTableColumn } from 'src/app/infra/database/dexie/i
import { DexieTypingsTable, TypingTableColumn } from 'src/app/infra/database/dexie/instance/chat/schema/typing';
import { MessageEntity } from 'src/app/core/chat/entity/message';
import { AttachmentTableColumn, DexieAttachmentsTableSchema } from 'src/app/infra/database/dexie/instance/chat/schema/attachment';
import { DexieDistributionTable, DistributionTable, DistributionTableColumn } from './instance/chat/schema/destribution';
import { BoldTableColumn, DexieBoldTable } from './instance/chat/schema/bold';
// import FDBFactory from 'fake-indexeddb/lib/FDBFactory';
// import FDBKeyRange from 'fake-indexeddb/lib/FDBKeyRange';
@@ -20,6 +22,8 @@ export const chatDatabase = new Dexie('chat-database-infra',{
room: DexieRoomsTable,
typing: DexieTypingsTable,
attachment: DexieAttachmentsTableSchema,
distribution: DexieDistributionTable,
bold: DexieBoldTable
};
chatDatabase.version(1).stores({
@@ -27,7 +31,9 @@ chatDatabase.version(1).stores({
members: MemberTableColumn,
room: RoomTableColumn,
typing: TypingTableColumn,
attachment: AttachmentTableColumn
attachment: AttachmentTableColumn,
distribution: DistributionTableColumn,
bold:BoldTableColumn
});
chatDatabase.message.mapToClass(MessageEntity)
@@ -77,6 +77,28 @@ export class DexieRepository<T, R> implements IDexieRepository<T, R> {
}
}
async updateMany(updatedDocument: Partial<T>[]) {
const schema = this.ZodSchema.array()
const dataValidation = schema.safeParse(updatedDocument)
if(dataValidation.success) {
try {
const updatedCount = await this.table.bulkPut(dataValidation.data);
return ok(updatedCount);
} catch (error) {
return err(new Error('Failed to update document: ' + error.message));
}
} else {
Logger.error(`dexie.js failed to update many into ${this.table.name}, invalid data`, {
data: document,
zodError: dataValidation.error.issues
});
return err((dataValidation as unknown as ZodError<T>))
}
}
async delete(id: any): Promise<RepositoryResult<void, T>> {
try {
await this.table.delete(id);
+19 -2
View File
@@ -10,7 +10,7 @@ import { RoomService } from 'src/app/module/chat/domain/service/room.service'
import { HttpListenToMessageLoadHistoryAdapter } from './domain/adapter';
import { ISignalRService } from 'src/app/infra/socket/adapter';
import { HttpModule } from 'src/app/infra/http/http.module';
import { HttpListenToMessageLoadHistoryUseCase } from 'src/app/core/chat/usecase/message/http-listen-to-message-load-history-use-case';
import { HttpListenToMessageLoadHistoryUseCase } from 'src/app/core/chat/usecase/message/http-listen-to-message-load-history-by-roomId-use-case';
import { IMessageLocalRepository } from 'src/app/core/chat/repository/message/message-local-repository';
import { MessageLocalDataSourceService } from './data/repository/message/message-local-data-source.service';
import { MessageRemoteDataSourceService } from './data/repository/message/message-remote-data-source.service';
@@ -31,6 +31,12 @@ import { IAttachmentLocalRepository } from 'src/app/core/chat/repository/typing/
import { AttachmentLocalDataSource } from './data/repository/attachment/attachment-local-repository.service';
import { IAttachmentRemoteRepository } from 'src/app/core/chat/repository/attachment/attachment-remote-repository';
import { AttachmentRemoteDataSourceService } from './data/repository/attachment/attachment-remote-repository.service';
import { IDistributionLocalRepository } from 'src/app/core/chat/repository/distribution/distribution-local-repository';
import { DistributionLocalRepository } from './data/repository/destribution/destribution-local-repository';
import { DistributionService } from './domain/service/distribution.service'
import { BoldLocalRepository } from './data/repository/bold/bold-local-repository';
import { IBoldLocalRepository } from 'src/app/core/chat/repository/bold/bold-local-repository';
import { BoldService } from 'src/app/module/chat/domain/service/bold.service'
@NgModule({
imports: [HttpModule],
providers: [
@@ -86,6 +92,15 @@ import { AttachmentRemoteDataSourceService } from './data/repository/attachment/
provide: IAttachmentRemoteRepository,
useClass: AttachmentRemoteDataSourceService
},
//
{
provide: IDistributionLocalRepository,
useClass: DistributionLocalRepository
},
{
provide: IBoldLocalRepository,
useClass: BoldLocalRepository
}
],
declarations: [],
schemas: [],
@@ -101,7 +116,9 @@ export class ChatModule {
private signalR: SignalRService,
private localDataSource: UserTypingLocalRepository,
private UserTypingRemoteRepositoryService: UserTypingRemoteRepositoryService,
private RoomService: RoomService
private RoomService: RoomService,
private DistributionService: DistributionService,
private BoldService: BoldService
) {
this.RoomService.init()
@@ -0,0 +1,29 @@
import { DistributionTable } from "src/app/infra/database/dexie/instance/chat/schema/destribution";
import { DistributionOutPutDTO } from "src/app/module/chat/domain/service/distribution.service";
export function distributionListDetermineChanges(____serverDistributions: DistributionOutPutDTO[], localDistributions: DistributionTable[], messageId: string) {
const serverDistribution = ____serverDistributions.map( e=> {
return {
...e,
$messageIdMemberId: messageId + e.memberId
}
})
const serverDistributionMap = new Map(serverDistribution.map(distribution => [distribution.$messageIdMemberId, distribution]));
const localDistributionMap = new Map(localDistributions.map(distribution => [distribution.$messageIdMemberId, distribution]));
const distributionToInsert = serverDistribution.filter(distribution => !localDistributionMap.has(distribution.$messageIdMemberId));
const distributionToUpdate = serverDistribution.filter(distribution => {
const localDistribution = localDistributionMap.get(distribution.$messageIdMemberId);
return localDistribution && (
distribution.deliverAt !== localDistribution.deliverAt ||
distribution.readAt !== localDistribution.readAt
)
});
const distributionToDelete = localDistributions.filter(distribution => !serverDistributionMap.has(distribution.$messageIdMemberId));
return { distributionToInsert, distributionToUpdate, distributionToDelete };
}
@@ -0,0 +1,33 @@
import { RoomTable } from "src/app/infra/database/dexie/instance/chat/schema/room";
import { RoomByIdOutputDTO } from "src/app/module/chat/domain/use-case/room/room-get-by-id-use-case.service";
import { RoomListItemOutPutDTO } from "src/app/module/chat/domain/use-case/room/room-get-list-use-case.service";
export function roomByIdDetermineChanges(serverResponse: RoomByIdOutputDTO, localRooms: RoomTable[]) {
const localRoomMap = new Map(localRooms.map(room => [room.id, room]));
let roomsToInsert:RoomByIdOutputDTO | undefined;
let roomsToUpdate: RoomByIdOutputDTO | undefined;
const fond = localRooms.filter(room => !localRoomMap.has(serverResponse.data.id));
if(!fond) {
roomsToInsert = serverResponse
}
const needToUpdate = localRooms.filter(room => {
const localRoom = localRoomMap.get(room.id);
return localRoom && (
room.roomName !== serverResponse.data.roomName ||
room.createdBy.wxUserId !== serverResponse.data.createdBy.wxUserId ||
room.createdAt !== serverResponse.data.createdAt ||
room.expirationDate !== serverResponse.data.expirationDate // ||
// room.chatRoom.roomType !== localRoom.roomType
);
});
if(needToUpdate) {
roomsToUpdate = serverResponse
}
return { roomsToInsert, roomsToUpdate };
}
@@ -1,3 +1,4 @@
import { RoomType } from "src/app/core/chat/entity/group";
import { RoomTable } from "src/app/infra/database/dexie/instance/chat/schema/room";
import { RoomListItemOutPutDTO } from "src/app/module/chat/domain/use-case/room/room-get-list-use-case.service";
@@ -8,8 +9,9 @@ export function roomListDetermineChanges(serverRooms: RoomListItemOutPutDTO[], l
const roomsToInsert = serverRooms.filter(room => !localRoomMap.has(room.chatRoom.id));
const roomsToUpdate = serverRooms.filter(room => {
const localRoom = localRoomMap.get(room.chatRoom.id);
return localRoom && (
room.chatRoom.roomName !== localRoom.roomName ||
room.chatRoom.roomName !== localRoom.roomName && room.chatRoom.roomType == RoomType.Group ||
room.chatRoom.createdBy.wxUserId !== localRoom.createdBy.wxUserId ||
room.chatRoom.createdAt !== localRoom.createdAt ||
room.chatRoom.expirationDate !== localRoom.expirationDate // ||
@@ -0,0 +1,20 @@
import { Injectable } from '@angular/core';
import { from } from "rxjs";
import { DexieRepository } from "src/app/infra/repository/dexie/dexie-repository.service";
import { Dexie, EntityTable, liveQuery, Observable } from 'Dexie';
import { BoldTable, BoldTableSchema } from "src/app/infra/database/dexie/instance/chat/schema/bold";
import { chatDatabase } from "src/app/infra/database/dexie/service";
import { IBoldLocalRepository } from "src/app/core/chat/repository/bold/bold-local-repository";
@Injectable({
providedIn: 'root'
})
export class BoldLocalRepository extends DexieRepository<BoldTable, BoldTable> implements IBoldLocalRepository {
constructor() {
super(chatDatabase.bold, BoldTableSchema)
}
listen() {
return from(liveQuery(() => chatDatabase.bold.toArray()))
}
}
@@ -0,0 +1,14 @@
import { DistributionTable, DistributionTableSchema } from "src/app/infra/database/dexie/instance/chat/schema/destribution";
import { chatDatabase } from "src/app/infra/database/dexie/service";
import { DexieRepository } from "src/app/infra/repository/dexie/dexie-repository.service";
export class DistributionLocalRepository extends DexieRepository<DistributionTable, DistributionTable> {
constructor() {
super(chatDatabase.distribution, DistributionTableSchema)
chatDatabase.distribution.hook("creating", function (primKey, obj, transaction) {
obj.$messageIdMemberId = `${obj.messageId}${obj.memberId}`
});
}
}
+1 -1
View File
@@ -2,7 +2,7 @@ import { HttpErrorResponse } from "@angular/common/http";
import { Result } from "neverthrow";
import { Observable } from "rxjs";
import { MessageEntity } from "src/app/core/chat/entity/message";
import { HttpListenToMessageLoadHistoryUseCaseInput } from "src/app/core/chat/usecase/message/http-listen-to-message-load-history-use-case";
import { HttpListenToMessageLoadHistoryUseCaseInput } from "src/app/core/chat/usecase/message/http-listen-to-message-load-history-by-roomId-use-case";
import { HttpResult } from "src/app/infra/http/type";
import { UseCase } from "src/app/utils/use-case-interface";
import { IMessageGetAllByRoomIdOutPut } from 'src/app/core/chat/usecase/message/message-get-all-by-room-Id'
@@ -36,10 +36,10 @@ import { MessageAttachmentByMessageIdInput, MessageAttachmentByMessageIdUseCase
import { AddMemberToRoomInputDTO, AddMemberToRoomInputDTOSchema } from '../domain/use-case/member/member-add-use-case.service';
import { RoomType } from "src/app/core/chat/entity/group";
import { HttpListenToMessageLoadHistoryAdapter } from './adapter'
import { HttpListenToMessageLoadHistoryUseCaseInput } from 'src/app/core/chat/usecase/message/http-listen-to-message-load-history-use-case';
import { HttpListenToMessageLoadHistoryUseCaseInput } from 'src/app/core/chat/usecase/message/http-listen-to-message-load-history-by-roomId-use-case';
import { MessageSocketRepositoryService } from 'src/app/module/chat/data/repository/message/message-live-signalr-data-source.service'
import { MessageMarkAsReadInput } from "src/app/module/chat/domain/use-case/message/message-mark-as-read-use-case.service";
import { BoldRemoveByRoomIdInput, BoldRemoveByRoomIdService } from 'src/app/module/chat/domain/use-case/bold/bold-remove-by-room-id.service'
export const InstanceId = uuidv4();
@Injectable({
@@ -80,6 +80,7 @@ export class ChatServiceService {
private MessageMarkAllMessageAsReadByRoomIdService: MessageMarkAllMessageAsReadByRoomIdService,
private HttpListenToMessageLoadHistory: HttpListenToMessageLoadHistoryAdapter,
private MessageSocketRepositoryService: MessageSocketRepositoryService,
private BoldRemoveByRoomIdService: BoldRemoveByRoomIdService
) {
this.MessageSocketRepositoryService.listenToDeleteMessages()
.pipe()
@@ -182,6 +183,9 @@ export class ChatServiceService {
// return this.GetMessageAttachmentLocallyUseCaseService.execute(input)
// }
removeBoldFromRoom(input: BoldRemoveByRoomIdInput) {
return this.BoldRemoveByRoomIdService.execute(input)
}
listenToMessageLoadHistory(input: HttpListenToMessageLoadHistoryUseCaseInput) {
return this.HttpListenToMessageLoadHistory.execute(input)
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { BoldService } from './bold.service';
describe('BoldService', () => {
let service: BoldService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(BoldService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,37 @@
import { Injectable } from '@angular/core';
import { filter, map } from 'rxjs/operators';
import { IMessageSocketRepository } from 'src/app/core/chat/repository/message/message-socket-repository';
import { InstanceId } from '../chat-service.service';
import { MessageEntity } from 'src/app/core/chat/entity/message';
import { IBoldLocalRepository } from 'src/app/core/chat/repository/bold/bold-local-repository';
@Injectable({
providedIn: 'root'
})
export class BoldService {
constructor(
private MessageSocketRepositoryService: IMessageSocketRepository,
private boldLocalRepository: IBoldLocalRepository
) {
this.listenToIncomingMessage();
}
listenToIncomingMessage() {
return this.MessageSocketRepositoryService.listenToMessages().pipe(
filter((message) => !message?.requestId?.startsWith(InstanceId)),
map(message => Object.assign(new MessageEntity(), message))
).subscribe(async (message) => {
const result = await this.boldLocalRepository.findOne({roomId: message.roomId})
if(result.isOk() && !result.value) {
const result = await this.boldLocalRepository.insert({roomId: message.roomId, bold: 1})
} else if(result.isOk() && result.value.bold == 0) {
const result = await this.boldLocalRepository.update(message.roomId, {bold: 1})
}
});
}
}
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { DistributionService } from './distribution.service';
describe('DistributionService', () => {
let service: DistributionService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(DistributionService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,87 @@
import { Injectable } from '@angular/core';
import { filter, map } from 'rxjs/operators';
import { IMessageGetAllByRoomIdOutPut } from 'src/app/core/chat/usecase/message/message-get-all-by-room-Id';
import { HttpAdapter } from 'src/app/infra/http/adapter';
import { IDistributionLocalRepository } from 'src/app/core/chat/repository/distribution/distribution-local-repository'
import { z } from 'zod';
import { distributionListDetermineChanges } from '../../data/async/list/rooms/distributionListChangedetector';
import { DistributionEntity } from 'src/app/core/chat/entity/distribution';
export const DistributionOutPutDTOSchema = z.object({
$messageIdMemberId: z.string(),
memberId: z.number(),
readAt: z.string().nullable(),
deliverAt: z.string().nullable()
})
export type DistributionOutPutDTO = z.infer<typeof DistributionOutPutDTOSchema>
@Injectable({
providedIn: 'root'
})
export class DistributionService {
constructor(
private http: HttpAdapter,
private distributionLocalRepository: IDistributionLocalRepository
) {
// this.listenToLoadHistory()
}
listenToLoadHistory() {
return this.http.listen().pipe(
filter((response)=> {
if(response?.isOk()) {
return response.value.url.endsWith('Messages')
}
return false
}),
map((response: any) => response.value.data as IMessageGetAllByRoomIdOutPut)
)
.subscribe(async (data) => {
const localList = await this.distributionLocalRepository.find({roomId: data.data[0].roomId})
data.data.map(async (message) => {
const serverList = message.info
if(localList.isOk() && localList.value) {
// const localListForCurrentMessage = localList.value.filter((e) => e.messageId == message.id)
// console.log('localListForCurrentMessage', localListForCurrentMessage)
// const { distributionToInsert, distributionToUpdate, distributionToDelete } = await distributionListDetermineChanges(serverList, localListForCurrentMessage, message.id)
// console.log({distributionToInsert, distributionToUpdate, distributionToDelete})
// const map = distributionToInsert.map((e) => {
// e.
// })
// this.distributionLocalRepository.insertMany(distributionToInsert)
// const distributionEntityToInsert = distributionToInsert.map((ee)=> {
// return new DistributionEntity({
// roomId: message.roomId,
// deliverAt: ee.deliverAt,
// memberId: ee.memberId,
// messageId: message.roomId,
// readAt: ee.readAt,
// })
// console.log('create')
// })
// if(distributionEntityToInsert.length >= 0) {
// // console.log('distributionEntityToInsert', distributionEntityToInsert)
// //this.distributionLocalRepository.insertMany(distributionEntityToInsert)
// }
}
})
})
}
}
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { BoldRemoveByRoomIdService } from './bold-remove-by-room-id.service';
describe('BoldRemoveByRoomIdService', () => {
let service: BoldRemoveByRoomIdService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(BoldRemoveByRoomIdService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,33 @@
import { Injectable } from '@angular/core';
import { IBoldLocalRepository } from 'src/app/core/chat/repository/bold/bold-local-repository';
import { TracingType, XTracerAsync } from 'src/app/services/monitoring/opentelemetry/tracer';
import { zodSafeValidation } from 'src/app/utils/zodValidation';
import { z } from 'zod';
const BoldRemoveByRoomIdInputSchema = z.object({
roomId: z.string()
})
export type BoldRemoveByRoomIdInput = z.infer<typeof BoldRemoveByRoomIdInputSchema>
@Injectable({
providedIn: 'root'
})
export class BoldRemoveByRoomIdService {
constructor(
private boldLocalRepository: IBoldLocalRepository
) { }
@XTracerAsync({name:'BoldRemoveByRoomIdService', module:'chat', bugPrint: true})
async execute(input: BoldRemoveByRoomIdInput, tracing?: TracingType) {
const validation = zodSafeValidation<any>(BoldRemoveByRoomIdInputSchema, input)
if(validation.isOk()) {
return await this.boldLocalRepository.delete(input.roomId)
} else {
tracing.hasError("invalid parameter")
}
}
}
@@ -10,8 +10,11 @@ import { IRoomRemoteRepository } from 'src/app/core/chat/repository/room/room-re
import { IMemberLocalRepository } from 'src/app/core/chat/repository/member/member-local-repository';
import { IRoomLocalRepository } from 'src/app/core/chat/repository/room/room-local-repository';
import { GetRoomByIdMapper } from 'src/app/core/chat/mapper/getRoomByIdMapper';
import { RoomEntity } from 'src/app/core/chat/entity/group';
import { RoomEntity, RoomType } from 'src/app/core/chat/entity/group';
import { GetRoomListMapper } from 'src/app/core/chat/mapper/getRoomListMapper';
import { roomByIdDetermineChanges } from '../../../data/async/list/rooms/roomByIdChangeDetector';
import { diff, addedDiff, deletedDiff, updatedDiff, detailedDiff } from 'deep-object-diff';
import { zodSafeValidation } from 'src/app/utils/zodValidation';
const UserSchema = z.object({
wxUserId: z.number(),
@@ -56,7 +59,6 @@ export class GetRoomByIdUseCaseService {
constructor(
private roomRemoteDataSourceService: IRoomRemoteRepository,
// private roomMemoryDataSourceService: Store<RoomRemoteDataSourceState>,
private roomLocalDataSourceService: IRoomLocalRepository,
private MemberListLocalRepository: IMemberLocalRepository
) { }
@@ -66,71 +68,63 @@ export class GetRoomByIdUseCaseService {
const result = await this.roomRemoteDataSourceService.getRoom(id)
if(result.isOk()) {
const validData = zodSafeValidation<RoomByIdOutputDTO>(RoomByIdOutputDTOSchema, result.value)
const localListRoom = await this.roomLocalDataSourceService.findAll()
if(localListRoom.isOk()) {
const object = {
chatRoom: result.value.data
}
const { roomsToInsert, roomsToUpdate } = roomListDetermineChanges([object], localListRoom.value)
if(validData.isOk()) {
const localListRoom = await this.roomLocalDataSourceService.findAll()
if(localListRoom.isOk()) {
if(roomsToUpdate) {
const getRoomById = await this.roomLocalDataSourceService.findOne({id:validData.value.data.id})
if(getRoomById.isOk() && getRoomById.value) {
console.log(validData.value)
const room = GetRoomByIdMapper.toDomain(validData.value)
const roomsToUpdateEntity = GetRoomListMapper.toDomain(roomsToUpdate)
for( const room of roomsToUpdateEntity) {
this.roomLocalDataSourceService.update(room.id, room)
if(room.expirationDate) {
console.log('room expiration date schedule')
// this.CronJobService.createCronJob('remove expired room', new Date(room.expirationDate), this.execute)
const added: Partial<RoomEntity> = addedDiff(getRoomById.value, room);
const deleted: Partial<RoomEntity> = deletedDiff(getRoomById.value, room);
const updated: Partial<RoomEntity> = updatedDiff(getRoomById.value, room);
delete added.members
if(room.roomType == RoomType.Direct) {
delete updated.roomName
}
}
}
if(roomsToInsert) {
if(Object.keys(added).length >= 1 || Object.keys(updated).length >= 1) {
console.log('added', added);
console.log('deleted', deleted);
console.log('updated', updated);
this.roomLocalDataSourceService.update(room.id, room)
}
const roomsToInsertEntity = GetRoomListMapper.toDomain(roomsToInsert)
for( const room of roomsToInsertEntity) {
} else if (getRoomById.isOk() && !getRoomById.value) {
console.log(validData.value)
const room = GetRoomByIdMapper.toDomain(validData.value)
this.roomLocalDataSourceService.insert(room)
if(room.expirationDate) {
console.log('room expiration date schedule')
// this.CronJobService.createCronJob('remove expired room', new Date(room.expirationDate), this.execute)
}
}
// ============================
const localList = await this.MemberListLocalRepository.getRoomMemberById(id)
const { membersToInsert, membersToUpdate, membersToDelete } = roomMemberListDetermineChanges(validData.value.data.members, localList, id)
for (const user of membersToInsert) {
await this.MemberListLocalRepository.addMember(MemberListMapper(user, id))
}
for (const user of membersToUpdate) {
await this.MemberListLocalRepository.updateMemberRole(MemberListMapper(user, id))
}
for(const user of membersToDelete) {
await this.MemberListLocalRepository.removeMemberFromRoom(user.$roomIdUserId)
}
}
} else {
// for( const roomData of roomsToUpdate) {
// const room = new RoomEntity({
// createdAt: result.value.data.createdAt,
// createdBy: result.value.data.createdBy,
// expirationDate: result.value.data.expirationDate,
// id: result.value.data.id,
// members: result.value.data.members,
// roomName: result.value.data.roomName,
// roomType: result.value.data.roomType,
// })
// this.roomLocalDataSourceService.update(room.id, room)
// }
// ============================
const localList = await this.MemberListLocalRepository.getRoomMemberById(id)
const { membersToInsert, membersToUpdate, membersToDelete } = roomMemberListDetermineChanges(result.value.data.members, localList, id)
for (const user of membersToInsert) {
await this.MemberListLocalRepository.addMember(MemberListMapper(user, id))
}
for (const user of membersToUpdate) {
await this.MemberListLocalRepository.updateMemberRole(MemberListMapper(user, id))
}
for(const user of membersToDelete) {
await this.MemberListLocalRepository.removeMemberFromRoom(user.$roomIdUserId)
}
}
} else if (isHttpResponse(result.error) ) {
if(result.error.status == 404) {
await this.roomLocalDataSourceService.delete(id)
@@ -80,9 +80,7 @@ export class GetRoomListUseCaseService {
}
const roomsToUpdateEntity = GetRoomListMapper.toDomain(roomsToUpdate)
for( const room of roomsToUpdateEntity) {
this.roomLocalDataSourceService.update(room.id, room)
}
this.roomLocalDataSourceService.updateMany(roomsToUpdateEntity)
for( const room of roomsToDelete) {
this.roomLocalDataSourceService.delete(room.id)
+5
View File
@@ -21,6 +21,8 @@ import { MessagesPageModule } from './component/messages/messages.module';
import { ContactsPageModule } from './component/contacts/contacts.module';
import { NewGroupPageModule } from './component/new-group/new-group.module';
import { ChatModule } from 'src/app/module/chat/chat.module';
import { IBoldLocalRepository } from 'src/app/core/chat/repository/bold/bold-local-repository';
import { BoldLocalRepository } from 'src/app/module/chat/data/repository/bold/bold-local-repository';
@NgModule({
imports: [
@@ -42,6 +44,9 @@ import { ChatModule } from 'src/app/module/chat/chat.module';
ImageCropperModule,
AttendeeModalPageModule,
ChatModule
],
providers: [
],
declarations: [
ChatPage
+2 -2
View File
@@ -61,7 +61,7 @@
<ion-label >
<span >
<div >
<div class="font-15-em" [class.bold-message]="true">
<div class="font-15-em" [class.bold-message]="boldTable?.[room.id]?.bold">
{{room.roomName}}
</div>
</div>
@@ -99,7 +99,7 @@
<ion-label >
<span >
<div >
<div class="font-15-em" [class.bold-message]="true">
<div class="font-15-em" [class.bold-message]="boldTable?.[room.id]?.bold">
{{room.roomName}}
</div>
</div>
+17 -5
View File
@@ -23,7 +23,8 @@ import { map, tap } from 'rxjs/operators';
import { interval, Subscription } from 'rxjs';
import { RoomTable } from 'src/app/infra/database/dexie/instance/chat/schema/room';
import { RoomType } from 'src/app/core/chat/entity/group';
import { BoldLocalRepository } from 'src/app/module/chat/data/repository/bold/bold-local-repository'
import { BoldTable } from 'src/app/infra/database/dexie/instance/chat/schema/bold';
@Component({
selector: 'app-chat',
templateUrl: './chat.page.html',
@@ -64,6 +65,8 @@ export class ChatPage implements OnInit {
RoomType = RoomType
boldTable: {[key: string]: BoldTable} = {}
constructor(
private modalController: ModalController,
private timeService: TimeService,
@@ -73,18 +76,27 @@ export class ChatPage implements OnInit {
public RouteService: RouteService,
private ChatServiceService: ChatServiceService,
private roomLocalDataSourceService: RoomLocalRepository,
private chatServiceService: ChatServiceService
private boldLocalRepository: BoldLocalRepository
) {
window.onresize = (event) => {
if (window.innerWidth > 701) {
this.modalController.dismiss();
}
};
}
this.showLoader = true;
this.boldLocalRepository.listen().subscribe((data) => {
const distributionObject: {[key: string]: BoldTable} = {};
for (const distribution of data) {
distributionObject[distribution.roomId] = distribution;
}
this.boldTable = distributionObject
})
}
// Fetch all items using useLiveQuery
@@ -127,7 +139,7 @@ export class ChatPage implements OnInit {
this.routerSubscription = this.router.events.subscribe((event) => {
if (event instanceof NavigationEnd && event.url.startsWith('/home/chat')) {
this.routeCheck()
this.ChatServiceService.getRoomList()
// this.ChatServiceService.getRoomList()
}
});
@@ -275,7 +275,7 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
}) as any
this.chatServiceService.removeBoldFromRoom({roomId: this.roomId})
}
messageStatus(message: MessageEntity) {
@@ -422,7 +422,10 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
setTimeout(() => {
this.scrollToBottomClicked()
}, 100)
this.chatServiceService.removeBoldFromRoom({roomId: this.roomId})
});
}
listenToDeleteMessage() {
+34
View File
@@ -0,0 +1,34 @@
import { v4 as uuidv4 } from 'uuid';
import { ZodSchema, ZodType } from 'zod';
// export interface IEntity {
// id: string;
// createdAt: Date;
// updatedAt: Date;
// deletedAt?: Date;
// }
export const BaseEntity = <T>(schema: ZodSchema) => {
abstract class Entity {
readonly id: string;
readonly createdAt: Date;
readonly updatedAt: Date;
deletedAt?: Date;
static nameOf = (name: keyof T) => name;
validate<T>(entity: T): ZodType {
return schema.parse(entity);
}
}
return Entity;
};