save message working without reply
This commit is contained in:
60
back/db/db.js
Normal file
60
back/db/db.js
Normal 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
44
back/db/mail.js
Normal 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
73
back/db/saveMessage.js
Normal 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
89
back/db/saveMessageApp.js
Normal 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
157
back/db/structure
Normal 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
168
back/db/structureV2.sql
Normal 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)
|
||||
);
|
||||
Reference in New Issue
Block a user