diff --git a/dashboard/public/js/index.js b/dashboard/public/js/index.js index 096081c5e..df6ee2f0a 100644 --- a/dashboard/public/js/index.js +++ b/dashboard/public/js/index.js @@ -80,8 +80,8 @@ app.config(['$routeProvider', function ($routeProvider) { // controller: 'DomainsController', // templateUrl: 'views/domains.html?' + window.VITE_CACHE_ID }).when('/email', { - controller: 'EmailsController', - templateUrl: 'views/emails.html?' + window.VITE_CACHE_ID + // controller: 'EmailsController', + // templateUrl: 'views/emails.html?' + window.VITE_CACHE_ID }).when('/emails-eventlog', { controller: 'EmailsEventlogController', templateUrl: 'views/emails-eventlog.html?' + window.VITE_CACHE_ID diff --git a/dashboard/src/Index.vue b/dashboard/src/Index.vue index ade6f97c7..b6b5c62d9 100644 --- a/dashboard/src/Index.vue +++ b/dashboard/src/Index.vue @@ -8,6 +8,7 @@ import AppstoreView from './views/AppstoreView.vue'; import BackupsView from './views/BackupsView.vue'; import BrandingView from './views/BrandingView.vue'; import DomainsView from './views/DomainsView.vue'; +import EmailsView from './views/EmailsView.vue'; import EventlogView from './views/EventlogView.vue'; import NetworkView from './views/NetworkView.vue'; import ProfileView from './views/ProfileView.vue'; @@ -26,6 +27,7 @@ const VIEWS = { BACKUPS: 'backups', BRANDING: 'branding', DOMAINS: 'domains', + EMAILS: 'email', EVENTLOG: 'eventlog', NETWORK: 'network', PROFILE: 'profile', @@ -55,6 +57,8 @@ function onHashChange() { view.value = VIEWS.BRANDING; } else if (v === VIEWS.DOMAINS) { view.value = VIEWS.DOMAINS; + } else if (v === VIEWS.EMAILS) { + view.value = VIEWS.EMAILS; } else if (v === VIEWS.EVENTLOG) { view.value = VIEWS.EVENTLOG; } else if (v === VIEWS.NETWORK) { @@ -105,6 +109,7 @@ onMounted(async () => { + diff --git a/dashboard/src/components/SettingsItem.vue b/dashboard/src/components/SettingsItem.vue new file mode 100644 index 000000000..0b99a7ff2 --- /dev/null +++ b/dashboard/src/components/SettingsItem.vue @@ -0,0 +1,29 @@ + + + + + \ No newline at end of file diff --git a/dashboard/src/models/MailModel.js b/dashboard/src/models/MailModel.js new file mode 100644 index 000000000..301f21838 --- /dev/null +++ b/dashboard/src/models/MailModel.js @@ -0,0 +1,234 @@ + +import { fetcher } from 'pankow'; +import { API_ORIGIN } from '../constants.js'; + +function create() { + const accessToken = localStorage.token; + + return { + async config(domain) { + let result; + try { + result = await fetcher.get(`${API_ORIGIN}/api/v1/mail/${domain}`, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 200) return [result]; + return [null, result.body]; + }, + async status(domain) { + let result; + try { + result = await fetcher.get(`${API_ORIGIN}/api/v1/mail/${domain}/status`, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 200) return [result]; + return [null, result.body]; + }, + async mailboxCount(domain) { + let result; + try { + result = await fetcher.get(`${API_ORIGIN}/api/v1/mail/${domain}/mailbox_count`, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 200) return [result]; + return [null, result.body.count]; + }, + async usage(domain) { + let result; + try { + result = await fetcher.get(`${API_ORIGIN}/api/v1/mailserver/usage`, { domain, access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 200) return [result]; + return [null, result.body.usage]; + }, + async location() { + let result; + try { + result = await fetcher.get(`${API_ORIGIN}/api/v1/mailserver/location`, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 200) return [result]; + return [null, result.body]; + }, + async setLocation(subdomain, domain) { + let result; + try { + result = await fetcher.post(`${API_ORIGIN}/api/v1/mailserver/location`, { subdomain, domain }, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 202) return [result]; + return [null, result.body.taskId]; + }, + async maxEmailSize() { + let result; + try { + result = await fetcher.get(`${API_ORIGIN}/api/v1/mailserver/max_email_size`, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 200) return [result]; + return [null, result.body.size]; + }, + async setMaxEmailSize(size) { + let result; + try { + result = await fetcher.post(`${API_ORIGIN}/api/v1/mailserver/max_email_size`, { size }, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 200) return [result]; + return [null]; + }, + async mailboxSharing() { + let result; + try { + result = await fetcher.get(`${API_ORIGIN}/api/v1/mailserver/mailbox_sharing`, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 200) return [result]; + return [null, result.body.enabled]; + }, + async setMailboxSharing(enable) { + let result; + try { + result = await fetcher.post(`${API_ORIGIN}/api/v1/mailserver/mailbox_sharing`, { enable }, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 200) return [result]; + return [null]; + }, + async virtualAllMail() { + let result; + try { + result = await fetcher.get(`${API_ORIGIN}/api/v1/mailserver/virtual_all_mail`, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 200) return [result]; + return [null, result.body.enabled]; + }, + async setVirtualAllMail(enable) { + let result; + try { + result = await fetcher.post(`${API_ORIGIN}/api/v1/mailserver/virtual_all_mail`, { enable }, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 200) return [result]; + return [null]; + }, + async dnsblConfig() { + let result; + try { + result = await fetcher.get(`${API_ORIGIN}/api/v1/mailserver/dnsbl_config`, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 200) return [result]; + return [null, result.body.zones]; + }, + async setDnsblConfig(zones) { + let result; + try { + result = await fetcher.post(`${API_ORIGIN}/api/v1/mailserver/dnsbl_config`, { zones }, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 200) return [result]; + return [null]; + }, + async ftsConfig() { + let result; + try { + result = await fetcher.get(`${API_ORIGIN}/api/v1/mailserver/fts_config`, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 200) return [result]; + return [null, result.body]; + }, + async setFtsConfig(enable) { + let result; + try { + result = await fetcher.post(`${API_ORIGIN}/api/v1/mailserver/fts_config`, { enable }, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 200) return [result]; + return [null]; + }, + async spamAcl() { + let result; + try { + result = await fetcher.get(`${API_ORIGIN}/api/v1/mailserver/spam_acl`, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 200) return [result]; + return [null, result.body]; + }, + async setSpamAcl(allowlist, blocklist) { + let result; + try { + result = await fetcher.post(`${API_ORIGIN}/api/v1/mailserver/spam_acl`, { allowlist, blocklist }, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 200) return [result]; + return [null]; + }, + async spamCustomConfig() { + let result; + try { + result = await fetcher.get(`${API_ORIGIN}/api/v1/mailserver/spam_custom_config`, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 200) return [result]; + return [null, result.body.config]; + }, + async setSpamCustomConfig(config) { + let result; + try { + result = await fetcher.post(`${API_ORIGIN}/api/v1/mailserver/spam_custom_config`, { config }, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 200) return [result]; + return [null]; + }, + }; +} + +export default { + create, +}; diff --git a/dashboard/src/views/EmailsView.vue b/dashboard/src/views/EmailsView.vue new file mode 100644 index 000000000..cd24dbeca --- /dev/null +++ b/dashboard/src/views/EmailsView.vue @@ -0,0 +1,278 @@ + + +