UNPKG

@topgroup/diginext

Version:

A BUILD SERVER & CLI to deploy apps to any Kubernetes clusters.

250 lines (249 loc) 10.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.NotificationService = exports.sendJojoNotificationDataSchema = exports.jojoWebhookSchema = exports.sendNotificationWebhookDataSchema = exports.sendNotificationDataSchema = void 0; const axios_1 = __importDefault(require("axios")); const lodash_1 = require("lodash"); const zod_1 = require("zod"); const Notification_1 = require("../entities/Notification"); const SystemTypes_1 = require("../interfaces/SystemTypes"); const dx_email_1 = require("../modules/diginext/dx-email"); const mongodb_1 = require("../plugins/mongodb"); const BaseService_1 = __importDefault(require("./BaseService")); exports.sendNotificationDataSchema = zod_1.z.object({ /** * User ID of the sender */ from: zod_1.z.string(), /** * User ID of the recipient */ to: zod_1.z.union([zod_1.z.string(), zod_1.z.array(zod_1.z.string())]), /** * Notification's title */ title: zod_1.z.string(), /** * Notification's content */ message: zod_1.z.string().optional(), /** * The system event that triggered the notification */ events: zod_1.z.array(zod_1.z.enum(SystemTypes_1.systemEventList)).optional(), /** * Target channels */ channels: zod_1.z.array(zod_1.z.enum(SystemTypes_1.webhookChannelList)).optional(), /** * Referenced data of a notification */ references: zod_1.z.record(zod_1.z.any()).optional(), /** * Callback URL of a notification */ url: zod_1.z.string().url().optional(), }); exports.sendNotificationWebhookDataSchema = exports.sendNotificationDataSchema.pick({ to: true, from: true, title: true, message: true, references: true, url: true, }); const embedFieldSchema = zod_1.z.object({ name: zod_1.z.string().optional(), value: zod_1.z.string().optional(), inline: zod_1.z.boolean().optional().default(false), }); const embedImageSchema = zod_1.z.object({ url: zod_1.z.string().url().optional(), }); const embedAuthorSchema = zod_1.z.object({ name: zod_1.z.string().optional(), icon_url: zod_1.z.string().url().optional(), }); const embedFooterSchema = zod_1.z.object({ text: zod_1.z.string().optional(), icon_url: zod_1.z.string().url().optional(), }); const embedSchema = zod_1.z.object({ title: zod_1.z.string().optional(), description: zod_1.z.string().optional(), url: zod_1.z.string().url().optional(), color: zod_1.z.number().nullable().optional(), image: embedImageSchema.optional(), author: embedAuthorSchema.optional(), footer: embedFooterSchema.optional(), fields: zod_1.z.array(embedFieldSchema).optional(), }); const componentSchema = zod_1.z.any().optional(); exports.jojoWebhookSchema = zod_1.z.object({ channelId: zod_1.z.string().optional(), content: zod_1.z.string().optional(), embeds: zod_1.z.array(embedSchema).optional(), components: zod_1.z.array(componentSchema).optional(), }); exports.sendJojoNotificationDataSchema = exports.jojoWebhookSchema.pick({ channelId: true, content: true, embeds: true, components: true, }); class NotificationService extends BaseService_1.default { constructor(ownership) { super(Notification_1.notificationSchema, ownership); this.JOJO_API_KEY = process.env.JOJO_API_KEY; this.JOJO_API_URL = "https://app.digicord.site/api/v1/send-data"; } /** * Send the notification via webhook */ async webhookSend(webhook, data, options) { // validate if (!webhook) throw new Error(`Notification "webhook" is required.`); if (!data) throw new Error(`Notification "data" is required.`); // process & return return this.send({ ...data, channels: webhook.channels, events: webhook.events, from: mongodb_1.MongoDB.toString(webhook.owner) }, options); } /** * Send the notification directly */ async send(data, options) { // validate if (!data) throw new Error(`Notification "data" is required.`); if (!data.to) throw new Error(`Notification recipient ID ("to") is required.`); if (!data.from) throw new Error(`Notification sender ID ("from") is required.`); if (!data.title) throw new Error(`Notification "title" is required.`); // process const { socketIO } = await Promise.resolve().then(() => __importStar(require("../server"))); const { UserService } = await Promise.resolve().then(() => __importStar(require("./index"))); const userSvc = new UserService(); const emailRecipients = await userSvc.find({ _id: { $in: (0, lodash_1.isArray)(data.to) ? data.to : [] } }); const results = await Promise.all(data.channels.map((channel) => { switch (channel) { case "http_callback": // make a request here break; case "email": // make a email notification request here return (0, dx_email_1.dxSendEmail)({ recipients: emailRecipients.map(({ name, email }) => ({ name, email })), subject: `[DIGINEXT / ${this.ownership.workspace.name}] ${data.title}`, content: `Hey,<br/><br/>You've got a notification from "${this.ownership.workspace.name}" workspace:<br/><br/>${data.message}<br/><br/>—<br/>You are receiving this because you are subscribed to this thread.<br/><a href="https://app.dxup.dev/settings/notifications">Manage your Diginext notifications</a>`, }, this.ownership.workspace.dx_key); break; case "web_push": // make a web push notification request here break; default: console.warn(`Webhook channel "${channel}" is invalid.`); break; } })); if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log("[NOTIFICATION] SEND > results :>> ", results); // create db instance if ((0, lodash_1.isArray)(data.to)) { // multiple recipients return Promise.all(data.to.map((recipientId) => { // create notification const notiData = {}; notiData.owner = recipientId; notiData.name = data.title; notiData.message = data.message; notiData.from = data.from; notiData.events = data.events; notiData.channels = data.channels; notiData.references = data.references; return this.create(notiData, options); })) .then((notifications) => { // emit websocket to clients notifications.map(({ owner: recipientId }) => { socketIO === null || socketIO === void 0 ? void 0 : socketIO.to(recipientId.toString()).emit("notification", { action: "new", message: "You have new notification" }); }); return notifications; }) .catch((e) => { console.error(`Unable to send notification:`, e); }); } else { // create notification -> single recipient const notiData = {}; notiData.owner = data.to; notiData.name = data.title; notiData.message = data.message; notiData.from = data.from; notiData.events = data.events; notiData.channels = data.channels; notiData.references = data.references; return this.create(notiData, options) .then((noti) => { // emit websocket to clients socketIO === null || socketIO === void 0 ? void 0 : socketIO.to(noti.owner.toString()).emit("notification", { action: "new", message: "You have new notification" }); return noti; }) .catch((e) => { console.error(`Unable to send notification:`, e); }); } } /** * Mark the notification as read. * @param id - Notification ID */ async markAsRead(filter = {}, options) { // process return this.updateOne(filter, { readAt: new Date() }, options); } /** * Send the notification to Jojo */ async sendToJojo(data, options) { if (!this.JOJO_API_KEY) throw new Error(`Jojo API key is not set.`); // process if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log("[NOTIFICATION] SEND TO JOJO > data :>> ", data); const jojoData = exports.jojoWebhookSchema.parse(data); const response = await axios_1.default.post(this.JOJO_API_URL, jojoData, { headers: { Authorization: `Bearer ${this.JOJO_API_KEY}` } }); if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log("[NOTIFICATION] SEND TO JOJO > response :>> ", response); return response.data; } } exports.NotificationService = NotificationService;