implement save of thread and members
This commit is contained in:
parent
a82ff9b85b
commit
68e1dfe7d8
@ -2,13 +2,31 @@ const { transformEmojis } = require("../utils/string.js");
|
||||
const { db, execQueryAsync, execQueryAsyncWithId, execQuery } = require("./db.js");
|
||||
const { queryFromId, queryToId, queryCcId } = require("./utils/addressQueries.js");
|
||||
|
||||
async function createRoom(roomName, ownerId, messageId) {
|
||||
async function getAllMembers(messageId) {
|
||||
const query = `
|
||||
SELECT GROUP_CONCAT(address.address_id) AS is
|
||||
FROM address
|
||||
INNER JOIN address_field ON
|
||||
address_field.address_id = address.address_id AND
|
||||
address_field.message_id = ?
|
||||
GROUP BY address_field.message_id
|
||||
`;
|
||||
const values = [messageId];
|
||||
return await execQueryAsync(query, values);
|
||||
}
|
||||
|
||||
async function registerMember(roomId, memberId) {
|
||||
const query = `INSERT IGNORE INTO app_room_member (room_id, member_id) VALUES (?, ?)`;
|
||||
const values = [roomId, memberId];
|
||||
return await execQueryAsync(query, values);
|
||||
}
|
||||
|
||||
async function createRoom(roomName, ownerId, messageId, roomType) {
|
||||
if (!roomName) roomName = "No room name";
|
||||
roomName = transformEmojis(roomName);
|
||||
const query = `INSERT IGNORE INTO app_room (room_name, owner_id, message_id) VALUES (?, ?, ?)`;
|
||||
const values = [roomName.substring(0, 255), ownerId, messageId];
|
||||
const query = `INSERT IGNORE INTO app_room (room_name, owner_id, message_id, room_type) VALUES (?, ?, ?, ?)`;
|
||||
const values = [roomName.substring(0, 255), ownerId, messageId, roomType];
|
||||
return await execQueryAsyncWithId(query, values);
|
||||
// todo add members
|
||||
}
|
||||
|
||||
async function registerMessageInRoom(messageId, roomId, isSeen, idate) {
|
||||
@ -17,10 +35,9 @@ async function registerMessageInRoom(messageId, roomId, isSeen, idate) {
|
||||
await execQueryAsync(query, values);
|
||||
|
||||
updateLastUpdateRoom(roomId, idate);
|
||||
|
||||
if (!isSeen) {
|
||||
incrementNotSeenRoom(roomId);
|
||||
}
|
||||
// if (!isSeen) {
|
||||
// incrementNotSeenRoom(roomId);
|
||||
// }
|
||||
}
|
||||
|
||||
function updateLastUpdateRoom(roomId, idate) {
|
||||
@ -33,29 +50,25 @@ function incrementNotSeenRoom(roomId) {
|
||||
// todo
|
||||
}
|
||||
|
||||
async function createThread(threadName, ownerId, messageId, parentRoomId, isDm) {
|
||||
const rootRoomId = -1; // todo
|
||||
const threadId = await createRoom(threadName, ownerId, messageId);
|
||||
const query = `INSERT INTO app_thread (room_id, parent_room_id, root_room_id, isDm) VALUES (?, ?, ?, ?)`;
|
||||
const values = [threadId, parentRoomId, rootRoomId, isDm];
|
||||
async function getRoomInfo(messageID) {
|
||||
const query = `
|
||||
SELECT
|
||||
app_room.room_id
|
||||
app_thread.root_id
|
||||
FROM app_room
|
||||
LEFT JOIN app_thread ON app_thread.room_id = app_room.room_id
|
||||
INNER JOIN app_room_message ON app_room_message.room_id = app_room.room_id
|
||||
INNER JOIN message ON message.message_id = app_room_message.message_id
|
||||
WHERE message.messageID = ?
|
||||
`;
|
||||
const values = [messageID];
|
||||
return await execQueryAsync(query, values);
|
||||
// todo add members
|
||||
}
|
||||
|
||||
async function registerMessageInThread(messageId, threadId, isSeen) {
|
||||
// todo check if it is still a thread or should be a room
|
||||
// todo isdm
|
||||
console.log("register message in thread")
|
||||
}
|
||||
|
||||
function updateLastUpdateThread(threadId) {
|
||||
// todo
|
||||
// check for parent
|
||||
}
|
||||
|
||||
function incrementNotSeenThread(threadId) {
|
||||
// todo
|
||||
// also increment root room
|
||||
async function registerThread(roomId, parentId, rootId) {
|
||||
const query = `INSERT IGNORE INTO app_thread (room_id, parent_id, root_id) VALUES (?, ?, ?)`;
|
||||
const values = [roomId, parentId, rootId];
|
||||
return await execQueryAsync(query, values);
|
||||
}
|
||||
|
||||
async function isRoomGroup(roomId) {
|
||||
@ -119,11 +132,13 @@ async function hasSameMembersAsParent(messageId, messageID) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getAllMembers,
|
||||
registerMember,
|
||||
createRoom,
|
||||
registerMessageInRoom,
|
||||
createThread,
|
||||
registerMessageInThread,
|
||||
registerThread,
|
||||
isRoomGroup,
|
||||
findRoomsFromMessage,
|
||||
hasSameMembersAsParent,
|
||||
getRoomInfo
|
||||
};
|
||||
|
@ -122,11 +122,11 @@ CREATE TABLE app_room (
|
||||
room_name VARCHAR(255) NOT NULL,
|
||||
owner_id INT NOT NULL,
|
||||
message_id INT NOT NULL,
|
||||
isGroup BOOLEAN NOT NULL DEFAULT false,
|
||||
room_type INT NOT NULL DEFAULT 0,
|
||||
notSeen INT NOT NULL DEFAULT 0,
|
||||
lastUpdate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP(),
|
||||
PRIMARY KEY (room_id),
|
||||
UNIQUE KEY (owner_id, message_id, isGroup),
|
||||
UNIQUE KEY (owner_id, message_id, room_type),
|
||||
FOREIGN KEY (owner_id) REFERENCES address(address_id),
|
||||
FOREIGN KEY (message_id) REFERENCES message(message_id)
|
||||
);
|
||||
@ -134,14 +134,13 @@ CREATE TABLE app_room (
|
||||
-- 12
|
||||
CREATE TABLE app_thread (
|
||||
room_id INT NOT NULL,
|
||||
parent_room_id INT,
|
||||
root_room_id INT,
|
||||
isDm BOOLEAN NOT NULL DEFAULT false,
|
||||
parent_id INT,
|
||||
root_id INT,
|
||||
PRIMARY KEY (room_id),
|
||||
UNIQUE KEY (room_id, parent_room_id, root_room_id),
|
||||
UNIQUE KEY (room_id, parent_id, root_id),
|
||||
FOREIGN KEY (room_id) REFERENCES app_room(room_id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (parent_room_id) REFERENCES app_room(room_id) ON DELETE SET NULL,
|
||||
FOREIGN KEY (root_room_id) REFERENCES app_room(room_id) ON DELETE SET NULL
|
||||
FOREIGN KEY (parent_id) REFERENCES app_room(room_id) ON DELETE SET NULL,
|
||||
FOREIGN KEY (root_id) REFERENCES app_room(room_id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
-- 13
|
||||
@ -157,6 +156,7 @@ CREATE TABLE app_room_message (
|
||||
CREATE TABLE app_room_member (
|
||||
room_id INT NOT NULL,
|
||||
member_id INT NOT NULL,
|
||||
UNIQUE KEY (room_id, member_id),
|
||||
FOREIGN KEY (room_id) REFERENCES app_room(room_id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (member_id) REFERENCES address(address_id)
|
||||
);
|
||||
|
@ -1,14 +0,0 @@
|
||||
const MYSQL = require("./sql/config.json").mysql;
|
||||
|
||||
module.exports = {
|
||||
databaseOptions: {
|
||||
host: "localhost",
|
||||
port: 3306,
|
||||
user: MYSQL.user,
|
||||
password: MYSQL.pwd,
|
||||
database: "mail_test",
|
||||
},
|
||||
createDatabase: true,
|
||||
dbSchema: "./sql/structureV2.sql",
|
||||
truncateDatabase: true,
|
||||
};
|
@ -6,10 +6,14 @@ const {
|
||||
isRoomGroup,
|
||||
findRoomsFromMessage,
|
||||
hasSameMembersAsParent,
|
||||
registerThread,
|
||||
registerMember,
|
||||
getAllMembers,
|
||||
} = require("../db/saveMessageApp");
|
||||
|
||||
const { findRoomByOwner, getAddresseId, getUserIdOfMailbox } = require("../db/mail");
|
||||
const { nbMembers } = require("./utils/statusUtils");
|
||||
const { nbMembers } = require("./utils/envelopeUtils");
|
||||
const { logger } = require("../system/Logger");
|
||||
|
||||
/**
|
||||
* take object address and join mailbox and host to return mailbox@host
|
||||
@ -26,11 +30,11 @@ async function initiateRoom(envelope, ownerId, messageId, isSeen) {
|
||||
}
|
||||
|
||||
const roomType = {
|
||||
ROOM: 'room',
|
||||
CHANNEL: 'channel',
|
||||
GROUP: 'group',
|
||||
DM: 'dm',
|
||||
THREAD: 'thread'
|
||||
ROOM: 0,
|
||||
CHANNEL: 1,
|
||||
GROUP: 2,
|
||||
DM: 3,
|
||||
THREAD: 4
|
||||
}
|
||||
|
||||
class registerMessageInApp {
|
||||
@ -56,19 +60,30 @@ class registerMessageInApp {
|
||||
return this.ownerId == this.userId;
|
||||
}
|
||||
|
||||
async initiateRoom(owner, roomType) {
|
||||
// todo roomType
|
||||
await createRoom(this.envelope.subject, owner, this.messageId).then(async (roomId) => {
|
||||
// todo register members
|
||||
await registerMessageInRoom(this.messageId, roomId, this.isSeen, this.envelope.date);
|
||||
async registerMembers(roomId) {
|
||||
getAllMembers(this.messageId).then((res) => {
|
||||
res[0].id.split(',').foreach(async (memberId) => {
|
||||
await registerMember(roomId, memberId);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async initiateRoom(owner, type) {
|
||||
try {
|
||||
const roomId = await createRoom(this.envelope.subject, owner, this.messageId, type);
|
||||
await registerMessageInRoom(this.messageId, roomId, this.isSeen, this.envelope.date);
|
||||
this.registerMembers(roomId);
|
||||
return roomId;
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
async createOrRegisterOnExistence(owner, roomType) {
|
||||
await findRoomByOwner(owner).then(async (res) => {
|
||||
if (res.length == 0) {
|
||||
// first message with this sender
|
||||
await initiateRoom(owner, roomType);
|
||||
await this.initiateRoom(owner, roomType);
|
||||
} else {
|
||||
// not a reply, add to the list of message if this sender
|
||||
await registerMessageInRoom(this.messageId, res[0].room_id, this.isSeen, this.envelope.date);
|
||||
@ -76,11 +91,28 @@ class registerMessageInApp {
|
||||
});
|
||||
}
|
||||
|
||||
async initiateThread() {
|
||||
await createRoom(this.envelope.subject, owner, this.messageId, roomType.THREAD).then(async (roomId) => {
|
||||
// find parent room infos
|
||||
await getRoomInfo(this.envelope.inReplyTo).then(async (room) => {
|
||||
// todo room not lenght, reply to transfer ?
|
||||
let root_id = room[0].root_id
|
||||
if (!root_id) root_id = room[0].room_id
|
||||
await registerThread(roomId, room[0].room_id, root_id);
|
||||
});
|
||||
// impl register previous message ?
|
||||
await registerMessageInRoom(this.messageId, roomId, this.isSeen, this.envelope.date);
|
||||
await this.registerMembers(roomId);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
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 this.initiateThread();
|
||||
await createThread(this.envelope.subject, this.ownerId, this.messageId, roomId, this.isDm()).then(
|
||||
async (threadId) => {
|
||||
await registerMessageInThread(this.messageId, threadId, this.isSeen);
|
||||
@ -105,7 +137,7 @@ class registerMessageInApp {
|
||||
initiateRoom(this.envelope, this.ownerId, this.messageId, this.isSeen);
|
||||
}
|
||||
} else {
|
||||
await this.createOrRegisterOnExistence(this.ownerId, roomType.ROOM);
|
||||
await this.createOrRegisterOnExistence(this.ownerId, roomType.CHANNEL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
21
back/mails/utils/envelopeUtils.js
Normal file
21
back/mails/utils/envelopeUtils.js
Normal file
@ -0,0 +1,21 @@
|
||||
function nbMembers(envelope) {
|
||||
return getMembers(envelope).length;
|
||||
}
|
||||
|
||||
function getMembers(envelope) {
|
||||
const members = [];
|
||||
const fields = ["from", "to", "sender", "replyTo", "cc", "bcc"];
|
||||
fields.forEach((field) => {
|
||||
if (!envelope[field]) return;
|
||||
envelope[field].forEach((member) => {
|
||||
if (members.find((m) => m.mailbox === member.mailbox && m.host === member.host)) return;
|
||||
members.push(member);
|
||||
});
|
||||
});
|
||||
return members;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
nbMembers,
|
||||
getMembers,
|
||||
};
|
@ -1,18 +0,0 @@
|
||||
function nbMembers(envelope) {
|
||||
let nbMembers =
|
||||
(envelope.bcc?.length ?? 0) +
|
||||
(envelope.cc?.length ?? 0) +
|
||||
(envelope.to?.length ?? 0) +
|
||||
(envelope.from?.length ?? 0);
|
||||
if (
|
||||
envelope.sender?.length > 0 &&
|
||||
!(envelope.sender[0].mailbox == envelope.from[0].mailbox && envelope.sender[0].host == envelope.from[0].host)
|
||||
) {
|
||||
nbMembers += envelope.sender?.length ?? 0;
|
||||
}
|
||||
return nbMembers;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
nbMembers,
|
||||
};
|
45
back/test/mail/utils/envelopeUtils-test.js
Normal file
45
back/test/mail/utils/envelopeUtils-test.js
Normal file
@ -0,0 +1,45 @@
|
||||
const { nbMembers } = require("../../../mails/utils/envelopeUtils");
|
||||
const { generateUsers } = require("../../test-utils/test-attrsUtils");
|
||||
|
||||
describe("envelopeUtils", () => {
|
||||
const names = generateUsers(6);
|
||||
describe("nbMembers", () => {
|
||||
it("sender and from shouldn't be counted twice if there are the same", () => {
|
||||
const envelope = {
|
||||
from: [names[0].user],
|
||||
sender: [names[0].user],
|
||||
replyTo: null,
|
||||
to: null,
|
||||
cc: null,
|
||||
bcc: null,
|
||||
inReplyTo: null,
|
||||
};
|
||||
expect(nbMembers(envelope)).toBe(1);
|
||||
});
|
||||
it("sender and from shoud be counted twice if there are the same", () => {
|
||||
const envelope = {
|
||||
from: [names[0].user],
|
||||
sender: [names[1].user],
|
||||
replyTo: null,
|
||||
to: null,
|
||||
cc: null,
|
||||
bcc: null,
|
||||
inReplyTo: null,
|
||||
};
|
||||
expect(nbMembers(envelope)).toBe(2);
|
||||
});
|
||||
it("should count every members", () => {
|
||||
// todo should merge identic members
|
||||
const envelope = {
|
||||
from: [names[0].user],
|
||||
sender: [names[1].user],
|
||||
replyTo: [names[2].user],
|
||||
to: [names[3].user],
|
||||
cc: [names[4].user],
|
||||
bcc: [names[5].user],
|
||||
inReplyTo: null,
|
||||
};
|
||||
expect(nbMembers(envelope)).toBe(6);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,40 +0,0 @@
|
||||
const { nbMembers } = require("../../../mails/utils/statusUtils");
|
||||
|
||||
describe("statusUtils", () => {
|
||||
it("sender and from shouldn't be counted twice if there are the same", () => {
|
||||
const envelope = {
|
||||
from: [{ name: "", mailbox: "user_1", host: "provider.com" }],
|
||||
sender: [{ name: "", mailbox: "user_1", host: "provider.com" }],
|
||||
replyTo: [{ name: "", mailbox: "user_1", host: "provider.com" }],
|
||||
to: null,
|
||||
cc: null,
|
||||
bcc: null,
|
||||
inReplyTo: null,
|
||||
};
|
||||
expect(nbMembers(envelope)).toBe(1);
|
||||
});
|
||||
it("sender and from shoud be counted twice if there are the same", () => {
|
||||
const envelope = {
|
||||
from: [{ name: "", mailbox: "user_1", host: "provider.com" }],
|
||||
sender: [{ name: "", mailbox: "user_2", host: "provider.com" }],
|
||||
replyTo: [{ name: "", mailbox: "user_1", host: "provider.com" }],
|
||||
to: null,
|
||||
cc: null,
|
||||
bcc: null,
|
||||
inReplyTo: null,
|
||||
};
|
||||
expect(nbMembers(envelope)).toBe(2);
|
||||
});
|
||||
it("should count every members", () => {
|
||||
const envelope = {
|
||||
from: [{ name: "", mailbox: "user_1", host: "provider.com" }],
|
||||
sender: [{ name: "", mailbox: "user_2", host: "provider.com" }],
|
||||
replyTo: [{ name: "", mailbox: "user_1", host: "provider.com" }],
|
||||
to: [{ name: "", mailbox: "user_1", host: "provider.com" }],
|
||||
cc: [{ name: "", mailbox: "user_1", host: "provider.com" }],
|
||||
bcc: [{ name: "", mailbox: "user_1", host: "provider.com" }],
|
||||
inReplyTo: null,
|
||||
};
|
||||
expect(nbMembers(envelope)).toBe(5);
|
||||
});
|
||||
});
|
@ -1,19 +0,0 @@
|
||||
beforeAll(async () => {
|
||||
// const schema = fs.readFileSync('../../sql/structureV2.sql', 'utf8');
|
||||
// await setupDB(mysqlConfig, schema);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
global.db.query("DROP database mail_test");
|
||||
});
|
||||
|
||||
describe('saveMessageApp', async () => {
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
});
|
||||
|
||||
it("", () => {
|
||||
|
||||
});
|
||||
});
|
61
back/test/test-utils/test-attrsUtils.js
Normal file
61
back/test/test-utils/test-attrsUtils.js
Normal file
@ -0,0 +1,61 @@
|
||||
const { names } = require("./names");
|
||||
|
||||
function generateAttrs(options) {
|
||||
const attrs = {
|
||||
"size": 42,
|
||||
"envelope": {
|
||||
date: "2023-03-21T15:25:42.000Z",
|
||||
subject: options.subject ?? "subject" + randomString(10),
|
||||
from: options.from ?? null,
|
||||
sender: options.sender ?? null,
|
||||
replyTo: options.replyTo ?? null,
|
||||
to: options.to ?? null,
|
||||
cc: options.cc ?? null,
|
||||
bcc: options.bcc ?? null,
|
||||
inReplyTo: options.inReplyTo ?? null,
|
||||
messageId: options.messageId ?? randomString(10),
|
||||
},
|
||||
"date": options.date ?? new Date(),
|
||||
"flags": options.flags ?? [],
|
||||
"uid": options.uid ?? randomInt(3),
|
||||
"modseq": options.modseq ?? randomInt(7),
|
||||
"x-gm-labels": ["\\Inbox"],
|
||||
"x-gm-msgid": "1760991478422670209",
|
||||
"x-gm-thrid": "1760991478422670209",
|
||||
};
|
||||
return attrs;
|
||||
}
|
||||
|
||||
function generateUsers(nb) {
|
||||
const users = [];
|
||||
for (let i = 0; i < nb; i++) {
|
||||
users.push({
|
||||
user: {
|
||||
name: "",
|
||||
mailbox: names[i],
|
||||
host: "provider.com",
|
||||
},
|
||||
id: i,
|
||||
});
|
||||
}
|
||||
return users;
|
||||
}
|
||||
|
||||
function randomString(length) {
|
||||
let result = "";
|
||||
const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
const charactersLength = characters.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function randomInt(length) {
|
||||
return (Math.random() * Math.pow(10, length)).toFixed();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
generateAttrs,
|
||||
generateUsers,
|
||||
};
|
Loading…
Reference in New Issue
Block a user