Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions backend/actions/Alert/createAlert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
'use strict';

const Archetype = require('archetype');
const authorize = require('../../authorize');

const CreateAlertParams = new Archetype({
workspaceId: {
$type: 'string'
},
name: {
$type: 'string'
},
eventType: {
$type: 'string',
$required: true
},
database: {
$type: 'string'
},
collection: {
$type: 'string'
},
slackChannel: {
$type: 'string',
$required: true
},
templateText: {
$type: 'string',
$required: true
},
enabled: {
$type: 'boolean'
},
roles: {
$type: ['string']
}
}).compile('CreateAlertParams');

module.exports = ({ studioConnection }) => async function createAlert(params) {
const {
workspaceId,
name,
eventType,
database,
collection,
slackChannel,
templateText,
enabled,
roles
} = new CreateAlertParams(params);

await authorize('Alert.createAlert', roles);

const Alert = studioConnection.model('__Studio_Alert');
const alert = await Alert.create({
workspaceId,
name,
eventType,
database,
collection,
slackChannel,
templateText,
enabled: !!enabled
});

return { alert };
};
25 changes: 25 additions & 0 deletions backend/actions/Alert/deleteAlert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use strict';

const Archetype = require('archetype');
const authorize = require('../../authorize');

const DeleteAlertParams = new Archetype({
alertId: {
$type: 'string',
$required: true
},
roles: {
$type: ['string']
}
}).compile('DeleteAlertParams');

module.exports = ({ studioConnection }) => async function deleteAlert(params) {
const { alertId, roles } = new DeleteAlertParams(params);

await authorize('Alert.deleteAlert', roles);

const Alert = studioConnection.model('__Studio_Alert');
await Alert.findByIdAndDelete(alertId);

return { success: true };
};
7 changes: 7 additions & 0 deletions backend/actions/Alert/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict';

exports.createAlert = require('./createAlert');
exports.deleteAlert = require('./deleteAlert');
exports.listAlerts = require('./listAlerts');
exports.sendTestAlert = require('./sendTestAlert');
exports.updateAlert = require('./updateAlert');
25 changes: 25 additions & 0 deletions backend/actions/Alert/listAlerts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use strict';

const Archetype = require('archetype');
const authorize = require('../../authorize');

const ListAlertsParams = new Archetype({
workspaceId: {
$type: 'string'
},
roles: {
$type: ['string']
}
}).compile('ListAlertsParams');

module.exports = ({ studioConnection }) => async function listAlerts(params = {}) {
const { workspaceId, roles } = new ListAlertsParams(params);

await authorize('Alert.listAlerts', roles);

const Alert = studioConnection.model('__Studio_Alert');
const query = workspaceId ? { workspaceId } : {};
const alerts = await Alert.find(query).sort({ createdAt: -1 }).lean();

return { alerts };
};
47 changes: 47 additions & 0 deletions backend/actions/Alert/sendTestAlert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
'use strict';

const Archetype = require('archetype');
const authorize = require('../../authorize');
const { renderTemplate, notifySlack } = require('../../alerts/alertUtils');

const SendTestAlertParams = new Archetype({
workspaceId: {
$type: 'string'
},
slackChannel: {
$type: 'string',
$required: true
},
templateText: {
$type: 'string',
$required: true
},
sampleDocument: {
$type: 'object',
$required: true
},
roles: {
$type: ['string']
}
}).compile('SendTestAlertParams');

module.exports = ({ options }) => async function sendTestAlert(params) {
const { workspaceId, slackChannel, templateText, sampleDocument, roles } = new SendTestAlertParams(params);

await authorize('Alert.sendTestAlert', roles);

const mothershipUrl = options?._mothershipUrl || 'https://mongoose-js.netlify.app/.netlify/functions';
const text = renderTemplate(templateText, sampleDocument);
await notifySlack({
mothershipUrl,
payload: {
workspaceId,
channel: slackChannel,
template: templateText,
text,
sampleDocument
}
});

return { success: true };
};
73 changes: 73 additions & 0 deletions backend/actions/Alert/updateAlert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
'use strict';

const Archetype = require('archetype');
const authorize = require('../../authorize');

const UpdateAlertParams = new Archetype({
alertId: {
$type: 'string',
$required: true
},
workspaceId: {
$type: 'string'
},
name: {
$type: 'string'
},
eventType: {
$type: 'string'
},
database: {
$type: 'string'
},
collection: {
$type: 'string'
},
slackChannel: {
$type: 'string'
},
templateText: {
$type: 'string'
},
enabled: {
$type: 'boolean'
},
roles: {
$type: ['string']
}
}).compile('UpdateAlertParams');

module.exports = ({ studioConnection }) => async function updateAlert(params) {
const {
alertId,
workspaceId,
name,
eventType,
database,
collection,
slackChannel,
templateText,
enabled,
roles
} = new UpdateAlertParams(params);

await authorize('Alert.updateAlert', roles);

const Alert = studioConnection.model('__Studio_Alert');
const alert = await Alert.findByIdAndUpdate(
alertId,
{
workspaceId,
name,
eventType,
database,
collection,
slackChannel,
templateText,
enabled
},
{ new: true }
);

return { alert };
};
1 change: 1 addition & 0 deletions backend/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
exports.ChatMessage = require('./ChatMessage');
exports.ChatThread = require('./ChatThread');
exports.Dashboard = require('./Dashboard');
exports.Alert = require('./Alert');
exports.Model = require('./Model');
exports.Script = require('./Script');
exports.status = require('./status');
36 changes: 36 additions & 0 deletions backend/alerts/alertUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
'use strict';

function getValueByPath(object, path) {
return path.split('.').reduce((acc, key) => (acc && acc[key] !== undefined ? acc[key] : null), object);
}

function renderTemplate(template, doc) {
if (!template) {
return '';
}
return template.replace(/{{\s*([^}]+)\s*}}/g, (_match, path) => {
const value = getValueByPath(doc, path.trim());
return value === null ? '—' : String(value);
});
}

async function notifySlack({ mothershipUrl, payload }) {
const response = await fetch(`${mothershipUrl}/notifySlack`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});

if (!response.ok) {
const text = await response.text();
throw new Error(`Slack notify failed (${response.status}): ${text}`);
}

return response.json().catch(() => ({}));
}

module.exports = {
getValueByPath,
renderTemplate,
notifySlack
};
Loading
Loading