Skip to content

Commit

Permalink
feat: add endpoint for contacting support (#1570)
Browse files Browse the repository at this point in the history
This is a work in progress.
  • Loading branch information
aalemayhu authored Aug 8, 2024
1 parent 7a331bf commit 7b0d8f3
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 5 deletions.
19 changes: 19 additions & 0 deletions src/controllers/IndexController/IndexController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import AuthenticationService from '../../services/AuthenticationService';
import TokenRepository from '../../data_layer/TokenRepository';
import UsersRepository from '../../data_layer/UsersRepository';
import { configureUserLocal } from '../../routes/middleware/configureUserLocal';
import { useDefaultEmailService } from '../../services/EmailService/EmailService';

class IndexController {
public getIndex(request: express.Request, response: express.Response) {
Expand All @@ -18,6 +19,24 @@ class IndexController {
response.send(getIndexFileContents());
});
}

async contactUs(req: express.Request, res: express.Response) {
const { name, email, message } = req.body;
console.info('Contact Us', name, email, message);
if (!email || !message) {
return res.status(400).send({ error: 'Missing email or message' });
}

const attachments = req.files as Express.Multer.File[];
const defaultEmailService = useDefaultEmailService();
await defaultEmailService.sendContactEmail(
name,
email,
message,
attachments
);
return res.status(200).send();
}
}

export default IndexController;
5 changes: 0 additions & 5 deletions src/lib/misc/getUploadLimits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,6 @@ const FREE_USER_MAX_UPLOAD_SIZE = 100 * 1024 * 1024;
const PAYING_MAX_FIELD_SIZE = FREE_USER_MAX_FIELD_SIZE * 10;
const PAYING_MAX_UPLOAD_SIZE = FREE_USER_MAX_UPLOAD_SIZE * 100;

export interface UploaderInfo {
patron: boolean;
subscriber: boolean;
}

export const getUploadLimits = (paying: boolean) => {
if (paying) {
return {
Expand Down
10 changes: 10 additions & 0 deletions src/routes/DefaultRouter.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import express from 'express';
import multer from 'multer';

import RequireAuthentication from './middleware/RequireAuthentication';
import IndexController from '../controllers/IndexController/IndexController';

const upload = multer({
limits: { fileSize: 25 * 1024 * 1024 },
});

const DefaultRouter = () => {
const controller = new IndexController();
const router = express.Router();
Expand All @@ -10,6 +16,10 @@ const DefaultRouter = () => {
router.get('/search*', RequireAuthentication, controller.getIndex);
router.get('*', (req, res) => controller.getIndex(req, res));

router.post('/api/contact-us', upload.array('attachments'), (req, res) =>
controller.contactUs(req, res)
);

return router;
};

Expand Down
54 changes: 54 additions & 0 deletions src/services/EmailService/EmailService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,20 @@ import {
} from './constants';
import { isValidDeckName, addDeckNameSuffix } from '../../lib/anki/format';
import { ClientResponse } from '@sendgrid/mail';
import { SUPPORT_EMAIL_ADDRESS } from '../../lib/constants';

type EmailResponse = { didSend: boolean; error?: Error };

export interface IEmailService {
sendResetEmail(email: string, token: string): void;
sendConversionEmail(email: string, filename: string, contents: Buffer): void;
sendConversionLinkEmail(email: string, filename: string, link: string): void;
sendContactEmail(
name: string,
email: string,
message: string,
attachments: Express.Multer.File[]
): Promise<EmailResponse>;
}

class EmailService implements IEmailService {
Expand Down Expand Up @@ -79,6 +88,35 @@ class EmailService implements IEmailService {

await sgMail.send(msg);
}

async sendContactEmail(
name: string,
email: string,
message: string,
attachments: Express.Multer.File[]
): Promise<EmailResponse> {
const msg = {
to: SUPPORT_EMAIL_ADDRESS,
from: DEFAULT_SENDER,
subject: `Contact form submission on behalf of ${
name ?? 'Anon'
} <${email}>`,
text: `Message: ${message}\n\n`,
attachments: attachments.map((file) => ({
content: file.buffer.toString('base64'),
filename: file.originalname,
type: file.mimetype,
disposition: 'attachment',
})),
};
try {
await sgMail.send(msg);
return { didSend: true };
} catch (e) {
console.error('Error sending email', e);
return { didSend: false, error: e as Error };
}
}
}

export class UnimplementedEmailService implements IEmailService {
Expand All @@ -93,6 +131,22 @@ export class UnimplementedEmailService implements IEmailService {
sendConversionLinkEmail(email: string, filename: string, link: string): void {
console.info('sendConversionLinkEmail not handled', email, filename, link);
}

sendContactEmail(
name: string,
email: string,
message: string,
attachments: Express.Multer.File[]
): Promise<EmailResponse> {
console.info(
'sendContactEmail not handled',
name,
email,
message,
attachments
);
return Promise.resolve({ didSend: false });
}
}

export const useDefaultEmailService = () => {
Expand Down

0 comments on commit 7b0d8f3

Please sign in to comment.