show addresses in front

This commit is contained in:
grimhilt 2023-04-03 20:37:07 +02:00
parent 6b4264fccc
commit fd253197cc
9 changed files with 317 additions and 55 deletions

View File

@ -101,9 +101,9 @@ export async function getMessages(roomId) {
export async function getMembers(roomId) { export async function getMembers(roomId) {
const query = ` const query = `
SELECT SELECT
address.address_id, address.address_id AS id,
address.address_name, address.address_name AS name,
address.email address.email AS email
FROM app_room_member FROM app_room_member
INNER JOIN address ON address.address_id = app_room_member.member_id INNER JOIN address ON address.address_id = app_room_member.member_id
WHERE app_room_member.room_id = ? WHERE app_room_member.room_id = ?

140
back/db/database.dart Normal file
View File

@ -0,0 +1,140 @@
Table "addresses" {
"id" int [pk, not null, increment]
"name" text
"localpart" text [not null]
"domain" text [not null]
"email" text [not null]
Indexes {
email [unique]
}
}
Table "mailboxes" {
"id" int [pk, not null, increment]
"name" text [not null]
"uidnext" int [not null, default: 1]
"nextmodseq" bigint [not null, default: 1]
"first_recent" int [not null, default: 1]
"uidvalidity" int [not null, default: 1]
Indexes {
name [unique]
}
}
Table "messages" {
"id" int [pk, not null, increment]
"messageID" text [pk, not null]
"idate" timestamp [not null]
"rfc822size" int
}
Table "mailbox_messages" {
"mailbox" int [not null]
"uid" int [pk, not null]
"message" int [pk, not null]
"modseq" bigint [not null]
"seen" boolean [not null, default: false]
"deleted" boolean [not null, default: false]
}
Ref: mailbox_messages.mailbox > mailboxes.id
Ref: mailbox_messages.message - messages.id
Table "bodyparts" {
"id" int [pk, not null, increment]
"bytes" int [not null]
"hash" text [not null]
"text" text
"data" binary
}
Table "part_numbers" {
"message" int [pk, not null]
"part" text [not null]
"bodypart" int [not null]
"bytes" int
"nb_lines" int
}
// todo on delete cascade
Ref: part_numbers.message > messages.id
Ref: part_numbers.bodypart - bodyparts.id
Table "field_names" {
"id" int [pk, not null, increment]
"name" text [not null]
Indexes {
name [unique]
}
}
Table "header_fields" {
"id" int [pk, not null, increment]
"message" int [pk, not null]
"part" text [not null]
"position" int [not null]
"field" int [not null]
"value" text
Indexes {
message [unique]
part [unique]
position [unique]
field [unique]
}
}
Ref: header_fields.message > messages.id
Ref: header_fields.part > part_numbers.part
Ref: header_fields.field > field_names.id
Table "address_fields" {
"message" int [not null]
"part" text [not null]
"position" int [not null]
"field" int [not null]
"number" int
"address" int [not null]
}
Ref: address_fields.message > messages.id
Ref: address_fields.part > part_numbers.part
Ref: address_fields.field > field_names.id
Ref: address_fields.address > addresses.id
// app table
Table "front_threads" {
"id" int [pk, not null, increment]
"room" int [not null]
"name" text
"notSeen" int [not null, default: true]
"lastUpdate" timestamp [not null]
"isDm" bool [not null, default: true]
}
Ref: front_threads.room > front_rooms.id
Table "front_rooms" {
"id" int [pk, not null, increment]
"name" text
"isGroup" bool [not null, default: false]
"notSeen" int [not null]
"lastUpdate" timestamp [not null]
}
Table "front_room_messages" {
"room" int [not null]
"thread" int [not null]
"message" int [not null]
}
Ref: front_room_messages.room > front_rooms.id
Ref: front_room_messages.message - messages.id
Ref: front_room_messages.thread > front_threads.id

108
back/db/database.sql Normal file
View File

@ -0,0 +1,108 @@
CREATE TABLE `addresses` (
`id` int PRIMARY KEY NOT NULL AUTO_INCREMENT,
`name` text,
`localpart` text NOT NULL,
`domain` text NOT NULL,
`email` text NOT NULL
);
CREATE TABLE `mailboxes` (
`id` int PRIMARY KEY NOT NULL AUTO_INCREMENT,
`name` text NOT NULL,
`uidnext` int NOT NULL DEFAULT 1,
`nextmodseq` bigint NOT NULL DEFAULT 1,
`first_recent` int NOT NULL DEFAULT 1,
`uidvalidity` int NOT NULL DEFAULT 1
);
CREATE TABLE `messages` (
`id` int PRIMARY KEY NOT NULL AUTO_INCREMENT,
`idate` timestamp NOT NULL,
`rfc822size` int
);
CREATE TABLE `mailbox_messages` (
`mailbox` int NOT NULL,
`uid` int NOT NULL,
`message` int NOT NULL,
`modseq` bigint NOT NULL,
`seen` boolean NOT NULL DEFAULT false,
`deleted` boolean NOT NULL DEFAULT false,
PRIMARY KEY (`uid`, `message`)
);
CREATE TABLE `bodyparts` (
`id` int PRIMARY KEY NOT NULL AUTO_INCREMENT,
`bytes` int NOT NULL,
`hash` text NOT NULL,
`text` text,
`data` binary
);
CREATE TABLE `part_numbers` (
`message` int PRIMARY KEY NOT NULL,
`part` text NOT NULL,
`bodypart` int NOT NULL,
`bytes` int,
`nb_lines` int
);
CREATE TABLE `field_names` (
`id` int PRIMARY KEY NOT NULL AUTO_INCREMENT,
`name` text NOT NULL
);
CREATE TABLE `header_fields` (
`id` int NOT NULL AUTO_INCREMENT,
`message` int NOT NULL,
`part` text NOT NULL,
`position` int NOT NULL,
`field` int NOT NULL,
`value` text,
PRIMARY KEY (`id`, `message`)
);
CREATE TABLE `address_fields` (
`message` int NOT NULL,
`part` text NOT NULL,
`position` int NOT NULL,
`field` int NOT NULL,
`number` int,
`address` int NOT NULL
);
CREATE UNIQUE INDEX `addresses_index_0` ON `addresses` (`email`);
CREATE UNIQUE INDEX `mailboxes_index_1` ON `mailboxes` (`name`);
CREATE UNIQUE INDEX `field_names_index_2` ON `field_names` (`name`);
CREATE UNIQUE INDEX `header_fields_index_3` ON `header_fields` (`message`);
CREATE UNIQUE INDEX `header_fields_index_4` ON `header_fields` (`part`);
CREATE UNIQUE INDEX `header_fields_index_5` ON `header_fields` (`position`);
CREATE UNIQUE INDEX `header_fields_index_6` ON `header_fields` (`field`);
ALTER TABLE `mailbox_messages` ADD FOREIGN KEY (`mailbox`) REFERENCES `mailboxes` (`id`);
ALTER TABLE `messages` ADD FOREIGN KEY (`id`) REFERENCES `mailbox_messages` (`message`);
ALTER TABLE `part_numbers` ADD FOREIGN KEY (`message`) REFERENCES `messages` (`id`);
ALTER TABLE `bodyparts` ADD FOREIGN KEY (`id`) REFERENCES `part_numbers` (`bodypart`);
ALTER TABLE `header_fields` ADD FOREIGN KEY (`message`) REFERENCES `messages` (`id`);
ALTER TABLE `header_fields` ADD FOREIGN KEY (`part`) REFERENCES `part_numbers` (`part`);
ALTER TABLE `header_fields` ADD FOREIGN KEY (`field`) REFERENCES `field_names` (`id`);
ALTER TABLE `address_fields` ADD FOREIGN KEY (`message`) REFERENCES `messages` (`id`);
ALTER TABLE `address_fields` ADD FOREIGN KEY (`part`) REFERENCES `part_numbers` (`part`);
ALTER TABLE `address_fields` ADD FOREIGN KEY (`field`) REFERENCES `field_names` (`id`);
ALTER TABLE `address_fields` ADD FOREIGN KEY (`address`) REFERENCES `addresses` (`id`);

View File

@ -1,5 +1,5 @@
export function removeDuplicates(array: []) { export function removeDuplicates(array: []) {
let unique = []; const unique = [];
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]);

View File

@ -30,5 +30,7 @@ export interface Account {
} }
export interface Address { export interface Address {
todo: boolean; id: number;
name: string | null;
email: string;
} }

View File

@ -1,5 +1,6 @@
import API from "@/services/imapAPI"; import API from "@/services/imapAPI";
import { decodeEmojis } from "@/utils/string"; import { decodeEmojis } from "@/utils/string";
import { AxiosError, AxiosResponse } from "axios";
import { createStore, Store } from "vuex"; import { createStore, Store } from "vuex";
import { Room, Account, Address, RoomType, Message } from "./models/model"; import { Room, Account, Address, RoomType, Message } from "./models/model";
@ -103,6 +104,12 @@ const store = createStore<State>({
const room = state.rooms.find((room) => room.id == roomId); const room = state.rooms.find((room) => room.id == roomId);
return room; return room;
}, },
address:
(state) =>
(addressId: number): Address | undefined => {
const address = state.addresses.find((address) => address.id == addressId);
return address;
},
messages: messages:
(state) => (state) =>
(roomId: number): Message[] => { (roomId: number): Message[] => {
@ -117,21 +124,21 @@ const store = createStore<State>({
actions: { actions: {
fetchAccounts: async (context) => { fetchAccounts: async (context) => {
API.getAccounts() API.getAccounts()
.then((res) => { .then((res: AxiosResponse) => {
context.commit("addAccounts", res.data); context.commit("addAccounts", res.data);
}) })
.catch((err) => { .catch((err: AxiosError) => {
console.log(err); console.log(err);
}); });
}, },
fetchRooms: async (context, data) => { fetchRooms: async (context, data) => {
if (data.account?.fetched == false) { if (data.account?.fetched == false) {
API.getRooms(data.accountId) API.getRooms(data.accountId)
.then((res) => { .then((res: AxiosResponse) => {
data.account.fetched = true; data.account.fetched = true;
context.commit("addRooms", { rooms: res.data }); context.commit("addRooms", { rooms: res.data });
}) })
.catch((err) => { .catch((err: AxiosError) => {
console.log(err); console.log(err);
}); });
} }
@ -140,20 +147,20 @@ const store = createStore<State>({
if (!data.room || data.room?.fetched == false) { if (!data.room || data.room?.fetched == false) {
store.dispatch("fetchRoomMembers", { roomId: data.roomId }); store.dispatch("fetchRoomMembers", { roomId: data.roomId });
API.getMessages(data.roomId) API.getMessages(data.roomId)
.then((res) => { .then((res: AxiosResponse) => {
context.commit("addMessages", { messages: res.data, roomId: data.roomId }); context.commit("addMessages", { messages: res.data, roomId: data.roomId });
}) })
.catch((err) => { .catch((err: AxiosError) => {
console.log(err); console.log(err);
}); });
} }
}, },
fetchRoomMembers: async (context, data) => { fetchRoomMembers: async (context, data) => {
API.getMembers(data.roomId) API.getMembers(data.roomId)
.then((res) => { .then((res: AxiosResponse) => {
context.commit("addAddress", { addresses: res.data, roomId: data.roomId }); context.commit("addAddress", { addresses: res.data, roomId: data.roomId });
}) })
.catch((err) => { .catch((err: AxiosError) => {
console.log(err); console.log(err);
}); });
}, },

9
front/src/utils/array.ts Normal file
View File

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

View File

@ -1,7 +1,9 @@
<script setup> <script setup>
import { defineProps, onMounted, ref } from "vue"; import { defineProps, onMounted, ref } from "vue";
import { decodeEmojis } from "../../utils/string"; import { decodeEmojis } from "../../utils/string";
import { removeDuplicates } from "../../utils/array";
import DOMPurify from "dompurify"; import DOMPurify from "dompurify";
import store from "@/store/store";
const props = defineProps({ data: Object }); const props = defineProps({ data: Object });
const date = new Date(props.data.date); const date = new Date(props.data.date);
@ -30,6 +32,17 @@ onMounted(() => {
`); `);
doc.close(); doc.close();
}); });
const displayAddresses = (addressesId) => {
// todo store members in rooms ?
addressesId = removeDuplicates(addressesId);
let res = "";
addressesId.forEach((addressId) => {
const address = store.getters.address(addressId);
if (address) res += address.email;
});
return res;
};
</script> </script>
<!-- to if to is more than me <!-- to if to is more than me
cc --> cc -->
@ -39,7 +52,9 @@ onMounted(() => {
<template> <template>
<div class="message"> <div class="message">
<div id="context"> <div id="context">
<div class="left" id="profile">{{ props.data.fromA }}</div> <div class="left" id="profile">
{{ displayAddresses(props.data.fromA?.split(",")) }} - {{ props.data.fromA }}
</div>
<div class="middle">{{ decodeEmojis(props.data.subject) }}</div> <div class="middle">{{ decodeEmojis(props.data.subject) }}</div>
<div class="right" id="date"> <div class="right" id="date">
{{ {{

View File

@ -1,44 +1,25 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es5", "target": "es5",
"module": "esnext", "module": "esnext",
"strict": true, "strict": true,
"jsx": "preserve", "jsx": "preserve",
"importHelpers": true, "importHelpers": true,
"allowJs": true, "allowJs": true,
"moduleResolution": "node", "moduleResolution": "node",
"skipLibCheck": true, "skipLibCheck": true,
"esModuleInterop": true, "esModuleInterop": true,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"useDefineForClassFields": true, "useDefineForClassFields": true,
"sourceMap": true, "sourceMap": true,
"baseUrl": ".", "baseUrl": ".",
"types": [ "types": ["webpack-env", "jest"],
"webpack-env", "paths": {
"jest" "@/*": ["src/*"]
], },
"paths": { "lib": ["esnext", "dom", "dom.iterable", "scripthost"]
"@/*": [
"src/*",
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}, },
"include": [ "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue", "tests/**/*.ts", "tests/**/*.tsx"],
"src/**/*.ts", "exclude": ["node_modules"]
"src/**/*.tsx", }
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
}