fetching mailboxes from api

This commit is contained in:
grimhilt 2023-03-17 13:31:27 +01:00
parent 14e64c1fc3
commit 095efb5440
24 changed files with 3107 additions and 603 deletions

3
.gitignore vendored
View File

@ -31,3 +31,6 @@ config.json
.envrc .envrc
*.txt *.txt
*.json *.json
tmp
*test*
*.png

View File

@ -1,4 +1,7 @@
{ {
"printWidth": 120,
"tabWidth": 4, "tabWidth": 4,
"quoteProps": "consistent",
"trailingComma": "all",
"useTabs": false "useTabs": false
} }

View File

@ -27,7 +27,7 @@ async function registerMessageInApp(messageId, attrs) {
} else { } else {
await findRoomByOwner(ownerId).then(async (res) => { await findRoomByOwner(ownerId).then(async (res) => {
if (res.length == 0) { if (res.length == 0) {
await createRoom(envelope.subject, ownerId).then(async (roomId) => { await createRoom(envelope.subject, ownerId, messageId).then(async (roomId) => {
await registerMessageInRoom(messageId, roomId, isSeen); await registerMessageInRoom(messageId, roomId, isSeen);
}); });
} else { } else {

View File

@ -0,0 +1,20 @@
const statusCode = require("../utils/statusCodes").statusCodes;
const { registerMailbox } = require("../db/api");
const { getAddresseId } = require("../db/mail");
async function addMailbox(body, res) {
const { email, pwd, xoauth, xoauth2, host, port, tls } = body;
getAddresseId(email).then((addressId) => {
registerMailbox(addressId, pwd, xoauth, xoauth2, host, port, tls)
.then((mailboxId) => {
res.status(statusCode.OK).json({ id: mailboxId });
})
.catch(() => {
res.status(statusCode.INTERNAL_SERVER_ERROR);
});
});
}
module.exports = {
addMailbox,
};

26
back/db/api.js Normal file
View File

@ -0,0 +1,26 @@
const { db, execQueryAsync, execQueryAsyncWithId } = require("./db.js");
const DEBUG = require("../utils/debug").DEBUG;
async function registerMailbox(userId, pwd, xoauth, xoauth2, host, port, tls) {
const query = `
INSERT INTO app_account
(user_id, account_pwd, xoauth, xoauth2, host, port, tls) VALUES (?, ?, ?, ?, ?, ?, ?)
`;
const values = [userId, pwd, xoauth, xoauth2, host, port, tls];
return await execQueryAsyncWithId(query, values);
}
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
`;
const values = [];
return await execQueryAsync(query, values);
}
module.exports = {
registerMailbox,
getMailboxes
};

View File

@ -14,7 +14,7 @@ async function registerMessage(timestamp, rfc822size, messageId) {
function registerMailbox_message(mailboxId, uid, messageId, modseq, seen, deleted) { function registerMailbox_message(mailboxId, uid, messageId, modseq, seen, deleted) {
const query = ` const query = `
INSERT IGNORE INTO mailbox_message INSERT IGNORE INTO mailbox_message
(mailbox_id, uid, message_id, modseq, seen, deleted) VALUES (?, ?, ?, ?, ?, ?) (mailbox_id, uid, message_id, modseq, seen, deleted) VALUES (1, 19, 10, '12450', 0, 0)
`; `;
const values = [mailboxId, uid, messageId, modseq, seen, deleted]; const values = [mailboxId, uid, messageId, modseq, seen, deleted];
execQuery(query, values); execQuery(query, values);

View File

@ -1,9 +1,9 @@
const { db, execQueryAsync, execQueryAsyncWithId } = require("./db.js"); const { db, execQueryAsync, execQueryAsyncWithId } = require("./db.js");
const DEBUG = require("../utils/debug").DEBUG; const DEBUG = require("../utils/debug").DEBUG;
async function createRoom(roomName, ownerId) { async function createRoom(roomName, ownerId, messageId) {
const query = `INSERT INTO app_room (room_name, owner_id) VALUES (?, ?)`; const query = `INSERT INTO app_room (room_name, owner_id, message_id) VALUES (?, ?, ?)`;
const values = [roomName.substring(0, 255), ownerId]; const values = [roomName.substring(0, 255), ownerId, messageId];
return await execQueryAsyncWithId(query, values); return await execQueryAsyncWithId(query, values);
// todo add members // todo add members
} }

View File

@ -35,7 +35,6 @@ CREATE TABLE mailbox (
first_recent INT NOT NULL DEFAULT 1, first_recent INT NOT NULL DEFAULT 1,
uidvalidity INT NOT NULL DEFAULT 1, uidvalidity INT NOT NULL DEFAULT 1,
PRIMARY KEY (mailbox_id), PRIMARY KEY (mailbox_id),
UNIQUE KEY (mailbox_name),
FOREIGN KEY (account_id) REFERENCES app_account(account_id) ON DELETE CASCADE FOREIGN KEY (account_id) REFERENCES app_account(account_id) ON DELETE CASCADE
); );
@ -121,11 +120,13 @@ CREATE TABLE app_room (
room_id INT AUTO_INCREMENT, room_id INT AUTO_INCREMENT,
room_name VARCHAR(255) NOT NULL, room_name VARCHAR(255) NOT NULL,
owner_id INT NOT NULL, owner_id INT NOT NULL,
message_id INT NOT NULL,
isGroup BOOLEAN NOT NULL DEFAULT false, isGroup BOOLEAN NOT NULL DEFAULT false,
notSeen INT NOT NULL DEFAULT 0, notSeen INT NOT NULL DEFAULT 0,
lastUpdate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP(), lastUpdate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP(),
PRIMARY KEY (room_id), PRIMARY KEY (room_id),
FOREIGN KEY (owner_id) REFERENCES address(address_id) FOREIGN KEY (owner_id) REFERENCES address(address_id),
FOREIGN KEY (message_id) REFERENCES message(message_id)
); );
-- 12 -- 12
@ -145,7 +146,7 @@ CREATE TABLE app_space_message (
message_id INT NOT NULL, message_id INT NOT NULL,
room_id INT, room_id INT,
thread_id INT, thread_id INT,
UNIQUE KEY (member_id, room_id, thread_id), UNIQUE KEY (message_id, room_id, thread_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 (room_id) REFERENCES app_room(room_id) ON DELETE SET NULL, 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 (thread_id) REFERENCES app_thread(thread_id) ON DELETE SET NULL

View File

@ -47,7 +47,7 @@ imap.once("ready", function () {
// }); // });
const promises = []; const promises = [];
const mails = []; const mails = [];
var f = imap.seq.fetch('1:10', { const f = imap.seq.fetch('1:10', {
size: true, size: true,
envelope: true envelope: true
}); });

View File

@ -71,7 +71,7 @@ function saveMessage(attrs, mailboxId, imap) {
async function saveFromParsedData(parsed, messageId) { async function saveFromParsedData(parsed, messageId) {
const promises = []; const promises = [];
Object.keys(parsed).forEach((key) => { Object.keys(parsed).forEach((key) => {
if (["from", "to", "cc", "bcc", "reply-to"].includes(key)) { if (["from", "to", "cc", "bcc", "replyTo"].includes(key)) {
promises.push( promises.push(
// save address field // save address field
getFieldId(key).then((fieldId) => { getFieldId(key).then((fieldId) => {

2050
back/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,9 @@
{ {
"dependencies": { "dependencies": {
"ajv": "^8.12.0",
"ajv-formats": "^2.1.1",
"cors": "^2.8.5",
"express": "^4.18.2",
"imap": "^0.8.19", "imap": "^0.8.19",
"imap-simple": "^5.1.0", "imap-simple": "^5.1.0",
"mailparser": "^3.6.3", "mailparser": "^3.6.3",

View File

@ -1,30 +0,0 @@
const statusCodes = require("../utils/statusCodes.js").statusCodes;
const express = require('express');
const router = require('router');
/**
* Return all mailboxes and folders for an user
*/
router.get("/mailboxes", (req, res) => {
const {token} = req.params;
const query = ``;
});
/**
* @param {number} mailboxId the id of the mailbox from which to fetch the messages, 0 if from all
* @param {number} offset the offset of the query
* @param {number} limit the number of message to return
* @param {string} token the token of the user
* @return {object} a list of room and their preview
*/
router.get("/{mailboxId}/messages", (req, res) => {
const {token, mailboxId, offset, limit} = req.params;
// todo check token
// todo use offset
const query = ``;
// SELECT header_fields.value FROM header_fields INNER JOIN field_names WHERE header_fields.field = field_names.id AND (field_names.name = "subject" OR field_names.name = "date"); ORDER BY messages.idate
// number of message missed in the room
});
module.exports = router;

63
back/routes/mail.js Normal file
View File

@ -0,0 +1,63 @@
const statusCodes = require("../utils/statusCodes.js").statusCodes;
const express = require("express");
const router = express.Router();
const Ajv = require("ajv");
const addFormats = require("ajv-formats");
const ajv = new Ajv({ allErrors: true });
addFormats(ajv);
const schema_mailbox = require("../schemas/mailbox_schema.json");
const { addMailbox } = require("../controllers/addMailbox.js");
const { getMailboxes } = require("../db/api.js");
const validate_mailbox = ajv.compile(schema_mailbox);
/**
* Return all mailboxes and folders for an user
*/
router.get("/mailboxes", (req, res) => {
getMailboxes().then((data) => {
res.status(statusCodes.OK).json(data)
});
});
/**
* @param {number} mailboxId the id of the mailbox (account_id) from which to fetch the messages, 0 if from all
* @param {number} offset the offset of the query
* @param {number} limit the number of message to return
* @param {string} token the token of the user
* @return {object} a list of room and their preview (subject)
*/
router.get("/{mailboxId}/messages", (req, res) => {
const { mailboxId, offset, limit } = req.params;
// todo check token
// todo use offset
const query = `
SELECT app_room.room_id, app_room.room_name, app_room.owner_id, app_room.notSeen, mailbox_message.mailbox_id, address.email
FROM app_room
INNER JOIN message
INNER JOIN mailbox_message
INNER JOIN address
WHERE
message.message_id = app_room.message_id AND
mailbox_message.mailbox_id = 1 AND
mailbox_message.message_id = message.message_id AND
address.address_id = app_room.owner_id
`;
const values = [mailboxId];
});
/**
* Register a new mailbox inside the app
*/
router.post("/mailbox", async (req, res) => {
const valid = validate_mailbox(req.body);
if (!valid) {
res.status(statusCodes.NOT_ACCEPTABLE).send(validate_mailbox.errors)
} else {
await addMailbox(req.body, res);
}
});
module.exports = router;

View File

@ -1,20 +1,14 @@
const mails = require("./routers/mail.js"); const express = require("express");
const cors = require("cors");
const express = require('express');
const cors = require('cors')
const app = express(); const app = express();
app.use(express.json()); app.use(express.json());
app.use( app.use(
express.urlencoded({ express.urlencoded({
extended: true, extended: true,
}) }),
); );
app.use(cors()); app.use(cors());
app.listen(process.env.PORT || 5500); app.listen(process.env.PORT || 5500);
const mailRouter = require("./routes/mail");
// anecdote app.use("/api/mail", mailRouter);
app.get("/api/mails/mailboxes", mails.getMailboxes);

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
import axios from 'axios' import axios from 'axios'
export default(url='localhost') => { export default(url='/api') => {
return axios.create({ return axios.create({
baseURL: url, baseURL: url,
}); });

View File

@ -1,7 +1,10 @@
import API from './API' import API from './API'
export default { export default {
getQuote() { registerMailbox(data) {
return API().get('/'); return API().post('/mail/mailbox', data);
} },
getMailboxes() {
return API().get('/mail/mailboxes');
},
} }

View File

@ -1,3 +1,4 @@
import API from "@/services/imapAPI";
import { createStore } from "vuex"; import { createStore } from "vuex";
const roomsStore = createStore({ const roomsStore = createStore({
@ -29,23 +30,36 @@ const roomsStore = createStore({
mailbox: 2, mailbox: 2,
}, },
], ],
mailboxes: [ mailboxes: [],
{ mail: "mail@domain.com", id: 1 },
{ mail: "name@example.com", id: 2 },
],
activeMailbox: -1 activeMailbox: -1
}; };
}, },
mutations: { mutations: {
setActiveMailbox(state, payload) { setActiveMailbox(state, payload) {
state.activeMailbox = payload; state.activeMailbox = payload;
},
addMailboxes(state, payload) {
payload.forEach(mailbox => {
state.mailboxes.push(mailbox);
});
} }
}, },
getters: { getters: {
folderRooms: (state) => () => { rooms: (state) => () => {
if (state.activeMailbox == -1) return state.rooms; if (state.activeMailbox == 0) return state.rooms;
return state.rooms.filter(room => room.mailbox == state.activeMailbox); return state.rooms.filter(room => room.mailbox == state.activeMailbox);
} }
},
actions: {
async addMailboxes(context) {
console.log("add mailboxes")
API.getMailboxes().then((res) => {
console.log(res.data)
context.commit("addMailboxes", res.data);
}).catch((err) => {
console.log(err)
});
}
} }
}); });

View File

@ -3,7 +3,7 @@ import { ref, computed, watchEffect } from 'vue'
import Modal from './Modal' import Modal from './Modal'
import API from '../../services/imapAPI'; import API from '../../services/imapAPI';
const modal = ref(true); const modal = ref(false);
const email = ref(""); const email = ref("");
const pwd = ref(""); const pwd = ref("");
@ -64,10 +64,20 @@ function checkError() {
} }
} }
function addMailboxRequest(event) { function addMailboxRequest() {
console.log(event.target.disabled = true)
checkError(); checkError();
API.getQuote().then((res) => {
const data = {
email: email.value,
pwd: pwd.value,
xoauth: xoauth.value,
xoauth2: xoauth2.value,
host: host.value,
port: port.value,
tls: true
};
API.registerMailbox(data).then((res) => {
console.log(res.status); console.log(res.status);
}).catch((err) => { }).catch((err) => {
console.log(err.request.status) console.log(err.request.status)

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="container" @click="setActiveMailbox(data.id)" :class="activeMailbox == data.id && 'active'"> <div class="container" @click="setActiveMailbox(data.id)" :class="activeMailbox == data.id && 'active'">
{{ data.mail }} {{ data.email }}
</div> </div>
</template> </template>

View File

@ -4,7 +4,7 @@
<!-- deconnect --> <!-- deconnect -->
</div> </div>
<span class="divider"></span> <span class="divider"></span>
<Mailbox :data="{'id': -1, 'mail': 'all'}"/> <Mailbox :data="{'id': 0, 'email': 'all'}"/>
<Mailbox v-for="(mailbox, index) in mailboxes" :key="index" :data="mailbox"/> <Mailbox v-for="(mailbox, index) in mailboxes" :key="index" :data="mailbox"/>
<span class="divider"></span> <span class="divider"></span>
@ -17,6 +17,7 @@
import { mapState } from 'vuex' import { mapState } from 'vuex'
import Mailbox from './Mailbox' import Mailbox from './Mailbox'
import AddMailboxModal from '../../modals/AddMailboxModal' import AddMailboxModal from '../../modals/AddMailboxModal'
import roomsStore from '@/store/rooms'
export default { export default {
name: 'Mailboxes', name: 'Mailboxes',
@ -28,6 +29,12 @@ export default {
...mapState(['mailboxes']) ...mapState(['mailboxes'])
}, },
} }
if (roomsStore.state.mailboxes.length == 0) {
console.log("call api get mailboxes");
roomsStore.dispatch('addMailboxes');
}
</script> </script>
<style scoped> <style scoped>

View File

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<User v-for="(room, index) in folderRooms()" :key="index" :sender="room.users" :object="room.object" /> <User v-for="(room, index) in rooms()" :key="index" :sender="room.users" :object="room.object" />
</div> </div>
</template> </template>
@ -17,7 +17,7 @@ export default {
User User
}, },
computed: { computed: {
...mapGetters(['folderRooms']) ...mapGetters(['rooms'])
} }
} }
</script> </script>

View File

@ -1,4 +1,11 @@
const { defineConfig } = require('@vue/cli-service') const { defineConfig } = require('@vue/cli-service');
module.exports = defineConfig({ module.exports = defineConfig({
transpileDependencies: true transpileDependencies: true,
devServer: {
proxy: {
"/api": {
target: "http://localhost:5500",
}
}
}
}) })