import Controller from "swaf/Controller"; import {Request, Response} from "express"; import User from "swaf/auth/models/User"; import {WhereTest} from "swaf/db/ModelQuery"; import UserMailIdentityComponent from "../../models/UserMailIdentityComponent"; import {NotFoundHttpError, ServerError} from "swaf/HttpError"; import MailDomain from "../../models/MailDomain"; import BackendController from "swaf/helpers/BackendController"; import MailIdentity from "../../models/MailIdentity"; import {RequireAdminMiddleware, RequireAuthMiddleware} from "swaf/auth/AuthComponent"; import UserNameComponent from "swaf/auth/models/UserNameComponent"; export default class MailboxBackendController extends Controller { public constructor() { super(); BackendController.registerMenuElement({ getLink: async () => Controller.route('backend-mail-domains'), getDisplayString: async () => 'Mail domains', getDisplayIcon: async () => 'globe', }); BackendController.registerMenuElement({ getLink: async () => Controller.route('backend-mailboxes'), getDisplayString: async () => 'Mailboxes', getDisplayIcon: async () => 'mail', }); } public getRoutesPrefix(): string { return '/backend/mailboxes'; } public routes(): void { this.get('/', this.getMailboxesBackend, 'backend-mailboxes', RequireAuthMiddleware, RequireAdminMiddleware); this.get('/mailbox/:id', this.getMailboxBackend, 'backend-mailbox', RequireAuthMiddleware, RequireAdminMiddleware); this.get('/domains', this.getDomainsBackend, 'backend-mail-domains', RequireAuthMiddleware, RequireAdminMiddleware); this.post('/add-domain', this.postAddDomain, 'backend-add-domain', RequireAuthMiddleware, RequireAdminMiddleware); this.get('/edit-domain/:id', this.getEditDomain, 'backend-edit-domain', RequireAuthMiddleware, RequireAdminMiddleware); this.post('/edit-domain/:id', this.postEditDomain, 'backend-edit-domain', RequireAuthMiddleware, RequireAdminMiddleware); this.post('/remove-domain', this.postRemoveDomain, 'backend-remove-domain', RequireAuthMiddleware, RequireAdminMiddleware); this.post('/:id/create-mail-identity', this.postCreateMailIdentity, 'backend-create-mail-identity', RequireAuthMiddleware, RequireAdminMiddleware); this.post('/set-main-mail-identity', this.postSetMainMailIdentity, 'backend-set-main-mail-identity', RequireAuthMiddleware, RequireAdminMiddleware); this.post('/delete-mail-identity', this.postDeleteMailIdentity, 'backend-delete-mail-identity', RequireAuthMiddleware, RequireAdminMiddleware); } protected async getMailboxesBackend(req: Request, res: Response): Promise { const users = await User.select() .where('main_mail_identity_id', null, WhereTest.NE) .with('mainMailIdentity') .with('mailIdentities') .get(); res.render('backend/mailboxes', { users: [{ value: 0, display: 'Public', }, ...(await User.select().get()).map(u => ({ value: u.id, display: u.name, }))], mailboxes: await Promise.all(users.map(async user => ({ id: user.id, username: user.as(UserNameComponent).name, name: await (await user.as(UserMailIdentityComponent).mainMailIdentity.get())?.toEmail(), identity_count: (await user.as(UserMailIdentityComponent).mailIdentities.get()).length, domain_count: (await user.as(UserMailIdentityComponent).mailDomains.get()).length, }))), }); } protected async getMailboxBackend(req: Request, res: Response): Promise { const user = await User.select() .where('id', req.params.id) .with('mailIdentities') .first(); if (!user) throw new NotFoundHttpError('User', req.url); const mainMailIdentity = await user.as(UserMailIdentityComponent).mainMailIdentity.get(); const mailDomains = await MailDomain.select().get(); const mailIdentities = await user.as(UserMailIdentityComponent).mailIdentities.get(); res.render('backend/mailbox', { mailbox: { id: user.id, userName: user.as(UserNameComponent).name, name: await mainMailIdentity?.toEmail() || 'Not created.', exists: !!mainMailIdentity, }, domains: mailDomains.map(d => ({ display: d.name, value: d.id, })), identities: await Promise.all(mailIdentities.map(async i => ({ id: i.id, email: await i.toEmail(), }))), }); } protected async getDomainsBackend(req: Request, res: Response): Promise { const mailDomains = await MailDomain.select() .with('owner') .with('identities') .get(); res.render('backend/mail_domains', { domains: await Promise.all(mailDomains.map(async domain => ({ id: domain.id, name: domain.name, owner_name: (await domain.owner.get())?.as(UserNameComponent).name, identity_count: (await domain.identities.get()).length, }))), }); } protected async postAddDomain(req: Request, res: Response): Promise { const domain = MailDomain.create(req.body); await domain.save(); req.flash('success', `Domain ${domain.name} successfully added with owner ${(await domain.owner.get())?.name}`); res.redirect(Controller.route('backend-edit-domain', domain.id)); } protected async getEditDomain(req: Request, res: Response): Promise { const domain = await MailDomain.getById(req.params.id); if (!domain) throw new NotFoundHttpError('Domain', req.url); res.render('backend/mail_domain', { domain: domain, users: [{ value: 0, display: 'Public', }, ...(await User.select().get()).map(u => ({ value: u.id, display: u.name, }))], }); } protected async postEditDomain(req: Request, res: Response): Promise { const domain = await MailDomain.select() .where('id', req.params.id) .first(); if (!domain) throw new NotFoundHttpError('Domain', req.url); domain.updateWithData(req.body); await domain.save(); req.flash('success', `Domain ${domain.name} updated successfully.`); res.redirect(Controller.route('backend-edit-domain', domain.id)); } protected async postRemoveDomain(req: Request, res: Response): Promise { const domain = await MailDomain.select() .where('id', req.body.id) .with('identities') .first(); if (!domain) throw new NotFoundHttpError('Domain', req.url); // Don't delete that domain if it still has identities if ((await domain.identities.get()).length > 0) { req.flash('error', `This domain still has identities. Please remove all of these first (don't forget to rename mailboxes).`); res.redirect(Controller.route('backend-edit-domain', domain.id)); return; } await domain.delete(); req.flash('success', `Domain ${domain.name} successfully deleted.`); res.redirect(Controller.route('backend-mailboxes')); } protected async postCreateMailIdentity(req: Request, res: Response): Promise { const user = await User.select() .where('id', req.params.id) .first(); if (!user) throw new NotFoundHttpError('User', req.url); const domain = await MailDomain.getById(req.body.mail_domain_id); if (!domain) throw new NotFoundHttpError('domain', req.url); const mailIdentityComponent = user.as(UserMailIdentityComponent); const identity = MailIdentity.create({ user_id: user.id, name: req.body.name, mail_domain_id: req.body.mail_domain_id, }); // Save identity await identity.save(); // Set main mail identity if not already set if (!mailIdentityComponent.main_mail_identity_id) { mailIdentityComponent.main_mail_identity_id = identity.id; await user.save(); req.flash('info', 'Mailbox created.'); } req.flash('success', 'Mail identity ' + await identity.toEmail() + ' successfully created.'); res.redirect(Controller.route('backend-mailbox', user.id)); } protected async postDeleteMailIdentity(req: Request, res: Response): Promise { const identity = await MailIdentity.select() .where('id', req.body.id) .with('user') .first(); if (!identity) throw new NotFoundHttpError('Mail identity', req.url); const user = identity.user.getOrFail(); if (!user) throw new NotFoundHttpError('Mail identity owner', req.url); if (user.as(UserMailIdentityComponent).main_mail_identity_id === identity.id) { req.flash('error', `Cannot delete this user's mailbox identity.`); res.redirect(Controller.route('backend-mailbox', user.id)); return; } await identity.delete(); req.flash('success', 'Identity ' + await identity.toEmail() + ' successfully deleted.'); res.redirect(Controller.route('backend-mailbox', user.id)); } protected async postSetMainMailIdentity(req: Request, res: Response): Promise { const identity = await MailIdentity.select() .where('id', req.body.id) .with('user.mainMailIdentity') .first(); if (!identity) throw new NotFoundHttpError('Mail identity', req.url); const user = await identity.user.getOrFail(); if (!user) throw new NotFoundHttpError('Mail identity owner', req.url); const mailIdentityComponent = user.as(UserMailIdentityComponent); const mainMailIdentity = mailIdentityComponent.mainMailIdentity.getOrFail(); if (!mainMailIdentity) throw new ServerError('Could not find this users main mail identity.'); mailIdentityComponent.main_mail_identity_id = identity.id; await user.save(); req.flash('success', 'User ' + user.id + ' main mail identity set to ' + await identity.toEmail()); req.flash('warning', 'Please rename user\'s mailbox folder to correspond to changing from ' + await mainMailIdentity.toEmail() + ' to ' + await identity.toEmail()); res.redirect(Controller.route('backend-mailbox', user.id)); } }