directus

Форк
0
127 строк · 3.7 Кб
1
import { useEnv } from '@directus/env';
2
import { InvalidPayloadError } from '@directus/errors';
3
import type { Accountability, SchemaOverview } from '@directus/types';
4
import fse from 'fs-extra';
5
import type { Knex } from 'knex';
6
import { Liquid } from 'liquidjs';
7
import type { SendMailOptions, Transporter } from 'nodemailer';
8
import path from 'path';
9
import { fileURLToPath } from 'url';
10
import getDatabase from '../../database/index.js';
11
import { useLogger } from '../../logger.js';
12
import getMailer from '../../mailer.js';
13
import type { AbstractServiceOptions } from '../../types/index.js';
14
import { Url } from '../../utils/url.js';
15

16
const env = useEnv();
17
const logger = useLogger();
18

19
const __dirname = path.dirname(fileURLToPath(import.meta.url));
20

21
const liquidEngine = new Liquid({
22
	root: [path.resolve(env['EMAIL_TEMPLATES_PATH'] as string), path.resolve(__dirname, 'templates')],
23
	extname: '.liquid',
24
});
25

26
export type EmailOptions = SendMailOptions & {
27
	template?: {
28
		name: string;
29
		data: Record<string, any>;
30
	};
31
};
32

33
export class MailService {
34
	schema: SchemaOverview;
35
	accountability: Accountability | null;
36
	knex: Knex;
37
	mailer: Transporter;
38

39
	constructor(opts: AbstractServiceOptions) {
40
		this.schema = opts.schema;
41
		this.accountability = opts.accountability || null;
42
		this.knex = opts?.knex || getDatabase();
43
		this.mailer = getMailer();
44

45
		if (env['EMAIL_VERIFY_SETUP']) {
46
			this.mailer.verify((error) => {
47
				if (error) {
48
					logger.warn(`Email connection failed:`);
49
					logger.warn(error);
50
				}
51
			});
52
		}
53
	}
54

55
	async send<T>(options: EmailOptions): Promise<T> {
56
		const { template, ...emailOptions } = options;
57
		let { html } = options;
58

59
		const defaultTemplateData = await this.getDefaultTemplateData();
60

61
		const from = `${defaultTemplateData.projectName} <${options.from || (env['EMAIL_FROM'] as string)}>`;
62

63
		if (template) {
64
			let templateData = template.data;
65

66
			templateData = {
67
				...defaultTemplateData,
68
				...templateData,
69
			};
70

71
			html = await this.renderTemplate(template.name, templateData);
72
		}
73

74
		if (typeof html === 'string') {
75
			// Some email clients start acting funky when line length exceeds 75 characters. See #6074
76
			html = html
77
				.split('\n')
78
				.map((line) => line.trim())
79
				.join('\n');
80
		}
81

82
		const info = await this.mailer.sendMail({ ...emailOptions, from, html });
83
		return info;
84
	}
85

86
	private async renderTemplate(template: string, variables: Record<string, any>) {
87
		const customTemplatePath = path.resolve(env['EMAIL_TEMPLATES_PATH'] as string, template + '.liquid');
88
		const systemTemplatePath = path.join(__dirname, 'templates', template + '.liquid');
89

90
		const templatePath = (await fse.pathExists(customTemplatePath)) ? customTemplatePath : systemTemplatePath;
91

92
		if ((await fse.pathExists(templatePath)) === false) {
93
			throw new InvalidPayloadError({ reason: `Template "${template}" doesn't exist` });
94
		}
95

96
		const templateString = await fse.readFile(templatePath, 'utf8');
97
		const html = await liquidEngine.parseAndRender(templateString, variables);
98

99
		return html;
100
	}
101

102
	private async getDefaultTemplateData() {
103
		const projectInfo = await this.knex
104
			.select(['project_name', 'project_logo', 'project_color', 'project_url'])
105
			.from('directus_settings')
106
			.first();
107

108
		return {
109
			projectName: projectInfo?.project_name || 'Directus',
110
			projectColor: projectInfo?.project_color || '#171717',
111
			projectLogo: getProjectLogoURL(projectInfo?.project_logo),
112
			projectUrl: projectInfo?.project_url || '',
113
		};
114

115
		function getProjectLogoURL(logoID?: string) {
116
			const projectLogoUrl = new Url(env['PUBLIC_URL'] as string);
117

118
			if (logoID) {
119
				projectLogoUrl.addPath('assets', logoID);
120
			} else {
121
				projectLogoUrl.addPath('admin', 'img', 'directus-white.png');
122
			}
123

124
			return projectLogoUrl.toString();
125
		}
126
	}
127
}
128

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.