save message working without reply

This commit is contained in:
grimhilt
2023-03-16 16:14:25 +01:00
parent 95f39cf53a
commit 14e64c1fc3
10 changed files with 240 additions and 248 deletions

60
back/db/db.js Normal file
View File

@@ -0,0 +1,60 @@
const mysql = require("mysql");
const MYSQL = require("./config.json").mysql;
const DEBUG = require("../utils/debug.js").DEBUG;
const db = mysql.createConnection({
host: MYSQL.host,
user: MYSQL.user,
password: MYSQL.pwd,
database: MYSQL.database,
});
db.connect(function (err) {
if (err) {
DEBUG.log("Impossible de se connecter", err.code);
} else {
DEBUG.log("Database successfully connected");
}
});
function execQueryAsync(query, values) {
return new Promise((resolve, reject) => {
db.query(query, values, (err, results, fields) => {
if (err) {
reject(err);
} else {
resolve(results);
}
});
});
}
function execQueryAsyncWithId(query, values) {
return new Promise((resolve, reject) => {
db.query(query, values, (err, results, fields) => {
if (err) {
reject(err);
} else {
resolve(results.insertId);
}
});
});
}
function execQuery(query, values) {
db.query(query, values, (err, results, fields) => {
if (err) {
DEBUG.log(err);
throw (err);
}
return results;
});
}
module.exports = {
db, // todo remove this
execQuery,
execQueryAsync,
execQueryAsyncWithId
};

44
back/db/mail.js Normal file
View File

@@ -0,0 +1,44 @@
const { db, execQueryAsync, execQueryAsyncWithId } = require("./db.js");
const DEBUG = require("../utils/debug").DEBUG;
function isValidEmail(email) {
// todo
return true;
}
async function getAddresseId(email, name) {
const localpart = email.split("@")[0];
const domain = email.split("@")[1];
const query = `INSERT INTO address
(address_name, localpart, domain, email) VALUES (?, ?, ?, ?)
ON DUPLICATE KEY UPDATE email = ?, address_id = LAST_INSERT_ID(address_id)`;
const values = [name, localpart, domain, email, email];
return await execQueryAsyncWithId(query, values);
}
function getMailboxId(email) {
return new Promise((resolve, reject) => {
resolve(0)
});
// todo
}
async function getFieldId(field) {
const query = `INSERT INTO field_name (field_name) VALUES (?) ON DUPLICATE KEY UPDATE field_id=LAST_INSERT_ID(field_id)`;
const values = [field]
return await execQueryAsyncWithId(query, values);
}
async function findRoomByOwner(ownerId) {
const query = `SELECT room_id FROM app_room WHERE owner_id = ?`;
const values = [ownerId];
return await execQueryAsync(query, values);
}
module.exports = {
getAddresseId,
getMailboxId,
getFieldId,
findRoomByOwner,
};

73
back/db/saveMessage.js Normal file
View File

@@ -0,0 +1,73 @@
const { db, execQuery, execQueryAsync, execQueryAsyncWithId } = require("./db.js");
const DEBUG = require("../utils/debug").DEBUG;
async function registerMessage(timestamp, rfc822size, messageId) {
const query = `
INSERT INTO message
(idate, messageID, rfc822size) VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE message_id = LAST_INSERT_ID(message_id)
`;
const values = [timestamp, messageId, rfc822size];
return await execQueryAsyncWithId(query, values);
}
function registerMailbox_message(mailboxId, uid, messageId, modseq, seen, deleted) {
const query = `
INSERT IGNORE INTO mailbox_message
(mailbox_id, uid, message_id, modseq, seen, deleted) VALUES (?, ?, ?, ?, ?, ?)
`;
const values = [mailboxId, uid, messageId, modseq, seen, deleted];
execQuery(query, values);
}
function registerBodypart(messageId, part, bodypartId, bytes, nbLines) {
const query = `
INSERT IGNORE INTO part_number
(message_id, part, bodypart_id, bytes, nb_lines) VALUES (?, ?, ?, ?, ?)
`;
const values = [messageId, part, bodypartId, bytes, nbLines];
execQuery(query, values);
}
async function saveBodypart(bytes, hash, text, data) {
const query = `INSERT IGNORE INTO bodypart (bytes, hash, text, data) VALUES (?, ?, ?,)`;
const values = [bytes, hash, text, data];
return await execQueryAsyncWithId(query, values);
}
async function saveHeader_fields(messageId, fieldId, bodypartId, part, value) {
const query = `
INSERT IGNORE INTO header_field
(message_id, field_id, bodypart_id, part, value) VALUES (?, ?, ?, ?, ?)
`;
const values = [messageId, fieldId, bodypartId, part, value];
return await execQueryAsync(query, values);
}
async function saveAddress_fields(messageId, fieldId, addressId, number) {
const query = `
INSERT IGNORE INTO address_field
(message_id , field_id, address_id, number) VALUES (?, ?, ?, ?)
`;
const values = [messageId, fieldId, addressId, number];
return await execQueryAsync(query, values);
}
function saveSource(messageId, content) {
const query = `
INSERT INTO source (message_id, content) VALUES (?, ?)
ON DUPLICATE KEY UPDATE content = ?
`;
const values = [messageId, content, content];
execQuery(query, values);
}
module.exports = {
registerMessage,
registerMailbox_message,
saveHeader_fields,
saveAddress_fields,
registerBodypart,
saveBodypart,
saveSource
}

89
back/db/saveMessageApp.js Normal file
View File

@@ -0,0 +1,89 @@
const { db, execQueryAsync, execQueryAsyncWithId } = require("./db.js");
const DEBUG = require("../utils/debug").DEBUG;
async function createRoom(roomName, ownerId) {
const query = `INSERT INTO app_room (room_name, owner_id) VALUES (?, ?)`;
const values = [roomName.substring(0, 255), ownerId];
return await execQueryAsyncWithId(query, values);
// todo add members
}
async function registerMessageInRoom(messageId, roomId, isSeen) {
const query = `INSERT INTO app_space_message (message_id, room_id) VALUES (?, ?)`;
const values = [messageId, roomId];
await execQueryAsync(query, values);
updateLastUpdateRoom(roomId);
if (!isSeen) {
incrementNotSeenRoom(roomId);
}
}
function updateLastUpdateRoom(roomId) {
// todo
}
function incrementNotSeenRoom(roomId) {
// todo
}
async function createThread(roomId, threadName, isDm) {
const query = `INSERT INTO app_thread (room_id, thread_name, isDm) VALUES (?, ?, ?)`;
const values = [roomId, threadName, isDm];
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
const query = `INSERT IGNORE INTO app_space_message
(message_id, thread_id) VALUES (?, ?)`;
const values = [messageId, threadId];
await execQueryAsync(query, values);
updateLastUpdateThread(threadId);
if (!isSeen) {
incrementNotSeenThread(threadId);
}
}
function updateLastUpdateRoom(threadId) {
// todo
// check for parent
}
function incrementNotSeenThread(threadId) {
// todo
// also increment parent room
}
async function isRoomGroup(roomId) {
return new Promise((resolve, reject) => {
const query = `SELECT isGroup FROM app_room WHERE room_id = '${roomId}'`;
db.query(query, (err, results, fields) => {
if (err) reject(err);
resolve(results[0].isGroup);
});
});
}
async function findSpacesFromMessage(messageId) {
const query = `SELECT room_id, thread_id FROM app_space_message WHERE message_id = '${messageId}'`;
return await execQueryAsync(query);
}
async function hasSameMembersAsParent(messageId, parentID) {
// const query = `SELECT `;
// return await execQueryAsync(query)
// todo
}
module.exports = {
createRoom,
registerMessageInRoom,
createThread,
registerMessageInThread,
isRoomGroup,
findSpacesFromMessage,
};

157
back/db/structure Normal file
View File

@@ -0,0 +1,157 @@
create table addresses (
id int not null auto_increment,
name text,
localpart text not null,
domain text not null,
email text not null,
primary key (id),
unique key (email)
);
create table mailboxes (
-- Grant: select, insert, update
id serial primary key,
name text not null unique,
-- owner int references users(id), todo
-- The UID that will be assigned to the next delivered message.
-- Incremented after each successful delivery.
uidnext int not null default 1,
-- The next modsequence value for this mailbox.
nextmodseq bigint not null default 1,
-- The UID of the first message that should be marked \Recent.
-- Set to uidnext when each new IMAP session is created.
first_recent int not null default 1,
-- The IMAP mailbox UIDVALIDITY value, which, along with a message UID,
-- is forever guaranteed to uniquely refer to a single message.
uidvalidity int not null default 1,
-- When a mailbox is deleted, its entry is marked (not removed), so
-- that its UIDVALIDITY can be incremented if it is ever re-created.
deleted boolean not null default false
);
/**
* Store message
*/
create table messages (
-- Grant: select, insert
id int primary key auto_increment,
-- the time the message was added to the mailbox, as a unix time_t
idate timestamp not null,
-- the size of the message in RFC 822 format, in bytes
rfc822size int
);
-- todo make this work
-- foreign key (mailbox) references mailboxes(id),
-- foreign key (uid) references messages(id),
create table mailbox_messages (
-- Grant: select, insert, update
mailbox int not null,
-- the message's number in the mailbox
uid int not null,
message int not null,
modseq bigint not null,
seen boolean not null default false,
deleted boolean not null default false,
primary key (mailbox, uid)
);
-- tood should not be auto increment but nextval('bodypart_ids')
create table bodyparts (
-- Grant: select, insert
id int primary key auto_increment,
-- the size of either text or data, whichever is used
bytes int not null,
-- MD5 hash of either text or data
hash text not null,
text text,
data binary
);
create table part_numbers (
-- Grant: select, insert
message int references messages(id) on delete cascade,
part text not null,
bodypart int references bodyparts(id),
bytes int,
nbLines int,
primary key (message)
);
create table field_names (
-- Grant: select, insert
id serial primary key,
name text unique
);
-- add foreign key (message, part)
-- references part_numbers(message, part)
--on delete cascade at the end
-- references field_names(id) to field
create table header_fields (
-- Grant: select, insert
id serial primary key,
message int not null,
part text not null,
position int not null,
field int not null,
value text,
unique (message, part, position, field)
);
create table address_fields (
-- Grant: select, insert
message int not null,
part text not null,
position int not null,
field int not null,
number int,
address int not null-- references addresses(id),
-- foreign key (message, part)
-- references part_numbers(message, part)
-- on delete cascade
);
create table date_fields (
-- Grant: select, insert
message int not null references messages(id)
on delete cascade,
value timestamp --with time zone
);
/**
* APP tables
*/
create table app_accounts (
id int not null auto_increment,
user varchar(255) not null,
password binary(20),
xoauth varchar(116),
xoauth2 varchar(116),
host varchar(255) not null default 'localhost',
port int(5) not null default 143,
tls int(1) not null default 0,
primary key (id)
);
create table app_rooms (
id int not null auto_increment,
name text not null,
owner int not null,
isGroup BIT(1) not null default 0,
notSeen int not null default 0,
lastUpdate timestamp not null,
primary key (id)
);
create table app_room_messages (
message int [not null]
room int,
primary key()
)

168
back/db/structureV2.sql Normal file
View File

@@ -0,0 +1,168 @@
-- Mail storage
-- 1
CREATE TABLE address (
address_id INT AUTO_INCREMENT,
address_name TEXT,
localpart TEXT NOT NULL,
domain TEXT NOT NULL,
email TEXT NOT NULL,
PRIMARY KEY (address_id),
UNIQUE KEY (email)
);
-- 2 app
CREATE TABLE app_account (
account_id INT AUTO_INCREMENT,
user_id INT NOT NULL,
account_pwd BINARY(22),
xoauth VARCHAR(116),
xoauth2 VARCHAR(116),
host VARCHAR(255) NOT NULL DEFAULT 'localhost',
port INT(5) NOT NULL DEFAULT 143,
tls BOOLEAN NOT NULL DEFAULT true,
PRIMARY KEY (account_id),
FOREIGN KEY (user_id) REFERENCES address(address_id) ON DELETE CASCADE
);
-- 3
CREATE TABLE mailbox (
mailbox_id INT AUTO_INCREMENT,
account_id INT NOT NULL,
mailbox_name TEXT NOT NULL,
uidnext INT NOT NULL DEFAULT 1,
nextmodseq BIGINT NOT NULL DEFAULT 1,
first_recent INT NOT NULL DEFAULT 1,
uidvalidity INT NOT NULL DEFAULT 1,
PRIMARY KEY (mailbox_id),
UNIQUE KEY (mailbox_name),
FOREIGN KEY (account_id) REFERENCES app_account(account_id) ON DELETE CASCADE
);
-- 4
CREATE TABLE message (
message_id INT AUTO_INCREMENT,
messageID TEXT NOT NULL,
idate TIMESTAMP NOT NULL,
rfc822size INT NOT NULL,
PRIMARY KEY (message_id),
UNIQUE KEY (messageID)
);
-- 5
-- if mailbox_message deleted message is not deleted
CREATE TABLE mailbox_message (
mailbox_id INT NOT NULL,
uid INT,
message_id INT,
modseq BIGINT NOT NULL,
seen BOOLEAN NOT NULL DEFAULT false,
deleted BOOLEAN NOT NULL DEFAULT false,
PRIMARY KEY (uid, message_id),
FOREIGN KEY (mailbox_id) REFERENCES mailbox(mailbox_id) ON DELETE CASCADE,
FOREIGN KEY (message_id) REFERENCES message(message_id) ON DELETE CASCADE
);
-- 6
CREATE TABLE bodypart (
bodypart_id INT AUTO_INCREMENT,
bytes INT NOT NULL,
hash TEXT NOT NULL,
text TEXT,
data BINARY,
PRIMARY KEY (bodypart_id)
);
-- 7
CREATE TABLE source (
message_id INT NOT NULL,
content TEXT NOT NULL,
PRIMARY KEY (message_id),
FOREIGN KEY (message_id) REFERENCES message(message_id) ON DELETE CASCADE
);
-- 8
CREATE TABLE field_name (
field_id INT AUTO_INCREMENT,
field_name VARCHAR (255),
PRIMARY KEY (field_id),
UNIQUE KEY (field_name)
);
-- 9
CREATE TABLE header_field (
message_id INT NOT NULL,
field_id INT NOT NULL,
bodypart_id INT,
part VARCHAR(128),
value TEXT NOT NULL,
UNIQUE KEY (message_id, field_id, bodypart_id),
FOREIGN KEY (message_id) REFERENCES message(message_id) ON DELETE CASCADE,
FOREIGN KEY (field_id) REFERENCES field_name(field_id), -- todo on delete behavior
FOREIGN KEY (bodypart_id) REFERENCES bodypart(bodypart_id)
);
-- 10
CREATE TABLE address_field (
message_id INT NOT NULL,
field_id INT NOT NULL,
address_id INT NOT NULL,
number INT,
UNIQUE KEY (message_id, field_id, address_id),
FOREIGN KEY (message_id) REFERENCES message(message_id) ON DELETE CASCADE,
FOREIGN KEY (field_id) REFERENCES field_name(field_id),
FOREIGN KEY (address_id) REFERENCES address(address_id)
);
-- App table
-- 11
CREATE TABLE app_room (
room_id INT AUTO_INCREMENT,
room_name VARCHAR(255) NOT NULL,
owner_id INT NOT NULL,
isGroup BOOLEAN NOT NULL DEFAULT false,
notSeen INT NOT NULL DEFAULT 0,
lastUpdate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP(),
PRIMARY KEY (room_id),
FOREIGN KEY (owner_id) REFERENCES address(address_id)
);
-- 12
CREATE TABLE app_thread (
thread_id INT AUTO_INCREMENT,
room_id INT NOT NULL,
thread_name VARCHAR(255) NOT NULL,
notSeen INT NOT NULL DEFAULT 0,
lastUpdate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP(),
isDm BOOLEAN NOT NULL DEFAULT false,
PRIMARY KEY (thread_id),
FOREIGN KEY (room_id) REFERENCES app_room(room_id) ON DELETE CASCADE
);
-- 13
CREATE TABLE app_space_message (
message_id INT NOT NULL,
room_id INT,
thread_id INT,
UNIQUE KEY (member_id, room_id, thread_id),
FOREIGN KEY (message_id) REFERENCES message(message_id) ON DELETE CASCADE,
FOREIGN KEY (room_id) REFERENCES app_room(room_id) ON DELETE SET NULL,
FOREIGN KEY (thread_id) REFERENCES app_thread(thread_id) ON DELETE SET NULL
);
-- 14
CREATE TABLE app_room_member (
room_id INT NOT NULL,
member_id INT NOT NULL,
FOREIGN KEY (room_id) REFERENCES app_room(room_id) ON DELETE CASCADE,
FOREIGN KEY (member_id) REFERENCES address(address_id)
);
-- 14
CREATE TABLE app_thread_member (
thread_id INT NOT NULL,
member_id INT NOT NULL,
FOREIGN KEY (thread_id) REFERENCES app_thread(thread_id) ON DELETE CASCADE,
FOREIGN KEY (member_id) REFERENCES address(address_id)
);