From b137263bef04f16f3fb8f199ebb8000289021073 Mon Sep 17 00:00:00 2001 From: grimhilt Date: Sat, 6 May 2023 13:23:13 +0200 Subject: [PATCH] deletion of messages (failing on server) --- back/abl/Message-abl.ts | 38 +++++++++++++++ back/db/database.sql | 3 +- back/db/imap/imap-db.ts | 1 + back/db/message/updateMessage-db.ts | 10 +++- back/mails/imap/Mailbox.ts | 7 ++- back/routes/message.ts | 8 ++++ back/validator/schemas/delete-schema.json | 16 +++++++ back/validator/validator.ts | 5 ++ .../components/structure/message/Composer.vue | 1 + .../components/structure/message/Options.vue | 47 ++++++++++++------- front/src/services/imapAPI.ts | 6 +++ front/src/store/store.ts | 7 +++ front/src/utils/array.ts | 4 +- 13 files changed, 129 insertions(+), 24 deletions(-) create mode 100644 back/validator/schemas/delete-schema.json diff --git a/back/abl/Message-abl.ts b/back/abl/Message-abl.ts index 6352114..4bf0743 100644 --- a/back/abl/Message-abl.ts +++ b/back/abl/Message-abl.ts @@ -2,6 +2,7 @@ import statusCode from "../utils/statusCodes"; import { Response } from "express"; import { getMessageUid, getUserOfMailbox } from "../db/utils/mail"; import emailManager from "../mails/EmailManager"; +import { deleteMessage } from "../db/message/updateMessage-db"; export default class Message { static async addFlag(body, res: Response) { @@ -51,4 +52,41 @@ export default class Message { res.status(statusCode.METHOD_FAILURE).send({ error: err }); }); } + + static deleteRemoteOnly = async (body, res: Response) => { + body.flag = "\\Deleted"; + await this.addFlag(body, res); + }; + + static async deleteEverywhere(body, res: Response) { + const { mailboxId, messageId } = body; + const uid = (await getMessageUid(messageId))[0]?.uid; + if (!uid) { + res.status(statusCode.NOT_FOUND).send({ error: "Message uid not found." }); + } + + const user = (await getUserOfMailbox(mailboxId))[0]?.user; + if (!user) { + res.status(statusCode.NOT_FOUND).send({ error: "Not account for this mailbox." }); + } + emailManager + .getImap(user) + .getMailbox(mailboxId) + .removeFlag(uid.toString(), ["\\Deleted"]) + .then(() => { + deleteMessage(messageId) + .then((result) => { + // todo check if room is empty + res.status(statusCode.OK).send(); + }) + .catch((err) => { + res.status(statusCode.METHOD_FAILURE).send({ error: err }); + console.log(err); + }); + }) + .catch((err) => { + console.log(err); + res.status(statusCode.METHOD_FAILURE).send({ error: err }); + }); + } } diff --git a/back/db/database.sql b/back/db/database.sql index b9aebe3..a344dd8 100644 --- a/back/db/database.sql +++ b/back/db/database.sql @@ -127,7 +127,7 @@ CREATE TABLE app_room ( PRIMARY KEY (room_id), UNIQUE KEY (owner_id, message_id, room_type), FOREIGN KEY (owner_id) REFERENCES address(address_id), - FOREIGN KEY (message_id) REFERENCES message(message_id) + FOREIGN KEY (message_id) REFERENCES message(message_id) ON DELETE SET NULL ); -- 12 @@ -175,6 +175,5 @@ create table flag ( flag_id INT NOT NULL, UNIQUE KEY (message_id, flag_id), FOREIGN KEY (message_id) REFERENCES message(message_id) ON DELETE CASCADE, - FOREIGN KEY (message_id) REFERENCES message(message_id) ON DELETE CASCADE, FOREIGN KEY (flag_id) REFERENCES flag_name(flag_id) ON DELETE CASCADE ); \ No newline at end of file diff --git a/back/db/imap/imap-db.ts b/back/db/imap/imap-db.ts index c3c9a06..692e8a5 100644 --- a/back/db/imap/imap-db.ts +++ b/back/db/imap/imap-db.ts @@ -35,6 +35,7 @@ export async function getMailbox(mailboxId: number) { } export function updateMailbox(mailboxId: number, uidnext: number) { + console.log("updateMailbox", mailboxId, uidnext); const query = `UPDATE mailbox SET uidnext = ? WHERE mailbox_id = ?`; const values = [uidnext, mailboxId]; execQuery(query, values); diff --git a/back/db/message/updateMessage-db.ts b/back/db/message/updateMessage-db.ts index ab09221..76530ef 100644 --- a/back/db/message/updateMessage-db.ts +++ b/back/db/message/updateMessage-db.ts @@ -1,6 +1,6 @@ import { execQuery, execQueryAsync, execQueryAsyncWithId } from "../db"; -export async function getFlags(uid: number): Promise<{flag_id: number, flag_name: string}[]> { +export async function getFlags(uid: number): Promise<{ flag_id: number; flag_name: string }[]> { const query = ` SELECT * FROM flag_name INNER JOIN flag ON flag.flag_id = flag_name.flag_id @@ -27,4 +27,10 @@ export async function updateMailboxDeleted(messageId: number, isDeleted: boolean const query = `UPDATE mailbox_message SET deleted = ? WHERE message_id = ?`; const values = [messageId, isDeleted]; return await execQueryAsync(query, values); -} \ No newline at end of file +} + +export async function deleteMessage(messageId: number) { + const query = `DELETE FROM message WHERE message_id = ?`; + const values = [messageId]; + return await execQueryAsync(query, values); +} diff --git a/back/mails/imap/Mailbox.ts b/back/mails/imap/Mailbox.ts index 0265800..f7d1914 100644 --- a/back/mails/imap/Mailbox.ts +++ b/back/mails/imap/Mailbox.ts @@ -59,6 +59,7 @@ export default class Mailbox { updateMsg.updateFlags(); }); + // wait for deletion this.imap.on("expunge", (seqno: number) => { console.log("Message with sequence number " + seqno + " has been deleted from the server."); }); @@ -113,7 +114,7 @@ export default class Mailbox { try { // fetch mails let secondUid = savedUid + STEP < currentUid ? savedUid + STEP : currentUid; - await this.mailFetcher(savedUid, secondUid, mails) + await this.mailFetcher(savedUid, secondUid, mails); logger.log(`Fetched ${STEP} uids (${mails.length} messages)`); // save same in the database for (let k = 0; k < mails.length; k++) { @@ -194,4 +195,8 @@ export default class Mailbox { }); }); } + + move(source: string, mailboxName: string, callback: (error: Error) => void) { + this.imap.move(source, mailboxName, callback); + } } diff --git a/back/routes/message.ts b/back/routes/message.ts index 7a34c51..3b5394d 100644 --- a/back/routes/message.ts +++ b/back/routes/message.ts @@ -11,5 +11,13 @@ router.post("/removeFlag", async (req, res) => { await validator.validate("removeFlag", req.body, res, Message.removeFlag); }); +router.post("/deleteRemote", async(req, res) => { + await validator.validate("delete", req.body, res, Message.deleteRemoteOnly); +}); + +router.post("/delete", async(req, res) => { + await validator.validate("delete", req.body, res, Message.deleteEverywhere); +}); + export default router; diff --git a/back/validator/schemas/delete-schema.json b/back/validator/schemas/delete-schema.json new file mode 100644 index 0000000..40eabb9 --- /dev/null +++ b/back/validator/schemas/delete-schema.json @@ -0,0 +1,16 @@ +{ + "type": "object", + "properties": { + "mailboxId": { + "type": "number" + }, + "messageId": { + "type": "number" + } + }, + "required": [ + "mailboxId", + "messageId" + ], + "additionalProperties": false +} \ No newline at end of file diff --git a/back/validator/validator.ts b/back/validator/validator.ts index 8759ac5..b11d031 100644 --- a/back/validator/validator.ts +++ b/back/validator/validator.ts @@ -10,6 +10,7 @@ import getMessagesSchema from "./schemas/getMessages-schema.json"; import getMembersSchema from "./schemas/getMembers-schema.json"; import setFlagSchema from "./schemas/setFlag-schema.json"; import responseSchema from "./schemas/response-schema.json"; +import deleteSchema from "./schemas/delete-schema.json"; import { Request, Response } from "express"; import statusCodes from "../utils/statusCodes"; import logger from "../system/Logger"; @@ -22,6 +23,7 @@ class Validator { validateGetMembers: any; validateSetFlag: any; validateResponse: any; + delete: any; constructor() { this.validateCreateAccount = ajv.compile(createAccountSchema); @@ -31,6 +33,7 @@ class Validator { this.validateGetMembers = ajv.compile(getMembersSchema); this.validateSetFlag = ajv.compile(setFlagSchema); this.validateResponse = ajv.compile(responseSchema); + this.delete = ajv.compile(deleteSchema); } _getSchema(name: string): any { @@ -50,6 +53,8 @@ class Validator { return this.validateSetFlag; case "response": return this.validateResponse; + case "delete": + return this.delete; default: logger.err(`Schema ${name} not found`); break; diff --git a/front/src/components/structure/message/Composer.vue b/front/src/components/structure/message/Composer.vue index 34de7a3..43cea55 100644 --- a/front/src/components/structure/message/Composer.vue +++ b/front/src/components/structure/message/Composer.vue @@ -296,6 +296,7 @@ function sendMessage() { border-radius: 10px; padding: 0 10px; overflow: auto; + min-height: 150px; } .bubble-menu, diff --git a/front/src/components/structure/message/Options.vue b/front/src/components/structure/message/Options.vue index 5e7c2eb..5e8ea76 100644 --- a/front/src/components/structure/message/Options.vue +++ b/front/src/components/structure/message/Options.vue @@ -42,6 +42,30 @@ const setFlag = (flag: string, loadingState: Ref) => { loadingState.value = false; }); }; + +const deleteEverywhere = () => { + if (!room?.value || !props.msg) return; + API.deleteEverywhere({ mailboxId: room.value?.mailboxId, messageId: props.msg?.id }) + .then((res) => { + store.commit("removeMsg", { roomId: room.value?.id, messageId: props.msg?.id }); + }) + .catch((err) => { + console.log(err); + }); +}; + +const deleteRemoteOnly = () => { + if (!room?.value || !props.msg) return; + API.deleteRemoteOnly({ mailboxId: room.value?.mailboxId, messageId: props.msg?.id }) + .then((res) => { + if (!hasFlag(props.msg?.flags, "\\Deleted")) { + store.commit("addFlag", { roomId: room.value?.id, messageId: props.msg?.id, flag: "\\Deleted" }); + } + }) + .catch((err) => { + console.log(err); + }); +};