@topgroup/diginext
Version:
A BUILD SERVER & CLI to deploy apps to any Kubernetes clusters.
250 lines (249 loc) • 10.5 kB
JavaScript
;
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;