add error message

This commit is contained in:
Peter Maquiran
2024-06-11 11:46:04 +01:00
parent f3232c835d
commit fe51b38257
27 changed files with 675 additions and 478 deletions
@@ -16,7 +16,7 @@ export class MessageRemoteDataSourceService {
constructor(private httpService: HttpService) {}
@APIReturn(MessageOutPutDTOSchema)
@APIReturn(MessageOutPutDTOSchema, 'get/Messages')
@ValidateSchema(MessageInputDTOSchema)
async sendMessage(data: MessageInputDTO) {
return await this.httpService.post<MessageOutPutDTO>(`${this.baseUrl}/Messages`, data);
@@ -23,19 +23,19 @@ export class RoomRemoteDataSourceService {
@ValidateSchema(RoomInputDTOSchema)
@APIReturn(RoomOutPutDTOSchema)
@APIReturn(RoomOutPutDTOSchema, 'post/Room')
async createRoom(data: RoomInputDTO): DataSourceReturn<RoomOutPutDTO> {
return await this.httpService.post<RoomOutPutDTO>(`${this.baseUrl}/Room`, data);
}
@APIReturn(RoomListOutPutDTOSchema)
@APIReturn(RoomListOutPutDTOSchema, 'get/Room')
async getRoomList(): Promise<DataSourceReturn<RoomListOutPutDTO>> {
return await this.httpService.get<RoomListOutPutDTO>(`${this.baseUrl}/Room`);
}
@ValidateSchema(RoomByIdInputDTOSchema)
@APIReturn(RoomByIdOutputDTOSchema)
@APIReturn(RoomByIdOutputDTOSchema,'get/Room/${id}')
async getRoom(id: RoomByIdInputDTO): DataSourceReturn<RoomByIdOutputDTO> {
return await this.httpService.get(`${this.baseUrl}/Room/${id}`);
}
@@ -58,6 +58,16 @@ export class RoomLocalDataSourceService {
}
}
async deleteRoomById(id: string) {
try {
const result = await roomDataSource.room.delete(id)
return ok(result)
} catch (e) {
return err(false)
}
}
async updateRoom(data: TableRoom) {
try {
const result = await roomDataSource.room.update(data.id, data);
@@ -4,7 +4,8 @@ export const RoomInputDTOSchema = z.object({
roomName: z.string(),
createdBy: z.number(),
roomType: z.number(),
expirationDate: z.string().datetime().nullable()
expirationDate: z.string().datetime().nullable(),
members: z.array(z.number())
});
@@ -1,14 +1,14 @@
import { z } from "zod";
export const RoomOutPutDTOSchema = z.object({
success: z.string(),
success: z.boolean(),
message: z.string(),
data: z.object({
id: z.string(),
roomName: z.string(),
createdBy: z.any(),
createdAt: z.date(),
expirationDate: z.date(),
createdAt: z.string(),
expirationDate: z.string().nullable(),
roomType: z.any()
})
});
@@ -9,6 +9,7 @@ import { RoomByIdInputDTO } from '../dto/room/roomByIdInputDTO';
import { roomListDetermineChanges } from '../async/rooms/roomListChangeDetector';
import { UserRemoveListInputDTO } from '../dto/room/userRemoveListInputDTO';
import { roomMemberListDetermineChanges } from '../async/rooms/roomMembersChangeDetector';
import { captureAndReraiseAsync } from 'src/app/services/decorators/captureAndReraiseAsync';
@Injectable({
providedIn: 'root'
@@ -21,6 +22,7 @@ export class RoomRepositoryService {
private roomLocalDataSourceService: RoomLocalDataSourceService
) { }
@captureAndReraiseAsync('RoomRepositoryService/list')
async list() {
const result = await this.roomRemoteDataSourceService.getRoomList()
@@ -33,15 +35,25 @@ export class RoomRepositoryService {
if(result.isOk()) {
const { roomsToDelete, roomsToInsert, roomsToUpdate } = roomListDetermineChanges(result.value.data, localList)
console.log({ roomsToDelete, roomsToInsert, roomsToUpdate })
console.log({roomsToDelete, roomsToInsert, roomsToUpdate})
for( const roomData of roomsToInsert) {
this.roomLocalDataSourceService.createOrUpdateRoom(roomData)
this.roomLocalDataSourceService.createRoom(roomData)
}
for( const roomData of roomsToUpdate) {
this.roomLocalDataSourceService.updateRoom(roomData)
}
for( const roomData of roomsToDelete) {
this.roomLocalDataSourceService.deleteRoomById(roomData.id)
}
}
return result
}
@captureAndReraiseAsync('RoomRepositoryService/getRoomById')
async getRoomById(id: RoomByIdInputDTO) {
const result = await this.roomRemoteDataSourceService.getRoom(id)
@@ -50,6 +62,13 @@ export class RoomRepositoryService {
const { membersToInsert, membersToUpdate, membersToDelete } = roomMemberListDetermineChanges(result.value.data.members, localList, id)
const a = await this.roomLocalDataSourceService.createOrUpdateRoom(result.value.data)
if(a.isErr()) {
return a
}
for (const user of membersToInsert) {
this.roomLocalDataSourceService.addMember({...user, roomId:id})
}
@@ -63,6 +82,7 @@ export class RoomRepositoryService {
return result
}
@captureAndReraiseAsync('RoomRepositoryService/create')
async create(data: RoomInputDTO) {
const result = await this.roomRemoteDataSourceService.createRoom(data)
+133 -133
View File
@@ -73,122 +73,122 @@ export class ChatSystemService {
) {
this.RochetChatConnectorService.registerCallback({
type: 'reConnect',
funx: async () => {
/**
* @description when the phone is in the background for a long time it could disconnects from the socket then the socket reconnects automatically,
* when the connection is lost the subscribe is also lost, so we have to subscribe again when reconnection is establish.
*/
// this.RochetChatConnectorService.registerCallback({
// type: 'reConnect',
// funx: async () => {
// /**
// * @description when the phone is in the background for a long time it could disconnects from the socket then the socket reconnects automatically,
// * when the connection is lost the subscribe is also lost, so we have to subscribe again when reconnection is establish.
// */
this.RochetChatConnectorService.setStatus('online')
this.getUserStatus();
await this.chatService.refreshtoken();
this.getUser();
this.getAllRooms();
this.subscribeToRoom();
//
// this.RochetChatConnectorService.setStatus('online')
// this.getUserStatus();
// await this.chatService.refreshtoken();
// this.getUser();
// this.getAllRooms();
// this.subscribeToRoom();
// //
if (this.currentRoom) {
this.currentRoom.loadHistory({ forceUpdate: true })
}
// if (this.currentRoom) {
// this.currentRoom.loadHistory({ forceUpdate: true })
// }
for (const id in this.dm) {
this.dm[id].hasLoadHistory = false
}
// for (const id in this.dm) {
// this.dm[id].hasLoadHistory = false
// }
for (const id in this.group) {
this.group[id].hasLoadHistory = false
}
// for (const id in this.group) {
// this.group[id].hasLoadHistory = false
// }
}
})
// }
// })
if (this.sessionStore.user.Inactivity) {
this.loadChat();
}
// if (this.sessionStore.user.Inactivity) {
// this.loadChat();
// }
if (SessionStore.user?.ChatData?.data) {
this.restoreRooms();
}
// if (SessionStore.user?.ChatData?.data) {
// this.restoreRooms();
// }
document.addEventListener('resume', () => {
this.RochetChatConnectorService.setStatus('online')
if (this._dm?.length == 0 && this._group?.length == 0) {
if (SessionStore.user?.ChatData?.data) {
this.getAllRooms();
}
// document.addEventListener('resume', () => {
// this.RochetChatConnectorService.setStatus('online')
// if (this._dm?.length == 0 && this._group?.length == 0) {
// if (SessionStore.user?.ChatData?.data) {
// this.getAllRooms();
// }
}
});
// }
// });
try {
if (!this.platform.is('desktop')) {
App.addListener('appStateChange', ({ isActive }) => {
if (isActive) {
// The app is in the foreground.
console.log('App is in the foreground');
// try {
// if (!this.platform.is('desktop')) {
// App.addListener('appStateChange', ({ isActive }) => {
// if (isActive) {
// // The app is in the foreground.
// console.log('App is in the foreground');
if (SessionStore.user?.ChatData?.data) {
this.currentRoom?.loadHistory({ forceUpdate: true })
}
// if (SessionStore.user?.ChatData?.data) {
// this.currentRoom?.loadHistory({ forceUpdate: true })
// }
setTimeout(() => {
if (SessionStore.user?.ChatData?.data) {
this.subscribeToRoom()
this.RochetChatConnectorService.setStatus('online')
}
}, 1000);
// setTimeout(() => {
// if (SessionStore.user?.ChatData?.data) {
// this.subscribeToRoom()
// this.RochetChatConnectorService.setStatus('online')
// }
// }, 1000);
/* this.reloadComponent(true) */
} else {
// The app is in the background.
console.log('App is in the background');
// You can perform actions specific to the background state here.
}
});
}
} catch(error) {}
// /* this.reloadComponent(true) */
// } else {
// // The app is in the background.
// console.log('App is in the background');
// // You can perform actions specific to the background state here.
// }
// });
// }
// } catch(error) {}
}
loadChat() {
if (SessionStore.user?.ChatData?.data) {
this.ReLoadChat()
}
// if (SessionStore.user?.ChatData?.data) {
// this.ReLoadChat()
// }
}
private async ReLoadChat() {
if (SessionStore.user?.ChatData?.data) {
this.getUserStatus();
await this.chatService.refreshtoken();
// if (SessionStore.user?.ChatData?.data) {
// this.getUserStatus();
// await this.chatService.refreshtoken();
this.restoreUsers();
await this.getUser();
await this.restoreRooms();
await this.getAllRooms();
this.subscribeToRoom();
}
// this.restoreUsers();
// await this.getUser();
// await this.restoreRooms();
// await this.getAllRooms();
// this.subscribeToRoom();
// }
//
}
clearChat() {
this.dm = {}
this.group = {}
this._dm = []
this._group = []
// this.dm = {}
// this.group = {}
// this._dm = []
// this._group = []
this.loadingWholeList = false;
// this.loadingWholeList = false;
this.dmCount = 0;
this.groupCount = 0;
// this.dmCount = 0;
// this.groupCount = 0;
this.currentRoom = null
this.users = []
this.storage.remove('Users');
// this.currentRoom = null
// this.users = []
// this.storage.remove('Users');
}
openRoom(roomId) {
@@ -217,15 +217,15 @@ export class ChatSystemService {
async restoreRooms() {
try {
const _rooms = await this.storage.get('Rooms');
// try {
// const _rooms = await this.storage.get('Rooms');
if (_rooms) {
for (let roomData of this.sortArrayISODate(_rooms)) {
await this.prepareRoom(roomData);
}
}
} catch (e) { }
// if (_rooms) {
// for (let roomData of this.sortArrayISODate(_rooms)) {
// await this.prepareRoom(roomData);
// }
// }
// } catch (e) { }
}
@@ -358,27 +358,27 @@ export class ChatSystemService {
*/
subscribeToRoom() {
if (SessionStore.user?.ChatData?.data) {
// if (SessionStore.user?.ChatData?.data) {
for (const id in this.dm) {
this.defaultSubtribe(id)
}
// for (const id in this.dm) {
// this.defaultSubtribe(id)
// }
for (const id in this.group) {
this.defaultSubtribe(id)
}
// for (const id in this.group) {
// this.defaultSubtribe(id)
// }
this.RochetChatConnectorService.streamNotifyLogged().then((subscription => { }))
// this.RochetChatConnectorService.streamNotifyLogged().then((subscription => { }))
this.RochetChatConnectorService.subStreamMessageUser().then((subscription => {
console.log({subscription})
}))
} else {
// this.RochetChatConnectorService.subStreamMessageUser().then((subscription => {
// console.log({subscription})
// }))
// } else {
setTimeout(() => {
throw ('No chat data');
}, 1000)
}
// setTimeout(() => {
// throw ('No chat data');
// }, 1000)
// }
}
@@ -389,11 +389,11 @@ export class ChatSystemService {
*/
subscribeToRoomUpdate(id, roomData) {
this.defaultSubtribe(id);
// this.defaultSubtribe(id);
this.prepareRoom(roomData);
// this.prepareRoom(roomData);
this.getGroupRoom(id).loadHistory({});
// this.getGroupRoom(id).loadHistory({});
}
@@ -404,35 +404,35 @@ export class ChatSystemService {
*/
private defaultSubtribe(id: any) {
const room = this.getRoomById(id);
// const room = this.getRoomById(id);
if (!room.subscribeAttempt) {
// if (!room.subscribeAttempt) {
try {
// try {
room.subscribeAttempt = true;
} catch (error) {
console.log("error")
}
// room.subscribeAttempt = true;
// } catch (error) {
// console.log("error")
// }
this.RochetChatConnectorService.streamRoomMessages(id).then((subscription) => {
room.status.receive.message = true;
})
// this.RochetChatConnectorService.streamRoomMessages(id).then((subscription) => {
// room.status.receive.message = true;
// })
this.RochetChatConnectorService.subStreamNotifyRoom(id, 'typing', false).then((subscription) => {
room.status.receive.typing = true;
//
})
// this.RochetChatConnectorService.subStreamNotifyRoom(id, 'typing', false).then((subscription) => {
// room.status.receive.typing = true;
// //
// })
this.RochetChatConnectorService.subStreamNotifyRoom(id, 'readMessage', false).then((subscription) => {
room.status.receive.readMessage = true;
})
// this.RochetChatConnectorService.subStreamNotifyRoom(id, 'readMessage', false).then((subscription) => {
// room.status.receive.readMessage = true;
// })
this.RochetChatConnectorService.streamNotifyRoomDeleteMessage(id).then((subscription) => {
room.status.receive.deleteMessage = true;
})
}
// this.RochetChatConnectorService.streamNotifyRoomDeleteMessage(id).then((subscription) => {
// room.status.receive.deleteMessage = true;
// })
// }
}
@@ -51,7 +51,7 @@ export class RochetChatConnectorService {
}
wsSend({ message, requestId = uuidv4(), loginRequired = true }: send) {
this.ws.send({ message: { msg: "pong" }, loginRequired: false })
// this.ws.send({ message: { msg: "pong" }, loginRequired: false })
}
login() {
@@ -225,7 +225,7 @@ export class RochetChatConnectorService {
//
this.ws.send({ message, requestId });
// this.ws.send({ message, requestId });
return new Promise((resolve, reject) => {
this.ws.registerCallback({
+46 -46
View File
@@ -1231,66 +1231,66 @@ export class RoomService {
async updateContacts() {
let res
let error = false
// let res
// let error = false
if (this.t == 'd') {
// if (this.t == 'd') {
try {
res = await this.chatService.getMembers(this.id).toPromise();
} catch (e) {
await this.chatService.refreshtoken();
error = true
}
// try {
// res = await this.chatService.getMembers(this.id).toPromise();
// } catch (e) {
// await this.chatService.refreshtoken();
// error = true
// }
if (error) {
res = await this.chatService.getMembers(this.id).toPromise();
}
// if (error) {
// res = await this.chatService.getMembers(this.id).toPromise();
// }
} else {
if (this.t === 'p') {
// } else {
// if (this.t === 'p') {
try {
res = await this.chatService.getGroupMembers(this.id).toPromise()
} catch (e) {
await this.chatService.refreshtoken();
error = true
}
// try {
// res = await this.chatService.getGroupMembers(this.id).toPromise()
// } catch (e) {
// await this.chatService.refreshtoken();
// error = true
// }
if (error) {
res = await this.chatService.getGroupMembers(this.id).toPromise()
}
// if (error) {
// res = await this.chatService.getGroupMembers(this.id).toPromise()
// }
setTimeout(() => {
// console.log("getGroupMembers", this.membersExcludeMe)
}, 500)
// setTimeout(() => {
// // console.log("getGroupMembers", this.membersExcludeMe)
// }, 500)
}
else {
// }
// else {
try {
res = await this.chatService.getChannelMembers(this.id).toPromise()
// try {
// res = await this.chatService.getChannelMembers(this.id).toPromise()
} catch (e) {
await this.chatService.refreshtoken();
error = true
}
// } catch (e) {
// await this.chatService.refreshtoken();
// error = true
// }
if (error) {
res = await this.chatService.getChannelMembers(this.id).toPromise()
}
// if (error) {
// res = await this.chatService.getChannelMembers(this.id).toPromise()
// }
setTimeout(() => {
console.log("getChannelMembers", this.membersExcludeMe)
}, 500)
}
}
// setTimeout(() => {
// console.log("getChannelMembers", this.membersExcludeMe)
// }, 500)
// }
// }
const members = res['members'];
const users = members.filter(data => data.username != this.sessionStore.user.UserName);
this.members = members
this.membersExcludeMe = users
// const members = res['members'];
// const users = members.filter(data => data.username != this.sessionStore.user.UserName);
// this.members = members
// this.membersExcludeMe = users
}
async closeModal() {
@@ -1,9 +1,10 @@
import { HttpErrorResponse } from '@angular/common/http';
import { Result, err } from 'neverthrow';
import { Result } from 'neverthrow';
import { z, ZodError } from 'zod';
import * as Sentry from '@sentry/capacitor';
import { ColoredLoggerService } from '../logger/colored/service';
export function APIReturn(schema: z.ZodTypeAny) {
export function APIReturn(schema: z.ZodTypeAny, context: string) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
@@ -19,9 +20,8 @@ export function APIReturn(schema: z.ZodTypeAny) {
if (error instanceof ZodError) {
// If validation fails, throw an error with the details
//
console.error('API unexpected data structure')
console.error(result.value)
console.error(error.errors)
ColoredLoggerService.error(error.errors, 'API unexpected data structure '+ context, schema._def.description)
// Capture the Zod validation error with additional context
Sentry.withScope((scope) => {
scope.setTag('APIReturn', 'user');
@@ -0,0 +1,19 @@
import { err } from "neverthrow";
import { ColoredLoggerService } from "../logger/colored/service";
export function captureAndReraiseAsync(taskName: string) {
return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = async function(...args: any[]) {
try {
return await originalMethod.apply(this, args);
} catch (error) {
// Log the error along with taskName
ColoredLoggerService.error('Capture error from', taskName, error)
// Re-throw the same error
return err(error) ;
}
};
return descriptor;
};
}
+53
View File
@@ -0,0 +1,53 @@
import { DateTime } from 'luxon';
type GetDateWithFormatFormatInput = {
date?: Date;
format?: string;
};
export class DateUtils {
static getDateStringWithFormat(
input: Partial<GetDateWithFormatFormatInput> = {},
): string {
if (!input?.date) {
Object.assign(input, { date: DateUtils.getJSDate() });
}
if (!input?.format) {
Object.assign(input, { format: process.env.DATE_FORMAT });
}
return DateTime.fromJSDate(input.date, { zone: 'utc' })
.setZone(process.env.TZ)
.toFormat(input.format);
}
static getISODateString(): string {
return DateTime.fromJSDate(DateUtils.getJSDate(), { zone: 'utc' })
.setZone(process.env.TZ)
.toJSON();
}
static getISODateJSDateObject(dateObject: Date): string {
// Convert the JavaScript Date object to Luxon DateTime
const luxonDateTime = DateTime.fromJSDate(dateObject, { zone: 'utc' });
// Get the ISO 8601 formatted string in UTC
const isoDateString = luxonDateTime.toISO();
return isoDateString;
}
static getJSDate(): Date {
return DateTime.fromJSDate(DateTime.now().toJSDate(), { zone: 'utc' })
.setZone(process.env.TZ)
.toJSDate();
}
static getDate(): DateTime {
return DateTime.fromJSDate(DateUtils.getJSDate(), { zone: 'utc' }).setZone(
process.env.TZ,
);
}
}
@@ -0,0 +1,69 @@
import { DateUtils } from './date';
export type MessageType = {
message: string;
context?: string;
obj?: object;
};
function getCurrentTime() {
const now = new Date();
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
const milliseconds = String(now.getMilliseconds()).padStart(3, '0');
return `${hours}:${minutes}:${seconds}.${milliseconds}`;
}
export class ColoredLoggerService {
constructor() {}
static log(message: string): void {
console.log(
`[${getCurrentTime()}] %cINFO : `, // Console Message
'color: #00897B', // CSS Style
message
);
}
static debug({ message, context, obj = {} }: MessageType): void {
console.info(
`[${getCurrentTime()}] %cINFO : `, // Console Message
'color: #039BE5', // CSS Style
Object.assign(obj, { context, createdAt: DateUtils.getISODateString(), message })
);
}
static info({ message, context, obj = {} }: MessageType): void {
console.info(
`[${getCurrentTime()}] %cINFO : `, // Console Message
'color: #039BE5', // CSS Style
Object.assign(obj, { context, createdAt: DateUtils.getISODateString(), message })
);
}
static warn({ message, context, obj = {} }: MessageType): void {
console.warn(
`[${getCurrentTime()}] %cWARN : `, // Console Message
'color: #FB8C00', // CSS Style
Object.assign(obj, { context, createdAt: DateUtils.getISODateString(), message })
);
}
static error(error: any = "", message?: string, context = ""): void {
console.error(
`[${getCurrentTime()}] %cERROR : `, // Console Message
'color: #E53935', // CSS Style
message+', '+ context,
'\n',
error,
'\n',
);
}
fatal(error?: any, message?: string, context?: string): void {}
}
+12
View File
@@ -0,0 +1,12 @@
import { z, ZodSchema, ZodError } from "zod";
// Utility function to attach metadata
export function attachMetadata<T extends ZodSchema<any>>(schema: T, metadata: Record<string, any>): T {
return (schema.refine(value => true, { message: "Metadata attached", ...metadata }) as any) as T;
}
// Function to get metadata from a Zod error
export function getMetadata<T extends ZodSchema<any>>(schema: T, error: ZodError): Record<string, any> | undefined {
const metadataIssue = error.errors.find(issue => issue.message === "Metadata attached");
return metadataIssue ? metadataIssue : undefined;
}