@flusys/nestjs-email 4.1.1 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -384
- package/cjs/config/message-keys.js +1 -38
- package/cjs/controllers/email-template.controller.js +9 -3
- package/cjs/docs/email-swagger.config.js +5 -3
- package/cjs/dtos/email-template.dto.js +1 -21
- package/cjs/entities/email-config.entity.js +2 -1
- package/cjs/entities/email-template.entity.js +3 -8
- package/cjs/providers/email-factory.service.js +5 -5
- package/cjs/providers/mailgun-provider.js +5 -2
- package/cjs/providers/sendgrid-provider.js +5 -2
- package/cjs/services/email-provider-config.service.js +0 -10
- package/cjs/services/email-template.service.js +0 -13
- package/config/message-keys.d.ts +0 -68
- package/dtos/email-template.dto.d.ts +0 -2
- package/entities/email-template.entity.d.ts +0 -1
- package/fesm/config/message-keys.js +1 -33
- package/fesm/controllers/email-template.controller.js +10 -4
- package/fesm/docs/email-swagger.config.js +5 -3
- package/fesm/dtos/email-template.dto.js +1 -21
- package/fesm/entities/email-config.entity.js +2 -1
- package/fesm/entities/email-template.entity.js +3 -8
- package/fesm/providers/email-factory.service.js +5 -5
- package/fesm/providers/mailgun-provider.js +5 -2
- package/fesm/providers/sendgrid-provider.js +5 -2
- package/fesm/services/email-provider-config.service.js +0 -10
- package/fesm/services/email-template.service.js +0 -13
- package/interfaces/email-template.interface.d.ts +0 -1
- package/package.json +3 -3
- package/services/email-provider-config.service.d.ts +0 -2
- package/services/email-template.service.d.ts +0 -1
|
@@ -22,7 +22,8 @@ Object.defineProperty(exports, "emailSwaggerConfig", {
|
|
|
22
22
|
]
|
|
23
23
|
}
|
|
24
24
|
];
|
|
25
|
-
function buildDescription(enableCompanyFeature) {
|
|
25
|
+
function buildDescription(enableCompanyFeature, isMultiTenant) {
|
|
26
|
+
const multiTenantNote = isMultiTenant ? `\n> **Multi-Tenant Mode**: Include \`x-tenant-id\` header to target a specific tenant database.\n` : '';
|
|
26
27
|
const companyConfigs = enableCompanyFeature ? '\n- **Company-level email configs**' : '';
|
|
27
28
|
const companyIsolation = enableCompanyFeature ? '\n- **Company isolation**' : '';
|
|
28
29
|
const multiTenantSection = enableCompanyFeature ? `
|
|
@@ -35,7 +36,7 @@ All queries automatically filter by current user's company context.
|
|
|
35
36
|
` : '';
|
|
36
37
|
return `
|
|
37
38
|
# Email Management API
|
|
38
|
-
|
|
39
|
+
${multiTenantNote}
|
|
39
40
|
Complete email management system${enableCompanyFeature ? ' with multi-tenant and company support' : ''}.
|
|
40
41
|
|
|
41
42
|
## Features
|
|
@@ -102,9 +103,10 @@ All email endpoints are prefixed with \`/email\`:
|
|
|
102
103
|
}
|
|
103
104
|
function emailSwaggerConfig(bootstrapConfig) {
|
|
104
105
|
const enableCompanyFeature = bootstrapConfig?.enableCompanyFeature ?? true;
|
|
106
|
+
const isMultiTenant = bootstrapConfig?.databaseMode === 'multi-tenant';
|
|
105
107
|
return {
|
|
106
108
|
title: 'Email API',
|
|
107
|
-
description: buildDescription(enableCompanyFeature),
|
|
109
|
+
description: buildDescription(enableCompanyFeature, isMultiTenant),
|
|
108
110
|
version: '1.0',
|
|
109
111
|
path: 'api/docs/email',
|
|
110
112
|
bearerAuth: true,
|
|
@@ -55,7 +55,6 @@ let CreateEmailTemplateDto = class CreateEmailTemplateDto {
|
|
|
55
55
|
_define_property(this, "textContent", void 0);
|
|
56
56
|
_define_property(this, "isActive", void 0);
|
|
57
57
|
_define_property(this, "isHtml", void 0);
|
|
58
|
-
_define_property(this, "metadata", void 0);
|
|
59
58
|
}
|
|
60
59
|
};
|
|
61
60
|
_ts_decorate([
|
|
@@ -139,18 +138,6 @@ _ts_decorate([
|
|
|
139
138
|
(0, _classvalidator.IsOptional)(),
|
|
140
139
|
_ts_metadata("design:type", Boolean)
|
|
141
140
|
], CreateEmailTemplateDto.prototype, "isHtml", void 0);
|
|
142
|
-
_ts_decorate([
|
|
143
|
-
(0, _swagger.ApiPropertyOptional)({
|
|
144
|
-
type: 'object',
|
|
145
|
-
additionalProperties: true,
|
|
146
|
-
example: {
|
|
147
|
-
category: 'onboarding'
|
|
148
|
-
}
|
|
149
|
-
}),
|
|
150
|
-
(0, _classvalidator.IsObject)(),
|
|
151
|
-
(0, _classvalidator.IsOptional)(),
|
|
152
|
-
_ts_metadata("design:type", typeof Record === "undefined" ? Object : Record)
|
|
153
|
-
], CreateEmailTemplateDto.prototype, "metadata", void 0);
|
|
154
141
|
let UpdateEmailTemplateDto = class UpdateEmailTemplateDto extends (0, _swagger.PartialType)(CreateEmailTemplateDto) {
|
|
155
142
|
constructor(...args){
|
|
156
143
|
super(...args), _define_property(this, "id", void 0);
|
|
@@ -166,7 +153,7 @@ _ts_decorate([
|
|
|
166
153
|
], UpdateEmailTemplateDto.prototype, "id", void 0);
|
|
167
154
|
let EmailTemplateResponseDto = class EmailTemplateResponseDto extends _dtos.IdentityResponseDto {
|
|
168
155
|
constructor(...args){
|
|
169
|
-
super(...args), _define_property(this, "name", void 0), _define_property(this, "slug", void 0), _define_property(this, "description", void 0), _define_property(this, "subject", void 0), _define_property(this, "schema", void 0), _define_property(this, "htmlContent", void 0), _define_property(this, "textContent", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "isActive", void 0), _define_property(this, "isHtml", void 0)
|
|
156
|
+
super(...args), _define_property(this, "name", void 0), _define_property(this, "slug", void 0), _define_property(this, "description", void 0), _define_property(this, "subject", void 0), _define_property(this, "schema", void 0), _define_property(this, "htmlContent", void 0), _define_property(this, "textContent", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "isActive", void 0), _define_property(this, "isHtml", void 0);
|
|
170
157
|
}
|
|
171
158
|
};
|
|
172
159
|
_ts_decorate([
|
|
@@ -212,10 +199,3 @@ _ts_decorate([
|
|
|
212
199
|
(0, _swagger.ApiProperty)(),
|
|
213
200
|
_ts_metadata("design:type", Boolean)
|
|
214
201
|
], EmailTemplateResponseDto.prototype, "isHtml", void 0);
|
|
215
|
-
_ts_decorate([
|
|
216
|
-
(0, _swagger.ApiPropertyOptional)({
|
|
217
|
-
type: 'object',
|
|
218
|
-
additionalProperties: true
|
|
219
|
-
}),
|
|
220
|
-
_ts_metadata("design:type", Object)
|
|
221
|
-
], EmailTemplateResponseDto.prototype, "metadata", void 0);
|
|
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "EmailConfig", {
|
|
|
8
8
|
return EmailConfig;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
+
const _nestjsshared = require("@flusys/nestjs-shared");
|
|
11
12
|
const _entities = require("@flusys/nestjs-shared/entities");
|
|
12
13
|
const _typeorm = require("typeorm");
|
|
13
14
|
function _define_property(obj, key, value) {
|
|
@@ -55,7 +56,7 @@ _ts_decorate([
|
|
|
55
56
|
], EmailConfig.prototype, "provider", void 0);
|
|
56
57
|
_ts_decorate([
|
|
57
58
|
(0, _typeorm.Column)({
|
|
58
|
-
type:
|
|
59
|
+
type: (0, _nestjsshared.getJsonColumnType)(),
|
|
59
60
|
nullable: false
|
|
60
61
|
}),
|
|
61
62
|
_ts_metadata("design:type", typeof Record === "undefined" ? Object : Record)
|
|
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "EmailTemplate", {
|
|
|
8
8
|
return EmailTemplate;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
+
const _nestjsshared = require("@flusys/nestjs-shared");
|
|
11
12
|
const _entities = require("@flusys/nestjs-shared/entities");
|
|
12
13
|
const _typeorm = require("typeorm");
|
|
13
14
|
function _define_property(obj, key, value) {
|
|
@@ -34,7 +35,7 @@ function _ts_metadata(k, v) {
|
|
|
34
35
|
}
|
|
35
36
|
let EmailTemplate = class EmailTemplate extends _entities.Identity {
|
|
36
37
|
constructor(...args){
|
|
37
|
-
super(...args), _define_property(this, "name", void 0), _define_property(this, "slug", void 0), _define_property(this, "description", void 0), _define_property(this, "subject", void 0), _define_property(this, "schema", void 0), _define_property(this, "htmlContent", void 0), _define_property(this, "textContent", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "isActive", void 0), _define_property(this, "isHtml", void 0)
|
|
38
|
+
super(...args), _define_property(this, "name", void 0), _define_property(this, "slug", void 0), _define_property(this, "description", void 0), _define_property(this, "subject", void 0), _define_property(this, "schema", void 0), _define_property(this, "htmlContent", void 0), _define_property(this, "textContent", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "isActive", void 0), _define_property(this, "isHtml", void 0);
|
|
38
39
|
}
|
|
39
40
|
};
|
|
40
41
|
_ts_decorate([
|
|
@@ -71,7 +72,7 @@ _ts_decorate([
|
|
|
71
72
|
], EmailTemplate.prototype, "subject", void 0);
|
|
72
73
|
_ts_decorate([
|
|
73
74
|
(0, _typeorm.Column)({
|
|
74
|
-
type:
|
|
75
|
+
type: (0, _nestjsshared.getJsonColumnType)(),
|
|
75
76
|
nullable: false
|
|
76
77
|
}),
|
|
77
78
|
_ts_metadata("design:type", typeof Record === "undefined" ? Object : Record)
|
|
@@ -117,12 +118,6 @@ _ts_decorate([
|
|
|
117
118
|
}),
|
|
118
119
|
_ts_metadata("design:type", Boolean)
|
|
119
120
|
], EmailTemplate.prototype, "isHtml", void 0);
|
|
120
|
-
_ts_decorate([
|
|
121
|
-
(0, _typeorm.Column)('simple-json', {
|
|
122
|
-
nullable: true
|
|
123
|
-
}),
|
|
124
|
-
_ts_metadata("design:type", Object)
|
|
125
|
-
], EmailTemplate.prototype, "metadata", void 0);
|
|
126
121
|
EmailTemplate = _ts_decorate([
|
|
127
122
|
(0, _typeorm.Entity)({
|
|
128
123
|
name: 'email_template'
|
|
@@ -9,9 +9,9 @@ Object.defineProperty(exports, "EmailFactoryService", {
|
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
11
|
const _nestjsshared = require("@flusys/nestjs-shared");
|
|
12
|
-
const _config = require("../config");
|
|
13
12
|
const _common = require("@nestjs/common");
|
|
14
13
|
const _crypto = require("crypto");
|
|
14
|
+
const _config = require("../config");
|
|
15
15
|
const _interfaces = require("../interfaces");
|
|
16
16
|
const _emailproviderregistry = require("./email-provider.registry");
|
|
17
17
|
function _define_property(obj, key, value) {
|
|
@@ -47,7 +47,7 @@ let EmailFactoryService = class EmailFactoryService {
|
|
|
47
47
|
throw new _common.NotFoundException({
|
|
48
48
|
message: `Email provider '${config.provider}' is not registered`,
|
|
49
49
|
messageKey: _config.EMAIL_SEND_MESSAGES.CONFIG_NOT_FOUND,
|
|
50
|
-
|
|
50
|
+
messageVariables: {
|
|
51
51
|
provider: config.provider,
|
|
52
52
|
available: _emailproviderregistry.EmailProviderRegistry.getAll().join(', ')
|
|
53
53
|
}
|
|
@@ -60,11 +60,11 @@ let EmailFactoryService = class EmailFactoryService {
|
|
|
60
60
|
return instance;
|
|
61
61
|
} catch (error) {
|
|
62
62
|
throw new _common.InternalServerErrorException({
|
|
63
|
-
message: `
|
|
63
|
+
message: `Email provider '${config.provider}' not initialized successfully: ${this.extractErrorMessage(error)}`,
|
|
64
64
|
messageKey: _nestjsshared.SYSTEM_MESSAGES.SERVICE_NOT_AVAILABLE,
|
|
65
|
-
|
|
65
|
+
messageVariables: {
|
|
66
66
|
provider: config.provider,
|
|
67
|
-
|
|
67
|
+
available: _emailproviderregistry.EmailProviderRegistry.getAll().join(', ')
|
|
68
68
|
}
|
|
69
69
|
});
|
|
70
70
|
}
|
|
@@ -8,8 +8,8 @@ Object.defineProperty(exports, "MailgunProvider", {
|
|
|
8
8
|
return MailgunProvider;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
-
const _common = require("@nestjs/common");
|
|
12
11
|
const _constants = require("@flusys/nestjs-shared/constants");
|
|
12
|
+
const _common = require("@nestjs/common");
|
|
13
13
|
function _define_property(obj, key, value) {
|
|
14
14
|
if (key in obj) {
|
|
15
15
|
Object.defineProperty(obj, key, {
|
|
@@ -42,7 +42,10 @@ let MailgunProvider = class MailgunProvider {
|
|
|
42
42
|
} catch {
|
|
43
43
|
throw new _common.InternalServerErrorException({
|
|
44
44
|
message: 'Mailgun initialization failed. Install: npm install mailgun.js form-data',
|
|
45
|
-
messageKey: _constants.SYSTEM_MESSAGES.SDK_NOT_INSTALLED
|
|
45
|
+
messageKey: _constants.SYSTEM_MESSAGES.SDK_NOT_INSTALLED,
|
|
46
|
+
messageVariables: {
|
|
47
|
+
sdk: 'mailgun'
|
|
48
|
+
}
|
|
46
49
|
});
|
|
47
50
|
}
|
|
48
51
|
}
|
|
@@ -8,8 +8,8 @@ Object.defineProperty(exports, "SendGridProvider", {
|
|
|
8
8
|
return SendGridProvider;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
-
const _common = require("@nestjs/common");
|
|
12
11
|
const _constants = require("@flusys/nestjs-shared/constants");
|
|
12
|
+
const _common = require("@nestjs/common");
|
|
13
13
|
function _define_property(obj, key, value) {
|
|
14
14
|
if (key in obj) {
|
|
15
15
|
Object.defineProperty(obj, key, {
|
|
@@ -34,7 +34,10 @@ let SendGridProvider = class SendGridProvider {
|
|
|
34
34
|
} catch {
|
|
35
35
|
throw new _common.InternalServerErrorException({
|
|
36
36
|
message: 'SendGrid initialization failed. Install: npm install @sendgrid/mail',
|
|
37
|
-
messageKey: _constants.SYSTEM_MESSAGES.SDK_NOT_INSTALLED
|
|
37
|
+
messageKey: _constants.SYSTEM_MESSAGES.SDK_NOT_INSTALLED,
|
|
38
|
+
messageVariables: {
|
|
39
|
+
sdk: 'sendgrid'
|
|
40
|
+
}
|
|
38
41
|
});
|
|
39
42
|
}
|
|
40
43
|
}
|
|
@@ -118,16 +118,6 @@ let EmailProviderConfigService = class EmailProviderConfigService extends _class
|
|
|
118
118
|
}
|
|
119
119
|
});
|
|
120
120
|
}
|
|
121
|
-
async getConfigByProvider(provider, user) {
|
|
122
|
-
await this.ensureRepositoryInitialized();
|
|
123
|
-
const where = (0, _utils.buildCompanyWhereCondition)({
|
|
124
|
-
provider,
|
|
125
|
-
isActive: true
|
|
126
|
-
}, this.emailConfig.isCompanyFeatureEnabled(), user);
|
|
127
|
-
return this.repository.find({
|
|
128
|
-
where
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
121
|
constructor(cacheManager, utilsService, emailConfig, dataSourceProvider){
|
|
132
122
|
super('emailConfig', null, cacheManager, utilsService, EmailProviderConfigService.name, true, 'email'), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "emailConfig", void 0), _define_property(this, "dataSourceProvider", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.emailConfig = emailConfig, this.dataSourceProvider = dataSourceProvider;
|
|
133
123
|
}
|
|
@@ -54,7 +54,6 @@ const DEFAULT_SELECT_FIELDS = [
|
|
|
54
54
|
'schemaVersion',
|
|
55
55
|
'isActive',
|
|
56
56
|
'isHtml',
|
|
57
|
-
'metadata',
|
|
58
57
|
'createdAt',
|
|
59
58
|
'updatedAt'
|
|
60
59
|
];
|
|
@@ -114,18 +113,6 @@ let EmailTemplateService = class EmailTemplateService extends _classes.RequestSc
|
|
|
114
113
|
where
|
|
115
114
|
});
|
|
116
115
|
}
|
|
117
|
-
async getActiveTemplates(user) {
|
|
118
|
-
await this.ensureRepositoryInitialized();
|
|
119
|
-
const where = (0, _utils.buildCompanyWhereCondition)({
|
|
120
|
-
isActive: true
|
|
121
|
-
}, this.emailConfig.isCompanyFeatureEnabled(), user);
|
|
122
|
-
return this.repository.find({
|
|
123
|
-
where,
|
|
124
|
-
order: {
|
|
125
|
-
name: 'ASC'
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
116
|
// ─── Private Helpers ────────────────────────────────────────────────────────
|
|
130
117
|
async incrementSchemaVersionIfChanged(dto, entity) {
|
|
131
118
|
const updateDto = dto;
|
package/config/message-keys.d.ts
CHANGED
|
@@ -1,36 +1,10 @@
|
|
|
1
|
-
export declare const EMAIL_CONFIG_MESSAGES: {
|
|
2
|
-
readonly CREATE_SUCCESS: "email.config.create.success";
|
|
3
|
-
readonly CREATE_MANY_SUCCESS: "email.config.create.many.success";
|
|
4
|
-
readonly GET_SUCCESS: "email.config.get.success";
|
|
5
|
-
readonly GET_ALL_SUCCESS: "email.config.get.all.success";
|
|
6
|
-
readonly UPDATE_SUCCESS: "email.config.update.success";
|
|
7
|
-
readonly UPDATE_MANY_SUCCESS: "email.config.update.many.success";
|
|
8
|
-
readonly DELETE_SUCCESS: "email.config.delete.success";
|
|
9
|
-
readonly RESTORE_SUCCESS: "email.config.restore.success";
|
|
10
|
-
readonly NOT_FOUND: "email.config.not.found";
|
|
11
|
-
readonly ACTIVE_SUCCESS: "email.config.active.success";
|
|
12
|
-
readonly TEST_SUCCESS: "email.config.test.success";
|
|
13
|
-
readonly TEST_FAILED: "email.config.test.failed";
|
|
14
|
-
};
|
|
15
1
|
export declare const EMAIL_TEMPLATE_MESSAGES: {
|
|
16
|
-
readonly CREATE_SUCCESS: "email.template.create.success";
|
|
17
|
-
readonly CREATE_MANY_SUCCESS: "email.template.create.many.success";
|
|
18
2
|
readonly GET_SUCCESS: "email.template.get.success";
|
|
19
|
-
readonly GET_ALL_SUCCESS: "email.template.get.all.success";
|
|
20
|
-
readonly UPDATE_SUCCESS: "email.template.update.success";
|
|
21
|
-
readonly UPDATE_MANY_SUCCESS: "email.template.update.many.success";
|
|
22
|
-
readonly DELETE_SUCCESS: "email.template.delete.success";
|
|
23
|
-
readonly RESTORE_SUCCESS: "email.template.restore.success";
|
|
24
3
|
readonly NOT_FOUND: "email.template.not.found";
|
|
25
|
-
readonly PREVIEW_SUCCESS: "email.template.preview.success";
|
|
26
4
|
};
|
|
27
5
|
export declare const EMAIL_SEND_MESSAGES: {
|
|
28
6
|
readonly SUCCESS: "email.send.success";
|
|
29
7
|
readonly FAILED: "email.send.failed";
|
|
30
|
-
readonly QUEUED: "email.send.queued";
|
|
31
|
-
readonly TEMPLATE_SUCCESS: "email.send.template.success";
|
|
32
|
-
readonly BULK_SUCCESS: "email.send.bulk.success";
|
|
33
|
-
readonly TEST_SUCCESS: "email.send.test.success";
|
|
34
8
|
readonly CONFIG_NOT_FOUND: "email.send.config.not.found";
|
|
35
9
|
readonly CONFIG_INACTIVE: "email.send.config.inactive";
|
|
36
10
|
readonly CONFIG_DEFAULT_NOT_FOUND: "email.send.config.default.not.found";
|
|
@@ -38,45 +12,3 @@ export declare const EMAIL_SEND_MESSAGES: {
|
|
|
38
12
|
readonly TEMPLATE_INACTIVE: "email.send.template.inactive";
|
|
39
13
|
readonly TEMPLATE_ID_OR_SLUG_REQUIRED: "email.send.template.id.or.slug.required";
|
|
40
14
|
};
|
|
41
|
-
export declare const EMAIL_MODULE_MESSAGES: {
|
|
42
|
-
readonly EMAIL_CONFIG: {
|
|
43
|
-
readonly CREATE_SUCCESS: "email.config.create.success";
|
|
44
|
-
readonly CREATE_MANY_SUCCESS: "email.config.create.many.success";
|
|
45
|
-
readonly GET_SUCCESS: "email.config.get.success";
|
|
46
|
-
readonly GET_ALL_SUCCESS: "email.config.get.all.success";
|
|
47
|
-
readonly UPDATE_SUCCESS: "email.config.update.success";
|
|
48
|
-
readonly UPDATE_MANY_SUCCESS: "email.config.update.many.success";
|
|
49
|
-
readonly DELETE_SUCCESS: "email.config.delete.success";
|
|
50
|
-
readonly RESTORE_SUCCESS: "email.config.restore.success";
|
|
51
|
-
readonly NOT_FOUND: "email.config.not.found";
|
|
52
|
-
readonly ACTIVE_SUCCESS: "email.config.active.success";
|
|
53
|
-
readonly TEST_SUCCESS: "email.config.test.success";
|
|
54
|
-
readonly TEST_FAILED: "email.config.test.failed";
|
|
55
|
-
};
|
|
56
|
-
readonly EMAIL_TEMPLATE: {
|
|
57
|
-
readonly CREATE_SUCCESS: "email.template.create.success";
|
|
58
|
-
readonly CREATE_MANY_SUCCESS: "email.template.create.many.success";
|
|
59
|
-
readonly GET_SUCCESS: "email.template.get.success";
|
|
60
|
-
readonly GET_ALL_SUCCESS: "email.template.get.all.success";
|
|
61
|
-
readonly UPDATE_SUCCESS: "email.template.update.success";
|
|
62
|
-
readonly UPDATE_MANY_SUCCESS: "email.template.update.many.success";
|
|
63
|
-
readonly DELETE_SUCCESS: "email.template.delete.success";
|
|
64
|
-
readonly RESTORE_SUCCESS: "email.template.restore.success";
|
|
65
|
-
readonly NOT_FOUND: "email.template.not.found";
|
|
66
|
-
readonly PREVIEW_SUCCESS: "email.template.preview.success";
|
|
67
|
-
};
|
|
68
|
-
readonly EMAIL_SEND: {
|
|
69
|
-
readonly SUCCESS: "email.send.success";
|
|
70
|
-
readonly FAILED: "email.send.failed";
|
|
71
|
-
readonly QUEUED: "email.send.queued";
|
|
72
|
-
readonly TEMPLATE_SUCCESS: "email.send.template.success";
|
|
73
|
-
readonly BULK_SUCCESS: "email.send.bulk.success";
|
|
74
|
-
readonly TEST_SUCCESS: "email.send.test.success";
|
|
75
|
-
readonly CONFIG_NOT_FOUND: "email.send.config.not.found";
|
|
76
|
-
readonly CONFIG_INACTIVE: "email.send.config.inactive";
|
|
77
|
-
readonly CONFIG_DEFAULT_NOT_FOUND: "email.send.config.default.not.found";
|
|
78
|
-
readonly TEMPLATE_NOT_FOUND: "email.send.template.not.found";
|
|
79
|
-
readonly TEMPLATE_INACTIVE: "email.send.template.inactive";
|
|
80
|
-
readonly TEMPLATE_ID_OR_SLUG_REQUIRED: "email.send.template.id.or.slug.required";
|
|
81
|
-
};
|
|
82
|
-
};
|
|
@@ -9,7 +9,6 @@ export declare class CreateEmailTemplateDto {
|
|
|
9
9
|
textContent?: string;
|
|
10
10
|
isActive?: boolean;
|
|
11
11
|
isHtml?: boolean;
|
|
12
|
-
metadata?: Record<string, unknown>;
|
|
13
12
|
}
|
|
14
13
|
declare const UpdateEmailTemplateDto_base: import("@nestjs/common").Type<Partial<CreateEmailTemplateDto>>;
|
|
15
14
|
export declare class UpdateEmailTemplateDto extends UpdateEmailTemplateDto_base {
|
|
@@ -26,6 +25,5 @@ export declare class EmailTemplateResponseDto extends IdentityResponseDto {
|
|
|
26
25
|
schemaVersion: number;
|
|
27
26
|
isActive: boolean;
|
|
28
27
|
isHtml: boolean;
|
|
29
|
-
metadata: Record<string, unknown> | null;
|
|
30
28
|
}
|
|
31
29
|
export {};
|
|
@@ -1,37 +1,11 @@
|
|
|
1
1
|
// ==================== EMAIL MODULE MESSAGE KEYS ====================
|
|
2
|
-
export const EMAIL_CONFIG_MESSAGES = {
|
|
3
|
-
CREATE_SUCCESS: 'email.config.create.success',
|
|
4
|
-
CREATE_MANY_SUCCESS: 'email.config.create.many.success',
|
|
5
|
-
GET_SUCCESS: 'email.config.get.success',
|
|
6
|
-
GET_ALL_SUCCESS: 'email.config.get.all.success',
|
|
7
|
-
UPDATE_SUCCESS: 'email.config.update.success',
|
|
8
|
-
UPDATE_MANY_SUCCESS: 'email.config.update.many.success',
|
|
9
|
-
DELETE_SUCCESS: 'email.config.delete.success',
|
|
10
|
-
RESTORE_SUCCESS: 'email.config.restore.success',
|
|
11
|
-
NOT_FOUND: 'email.config.not.found',
|
|
12
|
-
ACTIVE_SUCCESS: 'email.config.active.success',
|
|
13
|
-
TEST_SUCCESS: 'email.config.test.success',
|
|
14
|
-
TEST_FAILED: 'email.config.test.failed'
|
|
15
|
-
};
|
|
16
2
|
export const EMAIL_TEMPLATE_MESSAGES = {
|
|
17
|
-
CREATE_SUCCESS: 'email.template.create.success',
|
|
18
|
-
CREATE_MANY_SUCCESS: 'email.template.create.many.success',
|
|
19
3
|
GET_SUCCESS: 'email.template.get.success',
|
|
20
|
-
|
|
21
|
-
UPDATE_SUCCESS: 'email.template.update.success',
|
|
22
|
-
UPDATE_MANY_SUCCESS: 'email.template.update.many.success',
|
|
23
|
-
DELETE_SUCCESS: 'email.template.delete.success',
|
|
24
|
-
RESTORE_SUCCESS: 'email.template.restore.success',
|
|
25
|
-
NOT_FOUND: 'email.template.not.found',
|
|
26
|
-
PREVIEW_SUCCESS: 'email.template.preview.success'
|
|
4
|
+
NOT_FOUND: 'email.template.not.found'
|
|
27
5
|
};
|
|
28
6
|
export const EMAIL_SEND_MESSAGES = {
|
|
29
7
|
SUCCESS: 'email.send.success',
|
|
30
8
|
FAILED: 'email.send.failed',
|
|
31
|
-
QUEUED: 'email.send.queued',
|
|
32
|
-
TEMPLATE_SUCCESS: 'email.send.template.success',
|
|
33
|
-
BULK_SUCCESS: 'email.send.bulk.success',
|
|
34
|
-
TEST_SUCCESS: 'email.send.test.success',
|
|
35
9
|
CONFIG_NOT_FOUND: 'email.send.config.not.found',
|
|
36
10
|
CONFIG_INACTIVE: 'email.send.config.inactive',
|
|
37
11
|
CONFIG_DEFAULT_NOT_FOUND: 'email.send.config.default.not.found',
|
|
@@ -39,9 +13,3 @@ export const EMAIL_SEND_MESSAGES = {
|
|
|
39
13
|
TEMPLATE_INACTIVE: 'email.send.template.inactive',
|
|
40
14
|
TEMPLATE_ID_OR_SLUG_REQUIRED: 'email.send.template.id.or.slug.required'
|
|
41
15
|
};
|
|
42
|
-
// Aggregated export for backward compatibility
|
|
43
|
-
export const EMAIL_MODULE_MESSAGES = {
|
|
44
|
-
EMAIL_CONFIG: EMAIL_CONFIG_MESSAGES,
|
|
45
|
-
EMAIL_TEMPLATE: EMAIL_TEMPLATE_MESSAGES,
|
|
46
|
-
EMAIL_SEND: EMAIL_SEND_MESSAGES
|
|
47
|
-
};
|
|
@@ -26,16 +26,16 @@ function _ts_param(paramIndex, decorator) {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
import { createApiController, EMAIL_TEMPLATE_PERMISSIONS } from '@flusys/nestjs-shared/classes';
|
|
29
|
-
import { EMAIL_TEMPLATE_MESSAGES } from '../config';
|
|
30
29
|
import { CurrentUser, RequirePermission } from '@flusys/nestjs-shared/decorators';
|
|
31
30
|
import { JwtAuthGuard } from '@flusys/nestjs-shared/guards';
|
|
32
31
|
import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
|
|
33
|
-
import { Body, Controller, Inject, Post, UseGuards } from '@nestjs/common';
|
|
32
|
+
import { Body, Controller, Inject, NotFoundException, Post, UseGuards } from '@nestjs/common';
|
|
34
33
|
import { ApiBearerAuth, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
|
34
|
+
import { EMAIL_TEMPLATE_MESSAGES } from '../config';
|
|
35
35
|
import { CreateEmailTemplateDto, EmailTemplateResponseDto, UpdateEmailTemplateDto } from '../dtos';
|
|
36
36
|
import { EmailTemplateService } from '../services';
|
|
37
37
|
export class EmailTemplateController extends createApiController(CreateEmailTemplateDto, UpdateEmailTemplateDto, EmailTemplateResponseDto, {
|
|
38
|
-
entityName: '
|
|
38
|
+
entityName: 'email.template',
|
|
39
39
|
security: {
|
|
40
40
|
insert: {
|
|
41
41
|
level: 'permission',
|
|
@@ -83,11 +83,17 @@ export class EmailTemplateController extends createApiController(CreateEmailTemp
|
|
|
83
83
|
}) {
|
|
84
84
|
async getBySlug(body, user) {
|
|
85
85
|
const data = await this.emailTemplateService.findBySlug(body.slug, user);
|
|
86
|
+
if (!data) {
|
|
87
|
+
throw new NotFoundException({
|
|
88
|
+
message: 'Email template not found',
|
|
89
|
+
messageKey: EMAIL_TEMPLATE_MESSAGES.NOT_FOUND
|
|
90
|
+
});
|
|
91
|
+
}
|
|
86
92
|
return {
|
|
87
93
|
success: true,
|
|
88
94
|
message: 'Template retrieved',
|
|
89
95
|
messageKey: EMAIL_TEMPLATE_MESSAGES.GET_SUCCESS,
|
|
90
|
-
data
|
|
96
|
+
data
|
|
91
97
|
};
|
|
92
98
|
}
|
|
93
99
|
constructor(emailTemplateService){
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
]
|
|
13
13
|
}
|
|
14
14
|
];
|
|
15
|
-
function buildDescription(enableCompanyFeature) {
|
|
15
|
+
function buildDescription(enableCompanyFeature, isMultiTenant) {
|
|
16
|
+
const multiTenantNote = isMultiTenant ? `\n> **Multi-Tenant Mode**: Include \`x-tenant-id\` header to target a specific tenant database.\n` : '';
|
|
16
17
|
const companyConfigs = enableCompanyFeature ? '\n- **Company-level email configs**' : '';
|
|
17
18
|
const companyIsolation = enableCompanyFeature ? '\n- **Company isolation**' : '';
|
|
18
19
|
const multiTenantSection = enableCompanyFeature ? `
|
|
@@ -25,7 +26,7 @@ All queries automatically filter by current user's company context.
|
|
|
25
26
|
` : '';
|
|
26
27
|
return `
|
|
27
28
|
# Email Management API
|
|
28
|
-
|
|
29
|
+
${multiTenantNote}
|
|
29
30
|
Complete email management system${enableCompanyFeature ? ' with multi-tenant and company support' : ''}.
|
|
30
31
|
|
|
31
32
|
## Features
|
|
@@ -95,9 +96,10 @@ All email endpoints are prefixed with \`/email\`:
|
|
|
95
96
|
* Use this with setupSwaggerDocs() from @flusys/nestjs-core
|
|
96
97
|
*/ export function emailSwaggerConfig(bootstrapConfig) {
|
|
97
98
|
const enableCompanyFeature = bootstrapConfig?.enableCompanyFeature ?? true;
|
|
99
|
+
const isMultiTenant = bootstrapConfig?.databaseMode === 'multi-tenant';
|
|
98
100
|
return {
|
|
99
101
|
title: 'Email API',
|
|
100
|
-
description: buildDescription(enableCompanyFeature),
|
|
102
|
+
description: buildDescription(enableCompanyFeature, isMultiTenant),
|
|
101
103
|
version: '1.0',
|
|
102
104
|
path: 'api/docs/email',
|
|
103
105
|
bearerAuth: true,
|
|
@@ -34,7 +34,6 @@ export class CreateEmailTemplateDto {
|
|
|
34
34
|
_define_property(this, "textContent", void 0);
|
|
35
35
|
_define_property(this, "isActive", void 0);
|
|
36
36
|
_define_property(this, "isHtml", void 0);
|
|
37
|
-
_define_property(this, "metadata", void 0);
|
|
38
37
|
}
|
|
39
38
|
}
|
|
40
39
|
_ts_decorate([
|
|
@@ -118,18 +117,6 @@ _ts_decorate([
|
|
|
118
117
|
IsOptional(),
|
|
119
118
|
_ts_metadata("design:type", Boolean)
|
|
120
119
|
], CreateEmailTemplateDto.prototype, "isHtml", void 0);
|
|
121
|
-
_ts_decorate([
|
|
122
|
-
ApiPropertyOptional({
|
|
123
|
-
type: 'object',
|
|
124
|
-
additionalProperties: true,
|
|
125
|
-
example: {
|
|
126
|
-
category: 'onboarding'
|
|
127
|
-
}
|
|
128
|
-
}),
|
|
129
|
-
IsObject(),
|
|
130
|
-
IsOptional(),
|
|
131
|
-
_ts_metadata("design:type", typeof Record === "undefined" ? Object : Record)
|
|
132
|
-
], CreateEmailTemplateDto.prototype, "metadata", void 0);
|
|
133
120
|
export class UpdateEmailTemplateDto extends PartialType(CreateEmailTemplateDto) {
|
|
134
121
|
constructor(...args){
|
|
135
122
|
super(...args), _define_property(this, "id", void 0);
|
|
@@ -145,7 +132,7 @@ _ts_decorate([
|
|
|
145
132
|
], UpdateEmailTemplateDto.prototype, "id", void 0);
|
|
146
133
|
export class EmailTemplateResponseDto extends IdentityResponseDto {
|
|
147
134
|
constructor(...args){
|
|
148
|
-
super(...args), _define_property(this, "name", void 0), _define_property(this, "slug", void 0), _define_property(this, "description", void 0), _define_property(this, "subject", void 0), _define_property(this, "schema", void 0), _define_property(this, "htmlContent", void 0), _define_property(this, "textContent", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "isActive", void 0), _define_property(this, "isHtml", void 0)
|
|
135
|
+
super(...args), _define_property(this, "name", void 0), _define_property(this, "slug", void 0), _define_property(this, "description", void 0), _define_property(this, "subject", void 0), _define_property(this, "schema", void 0), _define_property(this, "htmlContent", void 0), _define_property(this, "textContent", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "isActive", void 0), _define_property(this, "isHtml", void 0);
|
|
149
136
|
}
|
|
150
137
|
}
|
|
151
138
|
_ts_decorate([
|
|
@@ -191,10 +178,3 @@ _ts_decorate([
|
|
|
191
178
|
ApiProperty(),
|
|
192
179
|
_ts_metadata("design:type", Boolean)
|
|
193
180
|
], EmailTemplateResponseDto.prototype, "isHtml", void 0);
|
|
194
|
-
_ts_decorate([
|
|
195
|
-
ApiPropertyOptional({
|
|
196
|
-
type: 'object',
|
|
197
|
-
additionalProperties: true
|
|
198
|
-
}),
|
|
199
|
-
_ts_metadata("design:type", Object)
|
|
200
|
-
], EmailTemplateResponseDto.prototype, "metadata", void 0);
|
|
@@ -20,6 +20,7 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
20
20
|
function _ts_metadata(k, v) {
|
|
21
21
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
22
22
|
}
|
|
23
|
+
import { getJsonColumnType } from '@flusys/nestjs-shared';
|
|
23
24
|
import { Identity } from '@flusys/nestjs-shared/entities';
|
|
24
25
|
import { Column, Entity, Index } from 'typeorm';
|
|
25
26
|
export class EmailConfig extends Identity {
|
|
@@ -45,7 +46,7 @@ _ts_decorate([
|
|
|
45
46
|
], EmailConfig.prototype, "provider", void 0);
|
|
46
47
|
_ts_decorate([
|
|
47
48
|
Column({
|
|
48
|
-
type:
|
|
49
|
+
type: getJsonColumnType(),
|
|
49
50
|
nullable: false
|
|
50
51
|
}),
|
|
51
52
|
_ts_metadata("design:type", typeof Record === "undefined" ? Object : Record)
|
|
@@ -20,11 +20,12 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
20
20
|
function _ts_metadata(k, v) {
|
|
21
21
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
22
22
|
}
|
|
23
|
+
import { getJsonColumnType } from '@flusys/nestjs-shared';
|
|
23
24
|
import { Identity } from '@flusys/nestjs-shared/entities';
|
|
24
25
|
import { Column, Entity, Index } from 'typeorm';
|
|
25
26
|
export class EmailTemplate extends Identity {
|
|
26
27
|
constructor(...args){
|
|
27
|
-
super(...args), _define_property(this, "name", void 0), _define_property(this, "slug", void 0), _define_property(this, "description", void 0), _define_property(this, "subject", void 0), _define_property(this, "schema", void 0), _define_property(this, "htmlContent", void 0), _define_property(this, "textContent", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "isActive", void 0), _define_property(this, "isHtml", void 0)
|
|
28
|
+
super(...args), _define_property(this, "name", void 0), _define_property(this, "slug", void 0), _define_property(this, "description", void 0), _define_property(this, "subject", void 0), _define_property(this, "schema", void 0), _define_property(this, "htmlContent", void 0), _define_property(this, "textContent", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "isActive", void 0), _define_property(this, "isHtml", void 0);
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
_ts_decorate([
|
|
@@ -61,7 +62,7 @@ _ts_decorate([
|
|
|
61
62
|
], EmailTemplate.prototype, "subject", void 0);
|
|
62
63
|
_ts_decorate([
|
|
63
64
|
Column({
|
|
64
|
-
type:
|
|
65
|
+
type: getJsonColumnType(),
|
|
65
66
|
nullable: false
|
|
66
67
|
}),
|
|
67
68
|
_ts_metadata("design:type", typeof Record === "undefined" ? Object : Record)
|
|
@@ -107,12 +108,6 @@ _ts_decorate([
|
|
|
107
108
|
}),
|
|
108
109
|
_ts_metadata("design:type", Boolean)
|
|
109
110
|
], EmailTemplate.prototype, "isHtml", void 0);
|
|
110
|
-
_ts_decorate([
|
|
111
|
-
Column('simple-json', {
|
|
112
|
-
nullable: true
|
|
113
|
-
}),
|
|
114
|
-
_ts_metadata("design:type", Object)
|
|
115
|
-
], EmailTemplate.prototype, "metadata", void 0);
|
|
116
111
|
EmailTemplate = _ts_decorate([
|
|
117
112
|
Entity({
|
|
118
113
|
name: 'email_template'
|
|
@@ -21,9 +21,9 @@ function _ts_metadata(k, v) {
|
|
|
21
21
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
22
22
|
}
|
|
23
23
|
import { LogAction, SYSTEM_MESSAGES } from '@flusys/nestjs-shared';
|
|
24
|
-
import { EMAIL_SEND_MESSAGES } from '../config';
|
|
25
24
|
import { Injectable, InternalServerErrorException, NotFoundException } from '@nestjs/common';
|
|
26
25
|
import { createHash } from 'crypto';
|
|
26
|
+
import { EMAIL_SEND_MESSAGES } from '../config';
|
|
27
27
|
import { IEmailProviderConfig } from '../interfaces';
|
|
28
28
|
import { EmailProviderRegistry } from './email-provider.registry';
|
|
29
29
|
export class EmailFactoryService {
|
|
@@ -37,7 +37,7 @@ export class EmailFactoryService {
|
|
|
37
37
|
throw new NotFoundException({
|
|
38
38
|
message: `Email provider '${config.provider}' is not registered`,
|
|
39
39
|
messageKey: EMAIL_SEND_MESSAGES.CONFIG_NOT_FOUND,
|
|
40
|
-
|
|
40
|
+
messageVariables: {
|
|
41
41
|
provider: config.provider,
|
|
42
42
|
available: EmailProviderRegistry.getAll().join(', ')
|
|
43
43
|
}
|
|
@@ -50,11 +50,11 @@ export class EmailFactoryService {
|
|
|
50
50
|
return instance;
|
|
51
51
|
} catch (error) {
|
|
52
52
|
throw new InternalServerErrorException({
|
|
53
|
-
message: `
|
|
53
|
+
message: `Email provider '${config.provider}' not initialized successfully: ${this.extractErrorMessage(error)}`,
|
|
54
54
|
messageKey: SYSTEM_MESSAGES.SERVICE_NOT_AVAILABLE,
|
|
55
|
-
|
|
55
|
+
messageVariables: {
|
|
56
56
|
provider: config.provider,
|
|
57
|
-
|
|
57
|
+
available: EmailProviderRegistry.getAll().join(', ')
|
|
58
58
|
}
|
|
59
59
|
});
|
|
60
60
|
}
|
|
@@ -11,8 +11,8 @@ function _define_property(obj, key, value) {
|
|
|
11
11
|
}
|
|
12
12
|
return obj;
|
|
13
13
|
}
|
|
14
|
-
import { InternalServerErrorException } from '@nestjs/common';
|
|
15
14
|
import { SYSTEM_MESSAGES } from '@flusys/nestjs-shared/constants';
|
|
15
|
+
import { InternalServerErrorException } from '@nestjs/common';
|
|
16
16
|
const MAILGUN_API_URL = 'https://api.mailgun.net';
|
|
17
17
|
const MAILGUN_EU_API_URL = 'https://api.eu.mailgun.net';
|
|
18
18
|
export class MailgunProvider {
|
|
@@ -32,7 +32,10 @@ export class MailgunProvider {
|
|
|
32
32
|
} catch {
|
|
33
33
|
throw new InternalServerErrorException({
|
|
34
34
|
message: 'Mailgun initialization failed. Install: npm install mailgun.js form-data',
|
|
35
|
-
messageKey: SYSTEM_MESSAGES.SDK_NOT_INSTALLED
|
|
35
|
+
messageKey: SYSTEM_MESSAGES.SDK_NOT_INSTALLED,
|
|
36
|
+
messageVariables: {
|
|
37
|
+
sdk: 'mailgun'
|
|
38
|
+
}
|
|
36
39
|
});
|
|
37
40
|
}
|
|
38
41
|
}
|