load message in front

This commit is contained in:
grimhilt 2023-03-25 13:06:59 +01:00
parent 926dc60920
commit 4d4ef54bcb
12 changed files with 246 additions and 131 deletions

View File

@ -4,7 +4,7 @@ const { getMessages } = require("../db/api.js");
async function messages(body, res) {
const { roomId } = body;
getMessages(roomId).then((messages) => {
res.status(statusCode.OK).json(messages.data);
res.status(statusCode.OK).json(messages);
}).catch((err) => {
console.log(err)
res.status(statusCode.INTERNAL_SERVER_ERROR);

View File

@ -12,9 +12,11 @@ async function registerMailbox(userId, pwd, xoauth, xoauth2, host, port, tls) {
async function getMailboxes() {
const query = `
SELECT app_account.account_id AS id, address.email
FROM app_account INNER JOIN address
WHERE address.address_id = app_account.user_id
SELECT
app_account.account_id AS id,
address.email
FROM app_account INNER JOIN address
WHERE address.address_id = app_account.user_id
`;
const values = [];
return await execQueryAsync(query, values);
@ -46,31 +48,68 @@ async function getRooms(mailboxId) {
async function getMessages(roomId) {
// todo attachements name
// todo html, text, textAsHtml
// todo datetime
const query = `
SELECT
address_field.address_id,
bodypart.text,
header_field.value
FROM bodypart
INNER JOIN header_field
INNER JOIN address_field
msg.message_id AS id,
GROUP_CONCAT(fromT.address_id) AS fromA,
GROUP_CONCAT(toT.address_id) AS toA,
GROUP_CONCAT(ccT.address_id) AS ccA,
subjectT.value AS subject,
content.text AS content,
message.idate AS date
FROM app_room_message msg
LEFT JOIN (
SELECT address_field.address_id, address_field.message_id
FROM address_field
INNER JOIN field_name
WHERE
(
header_field.field_id = field_name.field_id OR
address_field.field_id = field_name.field_id
) AND
(
field_name.field_name = 'html' OR
field_name.field_name = 'text' OR
field_name.field_name = 'textAsHtml' OR
field_name.field_name = 'to' OR
field_name.field_name = 'cc' OR
field_name.field_name = 'subject'
)
`;
// todo roomID
const values = [];
field_name.field_id = address_field.field_id AND
field_name.field_name = 'from'
) fromT ON msg.message_id = fromT.message_id
LEFT JOIN (
SELECT address_field.address_id, address_field.message_id
FROM address_field
INNER JOIN field_name
WHERE
field_name.field_id = address_field.field_id AND
field_name.field_name = 'to'
) toT ON msg.message_id = toT.message_id
LEFT JOIN (
SELECT address_field.address_id, address_field.message_id
FROM address_field
INNER JOIN field_name
WHERE
field_name.field_id = address_field.field_id AND
field_name.field_name = 'cc'
) ccT ON msg.message_id = ccT.message_id
LEFT JOIN (
SELECT header_field.message_id, header_field.value
FROM header_field
INNER JOIN field_name
WHERE
field_name.field_id = header_field.field_id AND
field_name.field_name = 'subject'
) subjectT ON msg.message_id = subjectT.message_id
LEFT JOIN (
SELECT bodypart.text, header_field.message_id FROM bodypart
INNER JOIN header_field
INNER JOIN field_name
WHERE
field_name.field_id = header_field.field_id AND
field_name.field_name = 'html' AND
bodypart.bodypart_id = header_field.bodypart_id
) content ON msg.message_id = content.message_id
INNER JOIN message ON message.message_id = msg.message_id
WHERE msg.room_id = ?
GROUP BY msg.message_id;
`;
const values = [roomId];
return await execQueryAsync(query, values);
}

View File

@ -14,10 +14,10 @@ async function registerMessage(timestamp, rfc822size, messageId) {
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 (1, 19, 10, '12450', 0, 0)
(mailbox_id, uid, message_id, modseq, seen, deleted) VALUES (?, ?, ?, ?, ?, ?)
`;
// todo
const values = [mailboxId, uid, messageId, modseq, seen, deleted];
console.log(values)
execQuery(query, values);
}

View File

@ -9,7 +9,7 @@ async function createRoom(roomName, ownerId, messageId) {
}
async function registerMessageInRoom(messageId, roomId, isSeen) {
const query = `INSERT INTO app_space_message (message_id, room_id) VALUES (?, ?)`;
const query = `INSERT IGNORE INTO app_room_message (message_id, room_id) VALUES (?, ?)`;
const values = [messageId, roomId];
await execQueryAsync(query, values);
@ -68,8 +68,8 @@ async function isRoomGroup(roomId) {
});
}
async function findSpacesFromMessage(messageId) {
const query = `SELECT room_id, thread_id FROM app_space_message WHERE message_id = '${messageId}'`;
async function findRoomsFromMessage(messageId) {
const query = `SELECT room_id FROM app_room_message WHERE message_id = '${messageId}'`;
return await execQueryAsync(query);
}
@ -85,5 +85,5 @@ module.exports = {
createThread,
registerMessageInThread,
isRoomGroup,
findSpacesFromMessage,
findRoomsFromMessage,
};

View File

@ -131,25 +131,24 @@ CREATE TABLE app_room (
-- 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(),
parent_room_id INT,
root_room_id INT,
isDm BOOLEAN NOT NULL DEFAULT false,
PRIMARY KEY (thread_id),
FOREIGN KEY (room_id) REFERENCES app_room(room_id) ON DELETE CASCADE
PRIMARY KEY (room_id),
UNIQUE KEY (room_id, parent_room_id, root_room_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
);
-- 13
CREATE TABLE app_space_message (
CREATE TABLE app_room_message (
message_id INT NOT NULL,
room_id INT,
thread_id INT,
UNIQUE KEY (message_id, room_id, thread_id),
UNIQUE KEY (message_id, room_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
FOREIGN KEY (room_id) REFERENCES app_room(room_id) ON DELETE SET NULL
);
-- 14
@ -159,11 +158,3 @@ CREATE TABLE app_room_member (
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)
);

View File

@ -28,6 +28,7 @@ if (shouldReset) {
execQuery("SET FOREIGN_KEY_CHECKS=0");
results.map((table) => {
execQuery("DELETE FROM " + table.table_name);
// execQuery("DROP TABLE " + table.table_name);
});
});
return;

View File

@ -19,6 +19,7 @@ const validate_mailbox = ajv.compile(schema_mailbox);
*/
router.get("/mailboxes", (req, res) => {
getMailboxes().then((data) => {
data[0].id = 1; // todo debug
res.status(statusCodes.OK).json(data)
});
});
@ -49,9 +50,10 @@ router.get("/:roomId/messages", async (req, res) => {
* Register a new mailbox inside the app
*/
router.post("/mailbox", async (req, res) => {
console.log(req.body)
const valid = validate_mailbox(req.body);
if (!valid) {
res.status(statusCodes.NOT_ACCEPTABLE).send(validate_mailbox.errors)
res.status(statusCodes.NOT_ACCEPTABLE).send({ error: validate_mailbox.errors });
} else {
await addMailbox(req.body, res);
}

View File

@ -0,0 +1,13 @@
export default class Room {
constructor(id, user, userId, roomName, mailboxId) {
this.id = id;
this.user = user;
this.userId = userId;
this.roomName = roomName;
this.mailboxId = mailboxId;
this.messages = [];
this.messagesFetched = false;
this.threads = [];
}
}

View File

@ -1,42 +1,19 @@
import API from "@/services/imapAPI";
import { createStore } from "vuex";
import Room from "./models/Room";
const store = createStore({
state() {
return {
rooms: [
{
id: 0,
user: "clemnce",
userId: 0,
roomName: "Lorem magna minim cillum labore ex eiusmod proident excepteur sint irure ipsum.",
mailboxId: 1,
},
{
id: 1,
user: "juliette",
roomName: "Lorem magna minim cillum labore ex eiusmod proident excepteur sint irure ipsum.",
mailboxId: 1,
},
{
id: 2,
user: "jean",
roomName: "Lorem magna minim cillum labore ex eiusmod proident excepteur sint irure ipsum.",
mailboxId: 2,
},
{
id: 3,
user: "luc",
roomName: "Lorem magna minim cillum labore ex eiusmod proident excepteur sint irure ipsum.",
mailboxId: 2,
},
],
messages: [
new Room(1, "clemence", 0, "Est ex adipisicing non ipsum voluptate duis enim adipisicing labore.", 1),
new Room(2, "laurance", 0, "Est ex adipisicing non ipsum voluptate duis enim adipisicing labore.", 2),
new Room(3, "mathilde", 0, "Est ex adipisicing non ipsum voluptate duis enim adipisicing labore.", 1),
],
messages: [],
mailboxes: [],
activeMailbox: 0,
activeRoom: 0
activeRoom: 0,
};
},
mutations: {
@ -48,16 +25,18 @@ const store = createStore({
const mailbox = state.mailboxes.find((mailbox) => mailbox.id == payload);
// todo fetched mailbox all
if (mailbox?.fetched == false) {
API.getRooms(payload).then((res) => {
// todo add if not exist
mailbox.fetched = true;
res.data.forEach((room) => {
room.fetched = false;
state.rooms.push(room);
API.getRooms(payload)
.then((res) => {
// todo add if not exist
console.log(res.data)
mailbox.fetched = true;
res.data.forEach((room) => {
state.rooms.push(new Room(room.id, room.user, room.userId, room.roomName, room.mailboxId));
});
})
.catch((err) => {
console.log(err);
});
}).catch((err) => {
console.log(err)
});
}
},
setActiveRoom(state, payload) {
@ -66,24 +45,35 @@ const store = createStore({
// fetch messages for this room if not already fetched
const room = state.rooms.find((room) => room.id == payload);
if (!room || room?.fetched == false) {
console.log("add messages")
API.getMessages(payload).then((res) => {
// todo add if not exist
room.fetched = true;
res.data.forEach((msg) => {
state.messages.push(msg);
console.log("add messages");
API.getMessages(payload)
.then((res) => {
// todo add if not exist
room.fetched = true;
res.data.forEach((msg) => {
state.messages.push(msg);
});
})
.catch((err) => {
console.log(err);
});
}).catch((err) => {
console.log(err)
});
}
},
addMailboxes(state, payload) {
console.log(payload)
payload.forEach((mailbox) => {
mailbox.fetched = false;
state.mailboxes.push(mailbox);
});
},
addMessages(state, payload) {
const room = state.rooms.find((room) => room.id == payload.roomId);
payload.messages.forEach((message) => {
room.messages.push(message);
});
room.messagesFetched = true;
console.log(room.messages)
},
},
getters: {
rooms: (state) => () => {
@ -91,16 +81,16 @@ const store = createStore({
return state.rooms.filter((room) => room.mailboxId == state.activeMailbox);
},
messages: (state) => (roomId) => {
const room = state.rooms.find((room) => room.id === roomId);
if (room?.fetched === false) {
console.log("ok")
const room = state.rooms.find((room) => room.id == roomId);
if (!room.messagesFetched) {
console.log("fetched Messages")
store.dispatch("fetchMessages", { roomId: room.id });
}
return [1, 2];
}
return room.messages;
},
},
actions: {
async fetchMailboxes(context) {
console.log("add mailboxes");
fetchMailboxes: async (context) => {
API.getMailboxes()
.then((res) => {
context.commit("addMailboxes", res.data);
@ -109,8 +99,15 @@ const store = createStore({
console.log(err);
});
},
async fetchMessages(context) {
console.log(context)
fetchMessages: async (context, data) => {
API.getMessages(data.roomId)
.then((res) => {
console.log(res.data)
context.commit("addMessages", { messages: res.data, roomId: data.roomId });
})
.catch((err) => {
console.log(err);
});
},
},
});

View File

@ -19,7 +19,7 @@ export default {
<style scoped>
#main {
background-color: blue;
border-bottom: 1px solid #505050;
width: 100%;
height: 51px;
}

View File

@ -1,30 +1,72 @@
<script setup>
const data = {
html: "<div dir=\"ltr\">new content<br><div><br><div class=\"gmail_quote\"><div dir=\"ltr\" class=\"gmail_attr\">---------- Forwarded message ---------<br>De : <b class=\"gmail_sendername\" dir=\"auto\">Ulysse Carlier</b> <span dir=\"auto\">&lt;<a href=\"mailto:carlierulysse@gmail.com\">carlierulysse@gmail.com</a>&gt;</span><br>Date: ven. 10 mars 2023 à 14:52<br>Subject: message to transfer<br>To: Hugueprime M &lt;<a href=\"mailto:hugueprime@gmail.com\">hugueprime@gmail.com</a>&gt;<br></div><br><br><div dir=\"ltr\">content to transfer<br></div>\n</div></div></div>\n",
text: "new content\n\n---------- Forwarded message ---------\nDe : Ulysse Carlier <carlierulysse@gmail.com>\nDate: ven. 10 mars 2023 à 14:52\nSubject: message to transfer\nTo: Hugueprime M <hugueprime@gmail.com>\n\n\ncontent to transfer\n",
textAsHtml: "<p>new content</p><p>---------- Forwarded message ---------<br/>De : Ulysse Carlier &lt;<a href=\"mailto:carlierulysse@gmail.com\">carlierulysse@gmail.com</a>&gt;<br/>Date: ven. 10 mars 2023 &agrave; 14:52<br/>Subject: message to transfer<br/>To: Hugueprime M &lt;<a href=\"mailto:hugueprime@gmail.com\">hugueprime@gmail.com</a>&gt;</p><p>content to transfer</p>",
subject: "Fwd: message to transfer",
references: "<CAAGJdR0i=4w1i2Nb9=zx5bCPqkR+2eUCs=_qbXTSzugZu4EXFQ@mail.gmail.com>",
date: "2023-03-10T13:52:21.000Z",
}
import { defineProps } from "vue";
const props = defineProps({ data: Object });
console.log(props.data.date);
const date = new Date(props.data.date);
console.log(date);
</script>
<!-- to if to is more than me
<!-- to if to is more than me
cc -->
<!-- object (channel only)
<!-- object (channel only)
content
attachments -->
<template>
<div class="message">
<!-- <div v-html="data.html"></div> -->
<!-- <div v-html="data.text"></div> -->
<div></div>
<div v-html="data.textAsHtml"></div>
<div id="context">
<div class="left" id="profile">Carrefour@emailing .carrefor.fr "carrefour"</div>
<div class="middle">{{ props.data.subject }}</div>
<div class="right" id="date">
{{
date.toLocaleString("en-GB", {
weekday: "short",
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
timezone: "UTC+1",
})
}}
</div>
</div>
<div id="content">
<div v-html="props.data.content"></div>
</div>
</div>
</template>
<style scoped>
.message {
width: 100%;
width: auto;
border: white 1px solid;
padding: 10px;
margin: 5px;
}
#context {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
#content {
overflow: auto;
max-height: 300px;
width: 750px; /* template width being 600px to 640px up to 750px (experiment and test) */
}
.left,
.right {
display: flex;
align-items: center;
}
.middle {
margin: 0 10px;
flex: 1;
align-self: center;
display: contents;
}
</style>

View File

@ -14,7 +14,8 @@ onBeforeMount(async () => {
console.log(store.state.rooms.find((room) => room.id === id)?.fetched);
let room = store.state.rooms.find((room) => room.id === id);
if (!room || room?.fetched === false) {
await store.dispatch("fetchMessages");
// todo
// await store.dispatch("fetchMessages", );
}
store.commit("setActiveRoom", id);
});
@ -28,20 +29,49 @@ onBeforeRouteUpdate(async (to, from) => {
</script>
<template>
<div>
<div id="main">
<Header></Header>
<div>
<Message v-for="(message, index) in store.getters.messages(id)" :key="index" :data="message" />
<b>{{ id }}</b>
{{ messages.length }}
<div id="RoomViewBody">
<div class="content">
<Message v-for="(message, index) in store.getters.messages(id)" :key="index" :data="message" />
<b>{{ id }}</b>
{{ messages.length }}
</div>
<div id="composer">COMPOSER</div>
</div>
</div>
</template>
<style scoped>
div {
#main {
background-color: #1d1d23;
color: white;
width: 100%;
}
#RoomViewBody {
display: flex;
flex-direction: column;
height: 100%;
}
#composer {
position: absolute;
bottom: 0;
width: 100%;
padding-top: 10px;
/* todo composer */
height: 35px;
background-color: red;
}
.content {
display: flex;
flex-direction: column;
overflow: auto;
margin-bottom: 100px;
}
</style>