improve saveMessage (switch to class) and started to test

This commit is contained in:
grimhilt 2023-03-29 21:00:43 +02:00
parent 053213eecb
commit 1a63b3154a
9 changed files with 366 additions and 149 deletions

View File

@ -1,12 +1,13 @@
const statusCode = require("../utils/statusCodes").statusCodes; const statusCode = require("../utils/statusCodes").statusCodes;
const { getMessages } = require("../db/api.js"); const { getMessages } = require("../db/api.js");
const { logger } = require("../system/Logger");
async function messages(body, res) { async function messages(body, res) {
const { roomId } = body; const { roomId } = body;
getMessages(roomId).then((messages) => { getMessages(roomId).then((messages) => {
res.status(statusCode.OK).json(messages); res.status(statusCode.OK).json(messages);
}).catch((err) => { }).catch((err) => {
console.log(err) logger.err(err)
res.status(statusCode.INTERNAL_SERVER_ERROR); res.status(statusCode.INTERNAL_SERVER_ERROR);
}); });
} }

View File

@ -1,12 +1,13 @@
const statusCode = require("../utils/statusCodes").statusCodes; const statusCode = require("../utils/statusCodes").statusCodes;
const { getRooms } = require("../db/api.js"); const { getRooms } = require("../db/api.js");
const { logger } = require("../system/Logger");
async function rooms(body, res) { async function rooms(body, res) {
const { mailboxId, offset, limit } = body; const { mailboxId, offset, limit } = body;
getRooms(mailboxId).then((rooms) => { getRooms(mailboxId).then((rooms) => {
res.status(statusCode.OK).json(rooms); res.status(statusCode.OK).json(rooms);
}).catch((err) => { }).catch((err) => {
console.log(err) logger.error(err)
res.status(statusCode.INTERNAL_SERVER_ERROR); res.status(statusCode.INTERNAL_SERVER_ERROR);
}); });
} }

View File

@ -44,7 +44,7 @@ function execQueryAsyncWithId(query, values) {
function execQuery(query, values) { function execQuery(query, values) {
db.query(query, values, (err, results, fields) => { db.query(query, values, (err, results, fields) => {
if (err) { if (err) {
logger.err(err); logger.error(err);
throw (err); throw (err);
} }
return results; return results;

View File

@ -9,7 +9,7 @@ const {
} = require("../db/saveMessageApp"); } = require("../db/saveMessageApp");
const { findRoomByOwner, getAddresseId, getUserIdOfMailbox } = require("../db/mail"); const { findRoomByOwner, getAddresseId, getUserIdOfMailbox } = require("../db/mail");
const { isDmOnEnvelope, nbMembers } = require("./utils/statusUtils"); const { nbMembers } = require("./utils/statusUtils");
/** /**
* take object address and join mailbox and host to return mailbox@host * take object address and join mailbox and host to return mailbox@host
@ -18,105 +18,128 @@ function createAddress(elt) {
return `${elt.mailbox}@${elt.host}`; return `${elt.mailbox}@${elt.host}`;
} }
async function registerMessageInApp(messageId, attrs, boxId) { async function initiateRoom(envelope, ownerId, messageId, isSeen) {
const isSeen = attrs.flags.includes("\\Seen") ? 1 : 0; // todo verify await createRoom(envelope.subject, ownerId, messageId).then(async (roomId) => {
const envelope = attrs.envelope; // todo register members
await registerMessageInRoom(messageId, roomId, isSeen, envelope.date);
await getAddresseId(createAddress(envelope.sender[0])).then(async (ownerId) => {
if (envelope.inReplyTo) {
await registerReplyMessage(envelope, messageId, isSeen, ownerId);
} else {
const userId = (await getUserIdOfMailbox(boxId))[0]?.user_id;
if (ownerId == userId) {
// send by the user
if (nbMembers(envelope) == 2) {
// this is a dm
console.log(envelope)
const userTo = (await getAddresseId(createAddress(envelope.to[0])));
await findRoomByOwner(userTo).then(async (res) => {
if (res.length == 0) {
// first message of this conv with this sender
await createRoom(envelope.subject, userTo, messageId).then(async (roomId) => {
await registerMessageInRoom(messageId, roomId, isSeen, envelope.date);
});
} else {
// not a reply, add to the list of message if this sender
await registerMessageInRoom(messageId, res[0].room_id, isSeen, envelope.date);
}
});
} else {
// message coming from user with multiple member is a group
await createRoom(envelope.subject, ownerId, messageId).then(async (roomId) => {
await registerMessageInRoom(messageId, roomId, isSeen, envelope.date);
});
}
} else {
await findRoomByOwner(ownerId).then(async (res) => {
if (res.length == 0) {
// first message of this sender
if (!envelope.subject) console.error(envelope)
await createRoom(envelope.subject, ownerId, messageId).then(async (roomId) => {
await registerMessageInRoom(messageId, roomId, isSeen, envelope.date);
});
} else {
// not a reply, add to the list of message if this sender
await registerMessageInRoom(messageId, res[0].room_id, isSeen, envelope.date);
}
});
}
}
}); });
} }
async function registerReplyMessage(envelope, messageId, isSeen, ownerId) { const roomType = {
const messageID = envelope.messageId; ROOM: 'room',
await findRoomsFromMessage(messageId).then(async (rooms) => { CHANNEL: 'channel',
if (rooms.length == 0) { GROUP: 'group',
// no rooms, so is a transfer DM: 'dm',
// todo test if members of transferred message are included THREAD: 'thread'
} else if (rooms.length === 1) { }
// only one room so message is only in a room and not in a thread
// as a thread is associated to a room to begin class registerMessageInApp {
await isRoomGroup(rooms[0].room_id).then(async (isGroup) => { constructor(_messageId, _attrs, _boxId) {
if (isGroup) { this.messageId = _messageId;
const hasSameMembers = await hasSameMembersAsParent(messageID, envelope.inReplyTo); this.attrs = _attrs;
if (hasSameMembers) { this.envelope = this.attrs.envelope;
await registerMessageInRoom(messageId, rooms[0].room_id, isSeen, envelope.date); this.messageID = this.envelope.messageId;
} else { this.boxId = _boxId;
// is a group and has not the same member as the previous message this.isSeen = this.attrs.flags.includes("\\Seen") ? 1 : 0;
// some recipient has been removed create a thread this.ownerId;
const isDm = isDmOnEnvelope(envelope); this.userId;
await createThread(envelope.subject, ownerId, messageId, rooms[0].room_id, isDm).then(async (threadId) => { }
await registerMessageInThread(messageId, threadId, isSeen);
}); async init() {
} this.ownerId = await getAddresseId(createAddress(this.envelope.sender[0])); // todo use sender or from ?
} else { }
// reply from channel
// todo isDm = () => nbMembers(this.envelope) == 2;
// if (sender == owner) { // correction from the original sender
// // leave in the same channel async isFromUs() {
// } if (!this.userId) this.userId = (await getUserIdOfMailbox(boxId))[0]?.user_id;
} return this.ownerId = this.userId;
}); }
} else if (rooms.length > 1) {
// get the lowest thread (order by room_id) async initiateRoom(owner, roomType) {
const room = rooms[rooms.length-1]; // todo roomType
const hasSameMembers = await hasSameMembersAsParent(messageID, envelope.inReplyTo); await createRoom(this.envelope.subject, owner, this.messageId).then(async (roomId) => {
if (hasSameMembers) { // todo register members
await registerMessageInThread(messageId, room.room_id, isSeen); await registerMessageInRoom(this.messageId, roomId, this.isSeen, this.envelope.date);
});
}
async createOrRegisterOnExistence(owner, roomType) {
await findRoomByOwner(owner).then(async (res) => {
if (res.length == 0) {
// first message with this sender
await initiateRoom(owner, roomType);
} else { } else {
// has not the same members so it is a derivation of this thread // not a reply, add to the list of message if this sender
// todo put this in a function and add default message in the reply chain await registerMessageInRoom(this.messageId, res[0].room_id, this.isSeen, this.envelope.date);
const isDm = isDmOnEnvelope(envelope); }
await createThread(envelope.subject, ownerId, messageId, room.room_id, isDm).then(async (threadId) => { });
await registerMessageInThread(messageId, threadId, isSeen); }
});
async createOrRegisterOnMembers(roomId) {
const hasSameMembers = await hasSameMembersAsParent(this.messageID, this.envelope.inReplyTo);
if (hasSameMembers) {
await registerMessageInRoom(this.messageId, roomId, this.isSeen, this.envelope.date);
} else {
await createThread(this.envelope.subject, this.ownerId, this.messageId, roomId, this.isDm()).then(
async (threadId) => {
await registerMessageInThread(this.messageId, threadId, this.isSeen);
},
);
}
}
async save() {
await this.init();
if (this.envelope.inReplyTo) {
this.saveReply();
} else {
if (await this.isFromUs()) {
if (this.isDm()) {
// create or add new message to DM
const userTo = await getAddresseId(createAddress(this.envelope.to[0]));
await this.createOrRegisterOnExistence(userTo, roomType.DM);
} else {
// it is not a reply and not a dm
// so it is a channel, which can be possibly a group
initiateRoom(this.envelope, this.ownerId, this.messageId, this.isSeen);
}
} else {
await this.createOrRegisterOnExistence(this.ownerId, roomType.ROOM);
} }
} }
}); }
async saveReply() {
const messageID = envelope.messageId;
await findRoomsFromMessage(messageId).then(async (rooms) => {
if (rooms.length == 0) {
// no rooms, so is a transfer
// todo test if members of transferred message are included
} else if (rooms.length === 1) {
// only one room so message is only in a room and not in a thread
// as a thread is associated to a room
await isRoomGroup(rooms[0].room_id).then(async (isGroup) => {
if (isGroup) {
this.createOrRegisterOnMembers(rooms[0].room_id);
} else {
// reply from channel
// todo
// if (sender == owner) { // correction from the original sender
// // leave in the same channel
// }
}
});
} else if (rooms.length > 1) {
// get the lowest thread (order by room_id)
const roomId = rooms[rooms.length - 1].room_id;
this.createOrRegisterOnMembers(roomId);
}
});
}
} }
module.exports = { module.exports = {
registerMessageInApp registerMessageInApp,
roomType
}; };

View File

@ -1,7 +1,3 @@
function isDmOnEnvelope(envelope) {
return nbMembers(envelope) === 2;
}
function nbMembers(envelope) { function nbMembers(envelope) {
let nbMembers = let nbMembers =
(envelope.bcc?.length ?? 0) + (envelope.bcc?.length ?? 0) +
@ -18,6 +14,5 @@ function nbMembers(envelope) {
} }
module.exports = { module.exports = {
isDmOnEnvelope,
nbMembers, nbMembers,
}; };

View File

@ -1,52 +1,40 @@
process.env["NODE_DEV"] = "TEST"; const { getAddresseId } = require("../../db/mail");
const { saveFromParsedData } = require("../../mails/storeMessage"); const { generateAttrs, generateUsers } = require("../test-utils/test-attrsUtils");
const { TestDb } = require("../sql/test-utilsDb"); const { registerMessageInApp, roomType } = require("../../mails/saveMessage");
const MYSQL = require("../../db/config.json").MYSQL;
let db; jest.mock("../../db/mail");
beforeAll(async () => {
const options = {
databaseOptions: {
host: "localhost",
port: 3306,
user: MYSQL.user,
password: MYSQL.pwd,
database: "mail_test",
},
dbSchema: "../../sql/structureV2.sql",
};
db = new TestDb(options);
await db.init();
});
afterAll(async () => { // todo mock db
db.cleanTables();
});
describe("saveMessage", async () => { describe("saveMessage", () => {
describe("rooms", async () => { describe("is not a reply", () => {
it("messages not related and from same sender should be in the same room", async () => { it("first DM from user should create a DM room", async () => {
await saveFromParsedData( const users = generateUsers(2);
{ const attrs = generateAttrs({ from: [users[0].user], to: [users[1].user] });
to: { value: [{ address: "address1@email.com" }] },
from: { value: [{ address: "address2@email.com" }] }, getAddresseId.mockReturnValue(users[1].id);
messageId: "<messageId1>",
}, const register = new registerMessageInApp(1, attrs, 1);
1, register.ownerId = users[0].id;
);
await saveFromParsedData( jest.spyOn(register, "isFromUs").mockReturnValue(true);
{ jest.spyOn(register, "init").mockReturnValue("");
to: { value: [{ address: "address1@email.com" }] },
from: { value: [{ address: "address2@email.com" }] }, const createOrRegisterOnExistence = jest
messageId: "<messageId2>", .spyOn(register, "createOrRegisterOnExistence")
}, .mockImplementation(() => undefined);
2,
); await register.save();
// todo call parser
const query = "" expect(createOrRegisterOnExistence).toHaveBeenCalledWith(users[1].id, roomType.DM);
db.execQueryAsync().then((res) => {
expect(res.length).toBe(2);
})
}); });
// it("DM message from user should be added to DM room", async () => {
// });
// it("first GROUP message should create a group", () => {});
}); });
describe("replies", () => {
it("", () => {});
});
describe("", () => {});
}); });

View File

@ -0,0 +1,206 @@
const names = [
"James",
"Mary",
"Robert",
"Patricia",
"John",
"Jennifer",
"Michael",
"Linda",
"David",
"Elizabeth",
"William",
"Barbara",
"Richard",
"Susan",
"Joseph",
"Jessica",
"Thomas",
"Sarah",
"Charles",
"Karen",
"Christopher",
"Lisa",
"Daniel",
"Nancy",
"Matthew",
"Betty",
"Anthony",
"Margaret",
"Mark",
"Sandra",
"Donald",
"Ashley",
"Steven",
"Kimberly",
"Paul",
"Emily",
"Andrew",
"Donna",
"Joshua",
"Michelle",
"Kenneth",
"Carol",
"Kevin",
"Amanda",
"Brian",
"Dorothy",
"George",
"Melissa",
"Timothy",
"Deborah",
"Ronald",
"Stephanie",
"Edward",
"Rebecca",
"Jason",
"Sharon",
"Jeffrey",
"Laura",
"Ryan",
"Cynthia",
"Jacob",
"Kathleen",
"Gary",
"Amy",
"Nicholas",
"Angela",
"Eric",
"Shirley",
"Jonathan",
"Anna",
"Stephen",
"Brenda",
"Larry",
"Pamela",
"Justin",
"Emma",
"Scott",
"Nicole",
"Brandon",
"Helen",
"Benjamin",
"Samantha",
"Samuel",
"Katherine",
"Gregory",
"Christine",
"Alexander",
"Debra",
"Frank",
"Rachel",
"Patrick",
"Carolyn",
"Raymond",
"Janet",
"Jack",
"Catherine",
"Dennis",
"Maria",
"Jerry",
"Heather",
"Tyler",
"Diane",
"Aaron",
"Ruth",
"Jose",
"Julie",
"Adam",
"Olivia",
"Nathan",
"Joyce",
"Henry",
"Virginia",
"Douglas",
"Victoria",
"Zachary",
"Kelly",
"Peter",
"Lauren",
"Kyle",
"Christina",
"Ethan",
"Joan",
"Walter",
"Evelyn",
"Noah",
"Judith",
"Jeremy",
"Megan",
"Christian",
"Andrea",
"Keith",
"Cheryl",
"Roger",
"Hannah",
"Terry",
"Jacqueline",
"Gerald",
"Martha",
"Harold",
"Gloria",
"Sean",
"Teresa",
"Austin",
"Ann",
"Carl",
"Sara",
"Arthur",
"Madison",
"Lawrence",
"Frances",
"Dylan",
"Kathryn",
"Jesse",
"Janice",
"Jordan",
"Jean",
"Bryan",
"Abigail",
"Billy",
"Alice",
"Joe",
"Julia",
"Bruce",
"Judy",
"Gabriel",
"Sophia",
"Logan",
"Grace",
"Albert",
"Denise",
"Willie",
"Amber",
"Alan",
"Doris",
"Juan",
"Marilyn",
"Wayne",
"Danielle",
"Elijah",
"Beverly",
"Randy",
"Isabella",
"Roy",
"Theresa",
"Vincent",
"Diana",
"Ralph",
"Natalie",
"Eugene",
"Brittany",
"Russell",
"Charlotte",
"Bobby",
"Marie",
"Mason",
"Kayla",
"Philip",
"Alexis",
"Louis",
"Lori"
];
module.exports = {
names
}

View File

@ -12,5 +12,8 @@ export default {
}, },
getMessages(roomId) { getMessages(roomId) {
return API().get(`/mail/${roomId}/messages`); return API().get(`/mail/${roomId}/messages`);
} },
getMembers(roomId) {
return API().get(`/mail/${roomId}/members`);
},
} }

View File

@ -39,7 +39,7 @@ onMounted(() => {
<template> <template>
<div class="message"> <div class="message">
<div id="context"> <div id="context">
<div class="left" id="profile">Carrefour@emailing .carrefor.fr "carrefour"</div> <div class="left" id="profile">{{ props.data.fromA }}</div>
<div class="middle">{{ decodeEmojis(props.data.subject) }}</div> <div class="middle">{{ decodeEmojis(props.data.subject) }}</div>
<div class="right" id="date"> <div class="right" id="date">
{{ {{