reply message from thread and room

This commit is contained in:
grimhilt 2023-04-14 20:54:44 +02:00
parent 7ad22e55c1
commit 4799e477be
10 changed files with 117 additions and 20 deletions

View File

@ -1,6 +1,6 @@
import { Response } from "express";
import { getAccounts, registerAccount } from "../db/api-db";
import { getAddresseId } from "../db/utils/mail";
import { getAddressId } from "../db/utils/mail";
import statusCodes from "../utils/statusCodes";
export default class Account {
@ -12,7 +12,7 @@ export default class Account {
static async register(body, res: Response) {
const { email, pwd, xoauth, xoauth2, host, port, tls } = body;
getAddresseId(email).then((addressId) => {
getAddressId(email).then((addressId) => {
registerAccount(addressId, pwd, xoauth, xoauth2, host, port, tls)
.then((mailboxId) => {
res.status(statusCodes.OK).json({ id: mailboxId });

View File

@ -2,24 +2,58 @@ import statusCode from "../utils/statusCodes";
import { Response } from "express";
import { RoomType } from "../mails/message/saveMessage";
import { getRoomType } from "../db/message/saveMessage-db";
import { getRoomOwner } from "../db/Room-db";
import { getLastMsgData, getRoomOwner } from "../db/Room-db";
import emailManager from "../mails/EmailManager";
import MailBuilder from "../mails/utils/mailBuilder";
import { getAddresses } from "../db/utils/mail";
function rmUserFromAddrs(addresses: { email: string }[], user: string) {
let index = addresses.findIndex((a) => a.email == user);
if (index != -1) {
addresses.splice(index, 1);
}
}
export default class Room {
// todo change name
// todo change name of reponse
static async response(body, res: Response) {
const { user, roomId, text, html } = body;
console.log(body)
const roomType = (await getRoomType(roomId))[0].room_type;
if (roomType === RoomType.DM) {
const ownerEmail = (await getRoomOwner(roomId))[0].email;
const mailBuilder = new MailBuilder();
mailBuilder.from(user).to(ownerEmail).text(text).html(html);
emailManager.getSmtp(user).sendMail(mailBuilder.message);
// send new msg to recipient of dm
res.status(statusCode.OK).send();
} else if (roomType === RoomType.GROUP || roomType === RoomType.THREAD) {
// get all cc and to from of previous message and add them
const lastMsgData = (await getLastMsgData(roomId))[0];
console.log(lastMsgData);
const mailBuilder = new MailBuilder();
mailBuilder.inReplySubject(lastMsgData.subject).inReplyTo(lastMsgData.messageID).text(text).html(html);
const from = await getAddresses(lastMsgData.fromA);
let to = lastMsgData.toA ? await getAddresses(lastMsgData.toA) : [];
let cc = lastMsgData.ccA ? await getAddresses(lastMsgData.ccA) : [];
// remove us from recipients
rmUserFromAddrs(to, user);
rmUserFromAddrs(from, user);
// add sender of previous as recipient if it is not us
if (from.findIndex((a) => a.email == user) == -1) {
to = to.concat(from);
}
mailBuilder
.from(user)
.to(to.map((a) => a.email))
.cc(cc.map((a) => a.email));
emailManager.getSmtp(user).sendMail(mailBuilder.message);
res.status(statusCode.OK).send();
} else {
res.status(statusCode.FORBIDDEN).send({ error: "Cannot add a new message in a room or a channel." });
}

View File

@ -1,4 +1,5 @@
import { execQueryAsync } from "./db";
import { queryCcId, queryFromId, queryToId } from "./utils/addressQueries";
export async function getRoomOwner(roomId: number) {
const query = `
@ -10,3 +11,51 @@ export async function getRoomOwner(roomId: number) {
const values = [roomId];
return await execQueryAsync(query, values);
}
export async function getLastMsgData(roomId: number) {
const query = `
SELECT
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,
message.messageID AS messageID
FROM app_room_message msg
${queryFromId} fromT ON msg.message_id = fromT.message_id
${queryToId} toT ON msg.message_id = toT.message_id
${queryCcId} 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
ORDER BY message.idate DESC
LIMIT 1
`;
const values = [roomId];
return await execQueryAsync(query, values);
}

View File

@ -1,6 +1,6 @@
import { execQueryAsync, execQueryAsyncWithId } from "../db";
export async function getAddresseId(email: string, name?: string): Promise<number> {
export async function getAddressId(email: string, name?: string): Promise<number> {
const localpart = email.split("@")[0];
const domain = email.split("@")[1];
const query = `INSERT INTO address
@ -10,6 +10,12 @@ export async function getAddresseId(email: string, name?: string): Promise<numbe
return await execQueryAsyncWithId(query, values);
}
export async function getAddresses(ids: number | number[]): Promise<{ id: number, email: string }[]> {
const query = `SELECT address_id AS id, email FROM address WHERE address_id IN (?)`;
const values = [ids];
return await execQueryAsync(query, values);
}
export async function getFieldId(field: string): Promise<number> {
const query = `INSERT INTO field_name (field_name) VALUES (?) ON DUPLICATE KEY UPDATE field_id=LAST_INSERT_ID(field_id)`;
const values = [field];
@ -22,7 +28,7 @@ export async function getFlagId(flag: string): Promise<number> {
return await execQueryAsyncWithId(query, values);
}
export async function getMessageIdOnUid(uid: number): Promise<{message_id: number}[]> {
export async function getMessageIdOnUid(uid: number): Promise<{ message_id: number }[]> {
const query = `SELECT message_id FROM mailbox_message WHERE uid = ?`;
const values = [uid];
return await execQueryAsync(query, values);

View File

@ -11,7 +11,7 @@ import {
getThreadInfoOnId,
} from "../../db/message/saveMessage-db";
import { findRoomByOwner, getAddresseId, getUserIdOfMailbox } from "../../db/utils/mail";
import { findRoomByOwner, getAddressId, getUserIdOfMailbox } from "../../db/utils/mail";
import { nbMembers } from "../utils/envelopeUtils";
import logger from "../../system/Logger";
import { Attrs, Envelope, User } from "../../interfaces/mail/attrs.interface";
@ -57,7 +57,7 @@ export default class RegisterMessageInApp {
async init() {
if (this.envelope.from) {
this.ownerId = await getAddresseId(createAddress(this.envelope.from[0])); // todo use sender or from ?
this.ownerId = await getAddressId(createAddress(this.envelope.from[0])); // todo use sender or from ?
} else {
throw new Error("Envelope must have a 'from' field");
}
@ -152,7 +152,7 @@ export default class RegisterMessageInApp {
if (this.isDm()) {
// create or add new message to DM
if (!this.envelope.to) throw new Error("Who send a DM and put the recipient in cc ?");
const userTo = await getAddresseId(createAddress(this.envelope.to[0]));
const userTo = await getAddressId(createAddress(this.envelope.to[0]));
await this.createOrRegisterOnExistence(userTo, RoomType.DM);
} else {
// it is not a reply and not a dm

View File

@ -1,4 +1,4 @@
import { getAddresseId, getFlagId } from "../../db/utils/mail";
import { getAddressId, getFlagId } from "../../db/utils/mail";
import { EmailAddress, ParsedMail, simpleParser } from "mailparser";
import moment from "moment";
import Imap from "imap";
@ -91,7 +91,7 @@ async function saveFromParsedData(parsed: ParsedMail, messageId: number) {
// save address field
getFieldId(key).then((fieldId) => {
parsed[key].value.forEach((addr: EmailAddress, nb: number) => {
getAddresseId(addr.address, addr.name).then(async (addressId) => {
getAddressId(addr.address, addr.name).then(async (addressId) => {
await saveAddress_fields(messageId, fieldId, addressId, nb);
});
});

View File

@ -43,4 +43,10 @@ export default class MailBuilder {
this.message.inReplyTo = messageID;
return this;
}
inReplySubject(originSubject: string): MailBuilder {
// todo concate if multiple ?
this.message.subject = "RE: " + originSubject;
return this;
}
}

View File

@ -20,7 +20,7 @@ const boxId = 1;
jest.mock("../../db/utils/mail", () => {
return {
findRoomByOwner: jest.fn(),
getAddresseId: jest.fn(),
getAddressId: jest.fn(),
getUserIdOfMailbox: jest.fn(),
};
});
@ -38,7 +38,7 @@ jest.mock("../../db/message/saveMessage-db", () => {
getThreadInfoOnId: jest.fn(),
};
});
import { getAddresseId, getUserIdOfMailbox, findRoomByOwner } from "../../db/utils/mail";
import { getAddressId, getUserIdOfMailbox, findRoomByOwner } from "../../db/utils/mail";
import {
createRoom,
registerMessageInRoom,
@ -69,7 +69,7 @@ import { AttrsWithEnvelopeTest, createReplyWithSameMembers } from "../test-utils
// if only me reply -> channel
beforeAll(async () => {
mocked(getAddresseId).mockImplementation(db.getAddresseId);
mocked(getAddressId).mockImplementation(db.getAddressId);
mocked(getUserIdOfMailbox).mockImplementation(db.getUserIdOfMailbox);
mocked(findRoomByOwner).mockImplementation(db.findRoomByOwner);

View File

@ -146,7 +146,7 @@ export default class saveMessageDatabase {
});
};
getAddresseId = (email: string, name?: string): Promise<number> => {
getAddressId = (email: string, name?: string): Promise<number> => {
const match = this.users.find((user) => user.user.mailbox + "@" + user.user.host == email);
return new Promise((resolve, reject) => resolve(match?.id));
};

View File

@ -30,6 +30,8 @@ const send = () => {
html: htmlContent,
});
};
// todo subject input when dm of group...
</script>
<template>