@ackplus/nest-dynamic-templates 1.1.1 → 1.1.2
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/package.json +2 -2
- package/src/{index.ts → index.d.ts} +2 -14
- package/src/index.d.ts.map +1 -0
- package/src/lib/constant.d.ts +3 -0
- package/src/lib/constant.d.ts.map +1 -0
- package/src/lib/dto/create-template-layout.dto.d.ts +16 -0
- package/src/lib/dto/create-template-layout.dto.d.ts.map +1 -0
- package/src/lib/dto/create-template.dto.d.ts +18 -0
- package/src/lib/dto/create-template.dto.d.ts.map +1 -0
- package/src/lib/dto/render-content-template-layout.dto.d.ts +8 -0
- package/src/lib/dto/render-content-template-layout.dto.d.ts.map +1 -0
- package/src/lib/dto/render-content-template.dto.d.ts +9 -0
- package/src/lib/dto/render-content-template.dto.d.ts.map +1 -0
- package/src/lib/dto/render-template-layout.dto.d.ts +11 -0
- package/src/lib/dto/render-template-layout.dto.d.ts.map +1 -0
- package/src/lib/dto/render-template.dto.d.ts +15 -0
- package/src/lib/dto/render-template.dto.d.ts.map +1 -0
- package/src/lib/dto/template-filter.dto.d.ts +9 -0
- package/src/lib/dto/template-filter.dto.d.ts.map +1 -0
- package/src/lib/dto/template-layout-filter.dto.d.ts +8 -0
- package/src/lib/dto/template-layout-filter.dto.d.ts.map +1 -0
- package/src/lib/engines/language/html.engine.d.ts +10 -0
- package/src/lib/engines/language/html.engine.d.ts.map +1 -0
- package/src/lib/engines/language/{index.ts → index.d.ts} +1 -0
- package/src/lib/engines/language/index.d.ts.map +1 -0
- package/src/lib/engines/language/markdown.engine.d.ts +10 -0
- package/src/lib/engines/language/markdown.engine.d.ts.map +1 -0
- package/src/lib/engines/language/mjml.engine.d.ts +10 -0
- package/src/lib/engines/language/mjml.engine.d.ts.map +1 -0
- package/src/lib/engines/language/text.engine.d.ts +8 -0
- package/src/lib/engines/language/text.engine.d.ts.map +1 -0
- package/src/lib/engines/{language-engine.ts → language-engine.d.ts} +2 -7
- package/src/lib/engines/language-engine.d.ts.map +1 -0
- package/src/lib/engines/template/ejs.engine.d.ts +11 -0
- package/src/lib/engines/template/ejs.engine.d.ts.map +1 -0
- package/src/lib/engines/template/handlebars.engine.d.ts +11 -0
- package/src/lib/engines/template/handlebars.engine.d.ts.map +1 -0
- package/src/lib/engines/template/{index.ts → index.d.ts} +1 -0
- package/src/lib/engines/template/index.d.ts.map +1 -0
- package/src/lib/engines/template/nunjucks.engine.d.ts +17 -0
- package/src/lib/engines/template/nunjucks.engine.d.ts.map +1 -0
- package/src/lib/engines/template/pug.engine.d.ts +13 -0
- package/src/lib/engines/template/pug.engine.d.ts.map +1 -0
- package/src/lib/engines/{template-engine.ts → template-engine.d.ts} +2 -6
- package/src/lib/engines/template-engine.d.ts.map +1 -0
- package/src/lib/entities/template-layout.entity.d.ts +21 -0
- package/src/lib/entities/template-layout.entity.d.ts.map +1 -0
- package/src/lib/entities/template.entity.d.ts +22 -0
- package/src/lib/entities/template.entity.d.ts.map +1 -0
- package/src/lib/errors/template.errors.d.ts +20 -0
- package/src/lib/errors/template.errors.d.ts.map +1 -0
- package/src/lib/interfaces/{module-config.interface.ts → module-config.interface.d.ts} +2 -10
- package/src/lib/interfaces/module-config.interface.d.ts.map +1 -0
- package/src/lib/interfaces/template.types.d.ts +23 -0
- package/src/lib/interfaces/template.types.d.ts.map +1 -0
- package/src/lib/nest-dynamic-templates.module.d.ts +11 -0
- package/src/lib/nest-dynamic-templates.module.d.ts.map +1 -0
- package/src/lib/services/template-config.service.d.ts +55 -0
- package/src/lib/services/template-config.service.d.ts.map +1 -0
- package/src/lib/services/template-engine.registry.d.ts +22 -0
- package/src/lib/services/template-engine.registry.d.ts.map +1 -0
- package/src/lib/services/template-layout.service.d.ts +37 -0
- package/src/lib/services/template-layout.service.d.ts.map +1 -0
- package/src/lib/services/template.service.d.ts +39 -0
- package/src/lib/services/template.service.d.ts.map +1 -0
- package/src/test/helpers.d.ts +5 -0
- package/src/test/helpers.d.ts.map +1 -0
- package/src/test/test-database.config.d.ts +5 -0
- package/src/test/test-database.config.d.ts.map +1 -0
- package/src/test/test.setup.d.ts +4 -0
- package/src/test/test.setup.d.ts.map +1 -0
- package/eslint.config.mjs +0 -22
- package/jest.config.ts +0 -10
- package/project.json +0 -38
- package/src/lib/constant.ts +0 -2
- package/src/lib/dto/create-template-layout.dto.ts +0 -65
- package/src/lib/dto/create-template.dto.ts +0 -80
- package/src/lib/dto/render-content-template-layout.dto.ts +0 -32
- package/src/lib/dto/render-content-template.dto.ts +0 -37
- package/src/lib/dto/render-template-layout.dto.ts +0 -55
- package/src/lib/dto/render-template.dto.ts +0 -74
- package/src/lib/dto/template-filter.dto.ts +0 -52
- package/src/lib/dto/template-layout-filter.dto.ts +0 -51
- package/src/lib/engines/language/html.engine.ts +0 -49
- package/src/lib/engines/language/markdown.engine.ts +0 -37
- package/src/lib/engines/language/mjml.engine.ts +0 -44
- package/src/lib/engines/language/text.engine.ts +0 -15
- package/src/lib/engines/template/ejs.engine.ts +0 -33
- package/src/lib/engines/template/handlebars.engine.ts +0 -35
- package/src/lib/engines/template/nunjucks.engine.ts +0 -70
- package/src/lib/engines/template/pug.engine.ts +0 -43
- package/src/lib/entities/template-layout.entity.ts +0 -99
- package/src/lib/entities/template.entity.ts +0 -105
- package/src/lib/errors/template.errors.ts +0 -73
- package/src/lib/interfaces/template.types.ts +0 -25
- package/src/lib/nest-dynamic-templates.module.ts +0 -143
- package/src/lib/services/template-config.service.ts +0 -112
- package/src/lib/services/template-engine.registry.ts +0 -109
- package/src/lib/services/template-layout.service.ts +0 -407
- package/src/lib/services/template.service.ts +0 -476
- package/src/test/helpers.ts +0 -31
- package/src/test/nunjucks.service.spec.ts +0 -157
- package/src/test/pug.service.spec-temp +0 -254
- package/src/test/template-layout.service.spec.ts +0 -422
- package/src/test/template.service.spec.ts +0 -862
- package/src/test/test-database.config.ts +0 -24
- package/src/test/test-database.d.ts +0 -6
- package/src/test/test.setup.ts +0 -34
- package/src/types/ioredis.d.ts +0 -6
- package/src/types/mjml.d.ts +0 -5
- package/tsconfig.json +0 -17
- package/tsconfig.lib.json +0 -14
- package/tsconfig.spec.json +0 -15
|
@@ -1,407 +0,0 @@
|
|
|
1
|
-
import { BadRequestException, ConflictException, ForbiddenException, Injectable, NotFoundException } from '@nestjs/common';
|
|
2
|
-
import { InjectRepository } from '@nestjs/typeorm';
|
|
3
|
-
import { Equal, In, IsNull, Not, Repository } from 'typeorm';
|
|
4
|
-
import { NestDynamicTemplateLayout } from '../entities/template-layout.entity';
|
|
5
|
-
import { TemplateEngineEnum, TemplateLanguageEnum, TemplateTypeEnum } from '../interfaces/template.types';
|
|
6
|
-
import { TemplateLayoutFilterDto } from '../dto/template-layout-filter.dto';
|
|
7
|
-
import { TemplateEngineRegistryService } from './template-engine.registry';
|
|
8
|
-
import { RenderTemplateLayoutDto, RenderTemplateLayoutOutput } from '../dto/render-template-layout.dto';
|
|
9
|
-
import { CreateTemplateLayoutDto } from '../dto/create-template-layout.dto';
|
|
10
|
-
import { RenderContentTemplateLayoutDto } from '../dto/render-content-template-layout.dto';
|
|
11
|
-
import {
|
|
12
|
-
TemplateRenderError,
|
|
13
|
-
TemplateEngineError,
|
|
14
|
-
TemplateLanguageError,
|
|
15
|
-
} from '../errors/template.errors';
|
|
16
|
-
|
|
17
|
-
@Injectable()
|
|
18
|
-
export class TemplateLayoutService {
|
|
19
|
-
constructor(
|
|
20
|
-
@InjectRepository(NestDynamicTemplateLayout)
|
|
21
|
-
private readonly layoutRepository: Repository<NestDynamicTemplateLayout>,
|
|
22
|
-
private readonly engineRegistry: TemplateEngineRegistryService
|
|
23
|
-
) { }
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
async render(renderDto: RenderTemplateLayoutDto): Promise<RenderTemplateLayoutOutput> {
|
|
27
|
-
const { name, scope, scopeId, locale, context } = renderDto;
|
|
28
|
-
|
|
29
|
-
try {
|
|
30
|
-
// Find template with fallback
|
|
31
|
-
const templateLayout = await this.findTemplateLayout(name, scope, scopeId, locale);
|
|
32
|
-
if (!templateLayout) {
|
|
33
|
-
throw new NotFoundException(`Template layout not found: ${name} in scope ${scope || 'system'}`);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Validate content exists
|
|
37
|
-
if (!templateLayout.content) {
|
|
38
|
-
throw new BadRequestException(`Template layout '${name}' has no content to render`);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
let content = templateLayout.content;
|
|
42
|
-
|
|
43
|
-
// Render content by template engine
|
|
44
|
-
if (templateLayout.engine) {
|
|
45
|
-
try {
|
|
46
|
-
content = await this.renderEngine(templateLayout.engine, content, context || {});
|
|
47
|
-
} catch (error) {
|
|
48
|
-
throw new TemplateEngineError(templateLayout.engine, error as Error);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// If template has language format, process with language engine
|
|
53
|
-
if (templateLayout.language) {
|
|
54
|
-
try {
|
|
55
|
-
content = await this.renderLanguage(templateLayout.language, content, context || {});
|
|
56
|
-
} catch (error) {
|
|
57
|
-
throw new TemplateLanguageError(templateLayout.language, error as Error);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return {
|
|
62
|
-
content
|
|
63
|
-
};
|
|
64
|
-
} catch (error) {
|
|
65
|
-
// Re-throw known template errors
|
|
66
|
-
if (error instanceof TemplateEngineError ||
|
|
67
|
-
error instanceof TemplateLanguageError ||
|
|
68
|
-
error instanceof NotFoundException ||
|
|
69
|
-
error instanceof BadRequestException) {
|
|
70
|
-
throw error;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Wrap unknown errors
|
|
74
|
-
throw new TemplateRenderError('template layout rendering', error as Error, name);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async renderContent(input: RenderContentTemplateLayoutDto): Promise<string> {
|
|
79
|
-
const { content, language, engine, context } = input;
|
|
80
|
-
|
|
81
|
-
try {
|
|
82
|
-
if (!content) {
|
|
83
|
-
throw new BadRequestException('Content is required for template layout rendering');
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
let renderContent = content;
|
|
87
|
-
|
|
88
|
-
// Render content by template engine
|
|
89
|
-
if (engine) {
|
|
90
|
-
try {
|
|
91
|
-
renderContent = await this.renderEngine(engine, content, context || {});
|
|
92
|
-
} catch (error) {
|
|
93
|
-
throw new TemplateEngineError(engine, error as Error);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Render content by language engine
|
|
98
|
-
if (language) {
|
|
99
|
-
try {
|
|
100
|
-
renderContent = await this.renderLanguage(language, renderContent, context || {});
|
|
101
|
-
} catch (error) {
|
|
102
|
-
throw new TemplateLanguageError(language, error as Error);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return renderContent;
|
|
107
|
-
} catch (error) {
|
|
108
|
-
// Re-throw known template errors
|
|
109
|
-
if (error instanceof TemplateEngineError ||
|
|
110
|
-
error instanceof TemplateLanguageError ||
|
|
111
|
-
error instanceof BadRequestException) {
|
|
112
|
-
throw error;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Wrap unknown errors
|
|
116
|
-
throw new TemplateRenderError('template layout content rendering', error as Error);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
async renderLanguage(language: TemplateLanguageEnum, content: string, context: Record<string, any>): Promise<string> {
|
|
121
|
-
try {
|
|
122
|
-
if (!content) {
|
|
123
|
-
throw new BadRequestException('Content is required for language rendering');
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const languageEngine = this.engineRegistry.getLanguageEngine(language);
|
|
127
|
-
if (!languageEngine) {
|
|
128
|
-
throw new BadRequestException(`Language engine not found for: ${language}`);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return await languageEngine.render(content, context);
|
|
132
|
-
} catch (error) {
|
|
133
|
-
if (error instanceof BadRequestException) {
|
|
134
|
-
throw error;
|
|
135
|
-
}
|
|
136
|
-
throw new TemplateLanguageError(language, error as Error);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
async renderEngine(engine: TemplateEngineEnum, content: string, context: Record<string, any>): Promise<string> {
|
|
141
|
-
try {
|
|
142
|
-
if (!content) {
|
|
143
|
-
throw new BadRequestException('Content is required for engine rendering');
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const templateEngine = this.engineRegistry.getTemplateEngine(engine);
|
|
147
|
-
if (!templateEngine) {
|
|
148
|
-
throw new BadRequestException(`Template engine not found for: ${engine}`);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return await templateEngine.render(content, context);
|
|
152
|
-
} catch (error) {
|
|
153
|
-
if (error instanceof BadRequestException) {
|
|
154
|
-
throw error;
|
|
155
|
-
}
|
|
156
|
-
throw new TemplateEngineError(engine, error as Error);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Get all templates, with scoped templates taking precedence over system templates
|
|
162
|
-
*/
|
|
163
|
-
async getTemplateLayouts(filter: TemplateLayoutFilterDto = {}): Promise<NestDynamicTemplateLayout[]> {
|
|
164
|
-
const {
|
|
165
|
-
scope,
|
|
166
|
-
scopeId,
|
|
167
|
-
type,
|
|
168
|
-
locale,
|
|
169
|
-
excludeNames = [],
|
|
170
|
-
} = filter;
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
// Build the where clause
|
|
174
|
-
const where: any = {};
|
|
175
|
-
if (type) where.type = type;
|
|
176
|
-
if (locale) where.locale = locale;
|
|
177
|
-
if (excludeNames.length > 0) where.name = Not(In(excludeNames));
|
|
178
|
-
|
|
179
|
-
const systemTemplates = await this.layoutRepository.find({
|
|
180
|
-
where: {
|
|
181
|
-
...where,
|
|
182
|
-
scope: 'system',
|
|
183
|
-
scopeId: IsNull(),
|
|
184
|
-
},
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
if (scope === 'system') {
|
|
188
|
-
return systemTemplates;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// First get all templates matching the filters
|
|
192
|
-
const templates = await this.layoutRepository.find({
|
|
193
|
-
where: {
|
|
194
|
-
...where,
|
|
195
|
-
scope: Equal(scope),
|
|
196
|
-
scopeId: scopeId as any,
|
|
197
|
-
},
|
|
198
|
-
order: {
|
|
199
|
-
createdAt: 'DESC',
|
|
200
|
-
},
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
// Create a map to store unique templates by name+type
|
|
204
|
-
const templateMap = new Map<string, NestDynamicTemplateLayout>();
|
|
205
|
-
|
|
206
|
-
for (const template of systemTemplates) {
|
|
207
|
-
const key = `${template.type}/${template.name}/${template.locale}`;
|
|
208
|
-
templateMap.set(key, template);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
for (const template of templates) {
|
|
212
|
-
const key = `${template.type}/${template.name}/${template.locale}`;
|
|
213
|
-
templateMap.set(key, template);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// Convert map values back to array
|
|
217
|
-
return Array.from(templateMap.values());
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
async getTemplateLayoutById(id: string): Promise<NestDynamicTemplateLayout | null> {
|
|
221
|
-
return this.layoutRepository.findOne({
|
|
222
|
-
where: { id },
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
async findTemplateLayout(
|
|
227
|
-
name: string,
|
|
228
|
-
scope?: string,
|
|
229
|
-
scopeId?: string,
|
|
230
|
-
locale?: string
|
|
231
|
-
): Promise<NestDynamicTemplateLayout | null> {
|
|
232
|
-
// Try to find template in the following order:
|
|
233
|
-
// 1. Scoped template with locale
|
|
234
|
-
// 2. Scoped template without locale
|
|
235
|
-
// 3. System template with locale
|
|
236
|
-
// 4. System template without locale
|
|
237
|
-
|
|
238
|
-
const locales = (locale ? [locale, 'en'] : ['en']).filter(Boolean);
|
|
239
|
-
|
|
240
|
-
// First try to find in the specified scope
|
|
241
|
-
for (const currentLocale of locales) {
|
|
242
|
-
const template = await this.layoutRepository.findOne({
|
|
243
|
-
where: {
|
|
244
|
-
name,
|
|
245
|
-
scope,
|
|
246
|
-
scopeId: scope === 'system' ? IsNull() : Equal(scopeId),
|
|
247
|
-
locale: currentLocale,
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
if (template) {
|
|
252
|
-
return template;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// If not found and not already in system scope, try system scope
|
|
257
|
-
if (scope !== 'system') {
|
|
258
|
-
for (const currentLocale of locales) {
|
|
259
|
-
const template = await this.layoutRepository.findOne({
|
|
260
|
-
where: {
|
|
261
|
-
name,
|
|
262
|
-
scope: 'system',
|
|
263
|
-
scopeId: IsNull(),
|
|
264
|
-
locale: currentLocale,
|
|
265
|
-
}
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
if (template) {
|
|
269
|
-
return template;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
return null;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Create a system template. Only system templates can be created directly.
|
|
279
|
-
*/
|
|
280
|
-
async createTemplateLayout(data: CreateTemplateLayoutDto): Promise<NestDynamicTemplateLayout> {
|
|
281
|
-
// Ensure this is a system template
|
|
282
|
-
if (data.scope !== 'system') {
|
|
283
|
-
throw new ForbiddenException('Only system templates can be created directly');
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// Check if template already exists
|
|
287
|
-
const existingTemplate = await this.layoutRepository.findOne({
|
|
288
|
-
where: {
|
|
289
|
-
name: data.name,
|
|
290
|
-
scope: 'system',
|
|
291
|
-
scopeId: IsNull(),
|
|
292
|
-
locale: data.locale,
|
|
293
|
-
},
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
if (existingTemplate) {
|
|
297
|
-
throw new ConflictException(`System template already exists`);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
const template = this.layoutRepository.create({
|
|
301
|
-
...data,
|
|
302
|
-
scopeId: undefined, // Ensure system templates have no scopeId
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
return this.layoutRepository.save(template);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
async overwriteSystemTemplateLayout(templateId: string, updates: Partial<CreateTemplateLayoutDto>): Promise<NestDynamicTemplateLayout> {
|
|
309
|
-
let template = await this.layoutRepository.findOne({
|
|
310
|
-
where: { id: templateId },
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
if (!template) {
|
|
314
|
-
throw new NotFoundException(`Template not found: ${templateId}`);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
if (template.scope === 'system') {
|
|
318
|
-
if (!updates.scope) {
|
|
319
|
-
throw new BadRequestException('Scope is required when overwriting system template');
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// Check if template already exists in target scope
|
|
323
|
-
const existingTemplate = await this.layoutRepository.findOne({
|
|
324
|
-
where: {
|
|
325
|
-
name: template.name,
|
|
326
|
-
locale: template.locale,
|
|
327
|
-
scope: updates.scope,
|
|
328
|
-
scopeId: updates.scopeId as any,
|
|
329
|
-
},
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
if (existingTemplate) {
|
|
333
|
-
// Update existing template in target scope
|
|
334
|
-
template = existingTemplate;
|
|
335
|
-
} else {
|
|
336
|
-
// Create new template in target scope
|
|
337
|
-
const newTemplate = this.layoutRepository.create({
|
|
338
|
-
...template,
|
|
339
|
-
id: undefined,
|
|
340
|
-
createdAt: undefined,
|
|
341
|
-
updatedAt: undefined,
|
|
342
|
-
scope: updates.scope,
|
|
343
|
-
scopeId: updates.scopeId,
|
|
344
|
-
});
|
|
345
|
-
template = newTemplate;
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
template = this.layoutRepository.merge(template, updates);
|
|
350
|
-
await this.layoutRepository.save(template);
|
|
351
|
-
return template;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
/**
|
|
356
|
-
* Update a template
|
|
357
|
-
*/
|
|
358
|
-
async updateTemplateLayout(
|
|
359
|
-
id: string,
|
|
360
|
-
updates: Partial<CreateTemplateLayoutDto>,
|
|
361
|
-
canUpdateSystemTemplate: boolean = false,
|
|
362
|
-
): Promise<NestDynamicTemplateLayout> {
|
|
363
|
-
// Find the template
|
|
364
|
-
let template = await this.layoutRepository.findOne({
|
|
365
|
-
where: { id },
|
|
366
|
-
});
|
|
367
|
-
|
|
368
|
-
if (!template) {
|
|
369
|
-
throw new NotFoundException(`Template not found: ${id}`);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// If it's a system template and we can't update it, try to overwrite it
|
|
373
|
-
if (template.scope === 'system' && !canUpdateSystemTemplate) {
|
|
374
|
-
|
|
375
|
-
if (updates.scope) {
|
|
376
|
-
// Otherwise, allow overwriting to custom scope
|
|
377
|
-
return this.overwriteSystemTemplateLayout(id, updates);
|
|
378
|
-
} else {
|
|
379
|
-
throw new ForbiddenException('Cannot update system templates');
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
// For regular updates
|
|
384
|
-
template = this.layoutRepository.merge(template, updates);
|
|
385
|
-
return this.layoutRepository.save(template);
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
/**
|
|
389
|
-
* Delete a scoped template
|
|
390
|
-
*/
|
|
391
|
-
async deleteTemplateLayout(id: string, canDeleteSystemTemplate: boolean = false): Promise<void> {
|
|
392
|
-
const template = await this.layoutRepository.findOne({
|
|
393
|
-
where: { id },
|
|
394
|
-
});
|
|
395
|
-
|
|
396
|
-
if (!template) {
|
|
397
|
-
throw new Error(`Template not found: ${id}`);
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
// Prevent deleting system templates
|
|
401
|
-
if (template.scope === 'system' && !canDeleteSystemTemplate) {
|
|
402
|
-
throw new ForbiddenException('Cannot delete system templates');
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
await this.layoutRepository.remove(template);
|
|
406
|
-
}
|
|
407
|
-
}
|