diff --git a/.gitignore b/.gitignore index 6bfe34914..cdc60680c 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,8 @@ modoboa.kdev4 .kateproject test_project/cert.crt test_project/cert.key +test_project/envfile + +# Docker +docker/collections +docker/redis diff --git a/docker-compose.yml b/docker-compose.yml index fb8d92ff7..047f7514d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,8 +1,11 @@ services: redis: - image: redis:5-alpine + image: redis:7-alpine ports: - 6379:6379 + command: redis-server --save 60 1 --loglevel warning + volumes: + - ./docker/redis:/data rq: build: @@ -29,6 +32,7 @@ services: - 8000:8000 env_file: - test_project/oidc_key + - test_project/envfile environment: DB: "SQLITE" DEBUG: "True" @@ -93,7 +97,7 @@ services: dovecot: container_name: modoboa_dovecot restart: unless-stopped - image: dovecot/dovecot:latest + image: dovecot/dovecot:2.3-latest depends_on: - api volumes: @@ -107,6 +111,7 @@ services: dockerfile: docker/Dockerfile.radicale.dev volumes: - ./docker/radicale_config:/etc/radicale + - ./docker/collections:/collections policyd: container_name: modoboa_policyd diff --git a/frontend/package.json b/frontend/package.json index 68347ab85..3b8e72fda 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -22,10 +22,16 @@ "@fullcalendar/vue3": "^6.1.15", "@github/webauthn-json": "^2.1.1", "@mdi/font": "^7.3.67", + "@tiptap/extension-highlight": "^2.11.7", + "@tiptap/extension-text-align": "^2.11.7", + "@tiptap/pm": "^2.11.7", + "@tiptap/starter-kit": "^2.11.7", + "@tiptap/vue-3": "^2.11.7", "apexcharts": "^3.50.0", "axios": "^1.8.2", "core-js": "^3.37.1", "debounce": "^2.1.0", + "filesize": "^10.1.6", "js-cookie": "^3.0.5", "luxon": "^3.4.4", "oidc-client-ts": "^3.0.1", @@ -36,7 +42,7 @@ "vue-router": "^4.4.0", "vue3-apexcharts": "^1.5.3", "vue3-gettext": "^3.0.0-beta.6", - "vuetify": "^3.6.12" + "vuetify": "^3.8.3" }, "devDependencies": { "@vitejs/plugin-basic-ssl": "^1.1.0", @@ -47,7 +53,7 @@ "prettier": "^3.3.2", "sass": "1.77.1", "unplugin-fonts": "^1.0.3", - "vite": "^5.4.18", + "vite": "^6.3.4", "vite-plugin-vuetify": "^2.0.3" } } diff --git a/frontend/src/api/webmail.js b/frontend/src/api/webmail.js new file mode 100644 index 000000000..249686b9a --- /dev/null +++ b/frontend/src/api/webmail.js @@ -0,0 +1,123 @@ +import repository from './repository' + +export default { + getUserMailboxes(mailbox) { + const params = {} + if (mailbox) { + params.mailbox = mailbox + } + return repository.get('/webmail/mailboxes/', { params }) + }, + getUserMailboxQuota(mailbox) { + const params = { mailbox } + return repository.get('/webmail/mailboxes/quota/', { params }) + }, + getUserMailboxUnseen(mailbox) { + const params = { mailbox } + return repository.get('webmail/mailboxes/unseen/', { params }) + }, + createUserMailbox(body) { + return repository.post('/webmail/mailboxes/', body) + }, + renameUserMailbox(body) { + return repository.post('/webmail/mailboxes/rename/', body) + }, + compressUserMailbox(body) { + return repository.post('/webmail/mailboxes/compress/', body) + }, + deleteUserMailbox(body) { + return repository.post('/webmail/mailboxes/delete/', body) + }, + emptyUserMailbox(mailbox) { + const body = { name: mailbox } + return repository.post('/webmail/mailboxes/empty/', body) + }, + getMailboxEmails(mailbox, options) { + const params = { + mailbox, + ...options, + } + return repository.get(`/webmail/emails/`, { params }) + }, + getEmailContent(mailbox, mailid, options) { + const params = { + mailbox, + mailid, + ...options, + } + return repository.get(`/webmail/emails/content/`, { params }) + }, + getEmailSource(mailbox, mailid) { + const params = { + mailbox, + mailid, + } + return repository.get(`/webmail/emails/source/`, { params }) + }, + getEmailAttachment(mailbox, mailid, partnum) { + const params = { + mailbox, + mailid, + partnum, + } + return repository.get(`/webmail/emails/attachment/`, { + params, + responseType: 'blob', + }) + }, + deleteSelection(mailbox, selection) { + const body = { + mailbox, + selection, + } + return repository.post('/webmail/emails/delete/', body) + }, + markSelectionAsJunk(mailbox, selection) { + const body = { + mailbox, + selection, + } + return repository.post('/webmail/emails/mark_as_junk/', body) + }, + markSelectionAsNotJunk(mailbox, selection) { + const body = { + mailbox, + selection, + } + return repository.post('/webmail/emails/mark_as_not_junk/', body) + }, + flagSelection(mailbox, selection, status) { + const body = { + mailbox, + selection, + status, + } + return repository.post('/webmail/emails/flag/', body) + }, + sendEmail(body) { + return repository.post('/webmail/emails/send/', body) + }, + getComposeSession(uid) { + return repository.get(`/webmail/compose-sessions/${uid}/`) + }, + createComposeSession() { + return repository.post('/webmail/compose-sessions/') + }, + getAllowedSenders() { + return repository.get('/webmail/compose-sessions/allowed_senders/') + }, + uploadAttachment(sessionUid, body) { + return repository.post( + `/webmail/compose-sessions/${sessionUid}/attachments/`, + body, + { + headers: { 'Content-Type': 'multipart/form-data' }, + } + ) + }, + removeAttachment(sessionUid, name) { + return repository.delete( + `/webmail/compose-sessions/${sessionUid}/attachments/${name}/` + ) + }, +} diff --git a/frontend/src/components/shared/NavBar.vue b/frontend/src/components/shared/NavBar.vue index 7628d8d0c..6cc5c4a59 100644 --- a/frontend/src/components/shared/NavBar.vue +++ b/frontend/src/components/shared/NavBar.vue @@ -21,7 +21,11 @@ - +