rainbox.email/src/controllers/backend/MailboxBackendController.ts

209 lines
8.7 KiB
TypeScript

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} 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-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('/:id', this.getMailboxBackend, 'backend-mailbox', 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('/delete-mail-identity', this.postDeleteMailIdentity, 'backend-delete-mail-identity', RequireAuthMiddleware, RequireAdminMiddleware);
}
protected async getMailboxesBackend(req: Request, res: Response): Promise<void> {
const mailDomains = await MailDomain.select()
.with('owner')
.with('identities')
.get();
const users = await User.select()
.where('main_mail_identity_id', null, WhereTest.NE)
.with('mainMailIdentity')
.with('mailIdentities')
.get();
res.render('backend/mailboxes', {
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,
}))),
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<void> {
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.',
},
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 postAddDomain(req: Request, res: Response): Promise<void> {
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-mailboxes'));
}
protected async getEditDomain(req: Request, res: Response): Promise<void> {
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<void> {
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-mailboxes'));
}
protected async postRemoveDomain(req: Request, res: Response): Promise<void> {
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-mailboxes'));
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<void> {
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', req.params.id));
}
protected async postDeleteMailIdentity(req: Request, res: Response): Promise<void> {
const identity = await MailIdentity.select()
.where('id', req.body.id)
.with('user')
.first();
if (!identity) throw new NotFoundHttpError('Mail identity', req.url);
const user = await identity.user.get();
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', req.params.id));
return;
}
await identity.delete();
req.flash('success', 'Identity ' + await identity.toEmail() + ' successfully deleted.');
res.redirect(Controller.route('backend-mailbox', req.params.id));
}
}