saleor-apps-redis_apl/apps/emails-and-messages/src/modules/mjml/configuration/mjml-configuration.router.ts
2023-03-07 22:03:58 +01:00

248 lines
9.1 KiB
TypeScript

import { PrivateMetadataMjmlConfigurator } from "./mjml-configurator";
import { logger as pinoLogger } from "../../../lib/logger";
import {
mjmlCreateConfigurationSchema,
mjmlDeleteConfigurationInputSchema,
mjmlGetConfigurationInputSchema,
mjmlGetConfigurationsInputSchema,
mjmlGetEventConfigurationInputSchema,
mjmlUpdateEventConfigurationInputSchema,
mjmlUpdateOrCreateConfigurationSchema,
} from "./mjml-config-input-schema";
import { GetMjmlConfigurationService } from "./get-mjml-configuration.service";
import { router } from "../../trpc/trpc-server";
import { protectedClientProcedure } from "../../trpc/protected-client-procedure";
import { createSettingsManager } from "../../app-configuration/metadata-manager";
import { z } from "zod";
import { compileMjml } from "../compile-mjml";
import Handlebars from "handlebars";
import { MjmlConfigContainer } from "./mjml-config-container";
import { TRPCError } from "@trpc/server";
export const mjmlConfigurationRouter = router({
fetch: protectedClientProcedure.query(async ({ ctx }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug("mjmlConfigurationRouter.fetch called");
return new GetMjmlConfigurationService({
apiClient: ctx.apiClient,
saleorApiUrl: ctx.saleorApiUrl,
}).getConfiguration();
}),
getConfiguration: protectedClientProcedure
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(mjmlGetConfigurationInputSchema)
.query(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "mjmlConfigurationRouter.get called");
const mjmlConfigurator = new PrivateMetadataMjmlConfigurator(
createSettingsManager(ctx.apiClient),
ctx.saleorApiUrl
);
const configRoot = await mjmlConfigurator.getConfig();
return MjmlConfigContainer.getConfiguration(configRoot)(input);
}),
getConfigurations: protectedClientProcedure
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(mjmlGetConfigurationsInputSchema)
.query(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "mjmlConfigurationRouter.getConfigurations called");
const mjmlConfigurator = new PrivateMetadataMjmlConfigurator(
createSettingsManager(ctx.apiClient),
ctx.saleorApiUrl
);
const configRoot = await mjmlConfigurator.getConfig();
return MjmlConfigContainer.getConfigurations(configRoot)(input);
}),
createConfiguration: protectedClientProcedure
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(mjmlCreateConfigurationSchema)
.mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "mjmlConfigurationRouter.create called");
const mjmlConfigurator = new PrivateMetadataMjmlConfigurator(
createSettingsManager(ctx.apiClient),
ctx.saleorApiUrl
);
const configRoot = await mjmlConfigurator.getConfig();
const newConfigurationRoot = MjmlConfigContainer.createConfiguration(configRoot)(input);
await mjmlConfigurator.setConfig(newConfigurationRoot);
return null;
}),
deleteConfiguration: protectedClientProcedure
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(mjmlDeleteConfigurationInputSchema)
.mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "mjmlConfigurationRouter.delete called");
const mjmlConfigurator = new PrivateMetadataMjmlConfigurator(
createSettingsManager(ctx.apiClient),
ctx.saleorApiUrl
);
const configRoot = await mjmlConfigurator.getConfig();
const newConfigurationRoot = MjmlConfigContainer.deleteConfiguration(configRoot)(input);
await mjmlConfigurator.setConfig(newConfigurationRoot);
return null;
}),
updateOrCreateConfiguration: protectedClientProcedure
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(mjmlUpdateOrCreateConfigurationSchema)
.mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "mjmlConfigurationRouter.update or create called");
const mjmlConfigurator = new PrivateMetadataMjmlConfigurator(
createSettingsManager(ctx.apiClient),
ctx.saleorApiUrl
);
const configRoot = await mjmlConfigurator.getConfig();
const { id } = input;
if (!!id) {
const existingConfiguration = MjmlConfigContainer.getConfiguration(configRoot)({ id });
if (!existingConfiguration) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Configuration not found",
});
}
// checking typeof id is not enough to satisfy typescript, so need to override id field issue
const configuration = {
id,
...input,
events: existingConfiguration.events,
};
const newConfigurationRoot =
MjmlConfigContainer.updateConfiguration(configRoot)(configuration);
await mjmlConfigurator.setConfig(newConfigurationRoot);
return configuration;
} else {
const newConfigurationRoot = MjmlConfigContainer.createConfiguration(configRoot)(input);
await mjmlConfigurator.setConfig(newConfigurationRoot);
return newConfigurationRoot.configurations[newConfigurationRoot.configurations.length - 1];
}
}),
getEventConfiguration: protectedClientProcedure
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(mjmlGetEventConfigurationInputSchema)
.query(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "mjmlConfigurationRouter.getEventConfiguration or create called");
const mjmlConfigurator = new PrivateMetadataMjmlConfigurator(
createSettingsManager(ctx.apiClient),
ctx.saleorApiUrl
);
const configRoot = await mjmlConfigurator.getConfig();
const configuration = MjmlConfigContainer.getConfiguration(configRoot)({
id: input.configurationId,
});
if (!configuration) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Configuration not found",
});
}
const event = configuration.events.find((e) => e.eventType === input.eventType);
if (!event) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Event configuration not found",
});
}
return event;
}),
updateEventConfiguration: protectedClientProcedure
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(mjmlUpdateEventConfigurationInputSchema)
.mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "mjmlConfigurationRouter.updateEventConfiguration or create called");
const mjmlConfigurator = new PrivateMetadataMjmlConfigurator(
createSettingsManager(ctx.apiClient),
ctx.saleorApiUrl
);
const configRoot = await mjmlConfigurator.getConfig();
const configuration = MjmlConfigContainer.getConfiguration(configRoot)({
id: input.configurationId,
});
if (!configuration) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Configuration not found",
});
}
const eventIndex = configuration.events.findIndex((e) => e.eventType === input.eventType);
configuration.events[eventIndex] = {
active: input.active,
eventType: input.eventType,
template: input.template,
subject: input.subject,
};
const newConfigurationRoot =
MjmlConfigContainer.updateConfiguration(configRoot)(configuration);
await mjmlConfigurator.setConfig(newConfigurationRoot);
return configuration;
}),
renderTemplate: protectedClientProcedure
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(
z.object({
template: z.string().optional(),
subject: z.string().optional(),
payload: z.string(),
})
)
.mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "mjmlConfigurationRouter.renderTemplate called");
let renderedSubject = "";
const payload = JSON.parse(input.payload);
if (input.subject) {
const compiledSubjectTemplate = Handlebars.compile(input.subject);
logger.warn("subject part");
renderedSubject = compiledSubjectTemplate(payload);
}
let renderedEmail = "";
if (input.template) {
const compiledSubjectTemplate = Handlebars.compile(input.template);
const templatedEmail = compiledSubjectTemplate(payload);
const { html: rawHtml } = compileMjml(templatedEmail);
if (rawHtml) {
renderedEmail = rawHtml;
}
}
return {
renderedSubject,
renderedEmailBody: renderedEmail,
};
}),
});