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

5
.gitignore vendored
View File

@ -30,4 +30,7 @@ config.json
.direnv
.envrc
*.txt
*.json
*.json
tmp
*test*
*.png

View File

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

View File

@ -27,7 +27,7 @@ async function registerMessageInApp(messageId, attrs) {
} else {
await findRoomByOwner(ownerId).then(async (res) => {
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);
});
} 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) {
const query = `
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];
execQuery(query, values);

View File

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

View File

@ -35,7 +35,6 @@ CREATE TABLE mailbox (
first_recent INT NOT NULL DEFAULT 1,
uidvalidity INT NOT NULL DEFAULT 1,
PRIMARY KEY (mailbox_id),
UNIQUE KEY (mailbox_name),
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_name VARCHAR(255) NOT NULL,
owner_id INT NOT NULL,
message_id INT NOT NULL,
isGroup BOOLEAN NOT NULL DEFAULT false,
notSeen INT NOT NULL DEFAULT 0,
lastUpdate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP(),
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
@ -145,7 +146,7 @@ CREATE TABLE app_space_message (
message_id INT NOT NULL,
room_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 (room_id) REFERENCES app_room(room_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 mails = [];
var f = imap.seq.fetch('1:10', {
const f = imap.seq.fetch('1:10', {
size: true,
envelope: true
});

View File

@ -71,7 +71,7 @@ function saveMessage(attrs, mailboxId, imap) {
async function saveFromParsedData(parsed, messageId) {
const promises = [];
Object.keys(parsed).forEach((key) => {
if (["from", "to", "cc", "bcc", "reply-to"].includes(key)) {
if (["from", "to", "cc", "bcc", "replyTo"].includes(key)) {
promises.push(
// save address field
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": {
"ajv": "^8.12.0",
"ajv-formats": "^2.1.1",
"cors": "^2.8.5",
"express": "^4.18.2",
"imap": "^0.8.19",
"imap-simple": "^5.1.0",
"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();
app.use(express.json());
app.use(
express.urlencoded({
extended: true,
})
express.urlencoded({
extended: true,
}),
);
app.use(cors());
app.listen(process.env.PORT || 5500);
// anecdote
app.get("/api/mails/mailboxes", mails.getMailboxes);
const mailRouter = require("./routes/mail");
app.use("/api/mail", mailRouter);

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -1,7 +1,10 @@
import API from './API'
export default {
getQuote() {
return API().get('/');
}
registerMailbox(data) {
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";
const roomsStore = createStore({
@ -29,23 +30,36 @@ const roomsStore = createStore({
mailbox: 2,
},
],
mailboxes: [
{ mail: "mail@domain.com", id: 1 },
{ mail: "name@example.com", id: 2 },
],
mailboxes: [],
activeMailbox: -1
};
},
mutations: {
setActiveMailbox(state, payload) {
state.activeMailbox = payload;
},
addMailboxes(state, payload) {
payload.forEach(mailbox => {
state.mailboxes.push(mailbox);
});
}
},
getters: {
folderRooms: (state) => () => {
if (state.activeMailbox == -1) return state.rooms;
rooms: (state) => () => {
if (state.activeMailbox == 0) return state.rooms;
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 API from '../../services/imapAPI';
const modal = ref(true);
const modal = ref(false);
const email = ref("");
const pwd = ref("");
@ -64,10 +64,20 @@ function checkError() {
}
}
function addMailboxRequest(event) {
console.log(event.target.disabled = true)
function addMailboxRequest() {
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);
}).catch((err) => {
console.log(err.request.status)

View File

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

View File

@ -4,7 +4,7 @@
<!-- deconnect -->
</div>
<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"/>
<span class="divider"></span>
@ -17,6 +17,7 @@
import { mapState } from 'vuex'
import Mailbox from './Mailbox'
import AddMailboxModal from '../../modals/AddMailboxModal'
import roomsStore from '@/store/rooms'
export default {
name: 'Mailboxes',
@ -28,6 +29,12 @@ export default {
...mapState(['mailboxes'])
},
}
if (roomsStore.state.mailboxes.length == 0) {
console.log("call api get mailboxes");
roomsStore.dispatch('addMailboxes');
}
</script>
<style scoped>

View File

@ -1,6 +1,6 @@
<template>
<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>
</template>
@ -17,7 +17,7 @@ export default {
User
},
computed: {
...mapGetters(['folderRooms'])
...mapGetters(['rooms'])
}
}
</script>

View File

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