deletion of messages (failing on server)

This commit is contained in:
grimhilt 2023-05-06 13:23:13 +02:00
parent 2c7b4f1c78
commit b137263bef
13 changed files with 129 additions and 24 deletions

View File

@ -2,6 +2,7 @@ import statusCode from "../utils/statusCodes";
import { Response } from "express"; import { Response } from "express";
import { getMessageUid, getUserOfMailbox } from "../db/utils/mail"; import { getMessageUid, getUserOfMailbox } from "../db/utils/mail";
import emailManager from "../mails/EmailManager"; import emailManager from "../mails/EmailManager";
import { deleteMessage } from "../db/message/updateMessage-db";
export default class Message { export default class Message {
static async addFlag(body, res: Response) { static async addFlag(body, res: Response) {
@ -51,4 +52,41 @@ export default class Message {
res.status(statusCode.METHOD_FAILURE).send({ error: err }); 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 });
});
}
} }

View File

@ -127,7 +127,7 @@ CREATE TABLE app_room (
PRIMARY KEY (room_id), PRIMARY KEY (room_id),
UNIQUE KEY (owner_id, message_id, room_type), UNIQUE KEY (owner_id, message_id, room_type),
FOREIGN KEY (owner_id) REFERENCES address(address_id), 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 -- 12
@ -175,6 +175,5 @@ create table flag (
flag_id INT NOT NULL, flag_id INT NOT NULL,
UNIQUE KEY (message_id, flag_id), 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 (message_id) REFERENCES message(message_id) ON DELETE CASCADE,
FOREIGN KEY (flag_id) REFERENCES flag_name(flag_id) ON DELETE CASCADE FOREIGN KEY (flag_id) REFERENCES flag_name(flag_id) ON DELETE CASCADE
); );

View File

@ -35,6 +35,7 @@ export async function getMailbox(mailboxId: number) {
} }
export function updateMailbox(mailboxId: number, uidnext: number) { export function updateMailbox(mailboxId: number, uidnext: number) {
console.log("updateMailbox", mailboxId, uidnext);
const query = `UPDATE mailbox SET uidnext = ? WHERE mailbox_id = ?`; const query = `UPDATE mailbox SET uidnext = ? WHERE mailbox_id = ?`;
const values = [uidnext, mailboxId]; const values = [uidnext, mailboxId];
execQuery(query, values); execQuery(query, values);

View File

@ -1,6 +1,6 @@
import { execQuery, execQueryAsync, execQueryAsyncWithId } from "../db"; 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 = ` const query = `
SELECT * FROM flag_name SELECT * FROM flag_name
INNER JOIN flag ON flag.flag_id = flag_name.flag_id 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 query = `UPDATE mailbox_message SET deleted = ? WHERE message_id = ?`;
const values = [messageId, isDeleted]; const values = [messageId, isDeleted];
return await execQueryAsync(query, values); return await execQueryAsync(query, values);
} }
export async function deleteMessage(messageId: number) {
const query = `DELETE FROM message WHERE message_id = ?`;
const values = [messageId];
return await execQueryAsync(query, values);
}

View File

@ -59,6 +59,7 @@ export default class Mailbox {
updateMsg.updateFlags(); updateMsg.updateFlags();
}); });
// wait for deletion
this.imap.on("expunge", (seqno: number) => { this.imap.on("expunge", (seqno: number) => {
console.log("Message with sequence number " + seqno + " has been deleted from the server."); console.log("Message with sequence number " + seqno + " has been deleted from the server.");
}); });
@ -113,7 +114,7 @@ export default class Mailbox {
try { try {
// fetch mails // fetch mails
let secondUid = savedUid + STEP < currentUid ? savedUid + STEP : currentUid; 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)`); logger.log(`Fetched ${STEP} uids (${mails.length} messages)`);
// save same in the database // save same in the database
for (let k = 0; k < mails.length; k++) { 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);
}
} }

View File

@ -11,5 +11,13 @@ router.post("/removeFlag", async (req, res) => {
await validator.validate("removeFlag", req.body, res, Message.removeFlag); 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; export default router;

View File

@ -0,0 +1,16 @@
{
"type": "object",
"properties": {
"mailboxId": {
"type": "number"
},
"messageId": {
"type": "number"
}
},
"required": [
"mailboxId",
"messageId"
],
"additionalProperties": false
}

View File

@ -10,6 +10,7 @@ import getMessagesSchema from "./schemas/getMessages-schema.json";
import getMembersSchema from "./schemas/getMembers-schema.json"; import getMembersSchema from "./schemas/getMembers-schema.json";
import setFlagSchema from "./schemas/setFlag-schema.json"; import setFlagSchema from "./schemas/setFlag-schema.json";
import responseSchema from "./schemas/response-schema.json"; import responseSchema from "./schemas/response-schema.json";
import deleteSchema from "./schemas/delete-schema.json";
import { Request, Response } from "express"; import { Request, Response } from "express";
import statusCodes from "../utils/statusCodes"; import statusCodes from "../utils/statusCodes";
import logger from "../system/Logger"; import logger from "../system/Logger";
@ -22,6 +23,7 @@ class Validator {
validateGetMembers: any; validateGetMembers: any;
validateSetFlag: any; validateSetFlag: any;
validateResponse: any; validateResponse: any;
delete: any;
constructor() { constructor() {
this.validateCreateAccount = ajv.compile(createAccountSchema); this.validateCreateAccount = ajv.compile(createAccountSchema);
@ -31,6 +33,7 @@ class Validator {
this.validateGetMembers = ajv.compile(getMembersSchema); this.validateGetMembers = ajv.compile(getMembersSchema);
this.validateSetFlag = ajv.compile(setFlagSchema); this.validateSetFlag = ajv.compile(setFlagSchema);
this.validateResponse = ajv.compile(responseSchema); this.validateResponse = ajv.compile(responseSchema);
this.delete = ajv.compile(deleteSchema);
} }
_getSchema(name: string): any { _getSchema(name: string): any {
@ -50,6 +53,8 @@ class Validator {
return this.validateSetFlag; return this.validateSetFlag;
case "response": case "response":
return this.validateResponse; return this.validateResponse;
case "delete":
return this.delete;
default: default:
logger.err(`Schema ${name} not found`); logger.err(`Schema ${name} not found`);
break; break;

View File

@ -296,6 +296,7 @@ function sendMessage() {
border-radius: 10px; border-radius: 10px;
padding: 0 10px; padding: 0 10px;
overflow: auto; overflow: auto;
min-height: 150px;
} }
.bubble-menu, .bubble-menu,

View File

@ -42,6 +42,30 @@ const setFlag = (flag: string, loadingState: Ref<boolean>) => {
loadingState.value = false; 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);
});
};
</script> </script>
<template> <template>
@ -71,25 +95,14 @@ const setFlag = (flag: string, loadingState: Ref<boolean>) => {
:classes="hasFlag(props.msg?.flags, '\\Flagged') ? 'warn' : ''" :classes="hasFlag(props.msg?.flags, '\\Flagged') ? 'warn' : ''"
v-tooltip="hasFlag(props.msg?.flags, '\\Flagged') ? 'Unflag' : 'Flag'" v-tooltip="hasFlag(props.msg?.flags, '\\Flagged') ? 'Unflag' : 'Flag'"
/> />
<!--
<SvgLoader
v-if="isSeenFc(props.msg?.flags)"
svg="mail-check-line"
class="option"
v-tooltip="'Mark unread'"
:loading="seenLoading"
/>
<SvgLoader
v-if="!isSeenFc(props.msg?.flags)"
svg="mail-unread-line"
class="option"
v-tooltip="'Mark as read'"
:loading="seenLoading"
/> -->
</span> </span>
<SvgLoader svg="reply-line" class="option" /> <SvgLoader svg="reply-line" class="option" />
<SvgLoader svg="delete-bin-4-line" class="option" classes="danger" v-tooltip="'Delete from server'" /> <span @click="deleteRemoteOnly()">
<SvgLoader svg="delete-bin-6-line" class="option" classes="danger" v-tooltip="'Delete everywhere'" /> <SvgLoader svg="delete-bin-4-line" class="option" classes="danger" v-tooltip="'Delete from remote'" />
</span>
<span @click="deleteEverywhere()">
<SvgLoader svg="delete-bin-6-line" class="option" classes="danger" v-tooltip="'Delete everywhere'" />
</span>
<SvgLoader svg="share-forward-line" class="option" /> <SvgLoader svg="share-forward-line" class="option" />
<SvgLoader svg="reply-all-line" class="option" /> <SvgLoader svg="reply-all-line" class="option" />
</div> </div>

View File

@ -25,4 +25,10 @@ export default {
reponseEmail(data: { user: string; roomId: number; text: string; html: string }) { reponseEmail(data: { user: string; roomId: number; text: string; html: string }) {
return API().post(`/room/response`, data); return API().post(`/room/response`, data);
}, },
deleteRemoteOnly(data: { mailboxId: number; messageId: number }) {
return API().post(`/message/deleteRemote`, data);
},
deleteEverywhere(data: { mailboxId: number; messageId: number }) {
return API().post(`/message/delete`, data);
},
}; };

View File

@ -170,6 +170,13 @@ const store = createStore<State>({
updateSeen(state, payload.roomId, payload.flag, false); updateSeen(state, payload.roomId, payload.flag, false);
} }
}, },
removeMsg(state, payload) {
const msgs = msgOnRoomId(state, payload.roomId);
const msgIndex = msgs?.messages.findIndex((msg) => msg.id == payload.messageId) ?? -1;
if (msgs && msgIndex != -1) {
msgs.messages.splice(msgIndex, 1);
}
},
}, },
getters: { getters: {
rooms: (state) => (): Room[] => { rooms: (state) => (): Room[] => {

View File

@ -1,5 +1,5 @@
export function removeDuplicates(array: number[]) { export function removeDuplicates(array: any[]) {
const unique: number[] = []; const unique: any[] = [];
for (let i = 0; i < array.length; i++) { for (let i = 0; i < array.length; i++) {
if (!unique.includes(array[i])) { if (!unique.includes(array[i])) {
unique.push(array[i]); unique.push(array[i]);