UNPKG

@grouparoo/core

Version:
362 lines (361 loc) 14.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.plugin = void 0; const actionhero_1 = require("actionhero"); const mustacheUtils_1 = require("./mustacheUtils"); const App_1 = require("../models/App"); const AppRefreshQuery_1 = require("../models/AppRefreshQuery"); const ApiKey_1 = require("../models/ApiKey"); const Destination_1 = require("../models/Destination"); const DestinationGroupMembership_1 = require("../models/DestinationGroupMembership"); const Export_1 = require("../models/Export"); const Group_1 = require("../models/Group"); const GroupMember_1 = require("../models/GroupMember"); const GroupRule_1 = require("../models/GroupRule"); const Import_1 = require("../models/Import"); const Mapping_1 = require("../models/Mapping"); const Option_1 = require("../models/Option"); const OAuthRequest_1 = require("../models/OAuthRequest"); const Permission_1 = require("../models/Permission"); const GrouparooRecord_1 = require("../models/GrouparooRecord"); const RecordProperty_1 = require("../models/RecordProperty"); const Property_1 = require("../models/Property"); const Filter_1 = require("../models/Filter"); const RecordMultipleAssociationShim_1 = require("../models/RecordMultipleAssociationShim"); const Run_1 = require("../models/Run"); const GrouparooModel_1 = require("../models/GrouparooModel"); const Schedule_1 = require("../models/Schedule"); const Session_1 = require("../models/Session"); const Setting_1 = require("../models/Setting"); const SetupStep_1 = require("../models/SetupStep"); const Source_1 = require("../models/Source"); const Notification_1 = require("../models/Notification"); const Team_1 = require("../models/Team"); const TeamMember_1 = require("../models/TeamMember"); const ExportProcessor_1 = require("../models/ExportProcessor"); const propertiesCache_1 = require("./caches/propertiesCache"); const oAuth_1 = require("../modules/oAuth"); // the order matters here - the children need to come before the parents (destinationGroup -> destination) const models = [ App_1.App, AppRefreshQuery_1.AppRefreshQuery, ApiKey_1.ApiKey, Source_1.Source, Schedule_1.Schedule, Destination_1.Destination, DestinationGroupMembership_1.DestinationGroupMembership, Option_1.Option, OAuthRequest_1.OAuthRequest, Filter_1.Filter, Import_1.Import, Run_1.Run, Export_1.Export, ExportProcessor_1.ExportProcessor, GroupMember_1.GroupMember, Group_1.Group, GroupRule_1.GroupRule, Permission_1.Permission, GrouparooModel_1.GrouparooModel, GrouparooRecord_1.GrouparooRecord, RecordProperty_1.RecordProperty, Property_1.Property, RecordMultipleAssociationShim_1.RecordMultipleAssociationShim, Mapping_1.Mapping, Notification_1.Notification, Setting_1.Setting, Session_1.Session, SetupStep_1.SetupStep, Team_1.Team, TeamMember_1.TeamMember, ]; const _oAuthAccessTokenGetters = {}; var plugin; (function (plugin_1) { /** * This is needed when running in dev mode (TS) but you are using a compiled plugin (JS). * The plugin will actually load the JS model while core will be loading the TS model. * Both need to be "added" to sequelize to know which connection to use. */ function mountModels() { models.map((model) => { if (!model.isInitialized) actionhero_1.api.sequelize.addModels([model]); }); } plugin_1.mountModels = mountModels; /** * Register a Grouparoo Plugin */ function registerPlugin(plugin, validate) { actionhero_1.api.plugins.register(plugin, validate); } plugin_1.registerPlugin = registerPlugin; /** * Register a setting for your Grouparoo plugin */ async function registerSetting(pluginName, key, title, defaultValue, description, type, variant = "info") { const setting = await Setting_1.Setting.findOne({ where: { pluginName, key } }); if (setting) { return setting.update({ title, defaultValue: defaultValue.toString(), description, type, variant, }); } try { const setting = await Setting_1.Setting.create({ pluginName, key, title, value: defaultValue, defaultValue, description, type, variant, }); return setting; } catch (error) { throw new Error(`error registering setting: ${JSON.stringify({ pluginName, key, defaultValue: defaultValue.toString(), description, type, })}: ${error}`); } } plugin_1.registerSetting = registerSetting; /** * Read a setting for this plugin */ async function readSetting(pluginName, key) { const setting = await Setting_1.Setting.findOne({ where: { pluginName, key }, }); if (!setting) { throw new Error(`setting ${key} not registered for grouparoo plugin ${pluginName}`); } return setting; } plugin_1.readSetting = readSetting; /** * Update a setting for this plugin */ async function updateSetting(pluginName, key, value) { const setting = await plugin.readSetting(pluginName, key); setting.value = value; await setting.save(); return setting; } plugin_1.updateSetting = updateSetting; /** * When your plugin has a record for a record, send it to this method. We will use the provided mapping against your raw data row to store the original data and mapped data to the record. * mapping: an object whose keys are remote columns and whose values are the property keys, ie: {remoteColumnId: 'userId'} * row: {email: 'abc@company.com', vip: true} */ async function createImport(mapping, run, row) { const mappingKeys = Object.keys(mapping); const mappedRecordProperties = {}; mappingKeys.forEach((k) => { mappedRecordProperties[mapping[k]] = Array.isArray(row[k]) ? row[k] : [row[k]]; }); const _import = await Import_1.Import.create({ rawData: row, data: mappedRecordProperties, creatorType: "run", creatorId: run.id, }); return _import; } plugin_1.createImport = createImport; /** * Like plugin.createImport, but for many imports at once! * * mapping: an object whose keys are remote columns and whose values are the property keys, ie: {remoteColumnId: 'userId'} * rows: {email: 'abc@company.com', vip: true}[] */ async function createImports(mapping, run, rows) { const bulkParams = []; const mappingKeys = Object.keys(mapping); for (const row of rows) { const mappedRecordProperties = {}; mappingKeys.forEach((k) => { mappedRecordProperties[mapping[k]] = Array.isArray(row[k]) ? row[k] : [row[k]]; }); bulkParams.push({ rawData: row, data: mappedRecordProperties, creatorType: "run", creatorId: run.id, }); } if (bulkParams.length === 0) return []; let _imports = []; while (bulkParams.length > 0) { _imports = _imports.concat(await Import_1.Import.bulkCreate(bulkParams.splice(0, actionhero_1.config.batchSize.internalWrite))); } return _imports; } plugin_1.createImports = createImports; /** * data helpers */ function expandDates(raw) { if (!raw) { return null; } return { raw, iso: raw.toISOString(), sql: raw.toISOString().slice(0, 19).replace("T", " "), date: raw.toISOString().split("T")[0], time: raw.toISOString().split("T")[1].split(".")[0], }; } plugin_1.expandDates = expandDates; /** * Takes a string with mustache variables and replaces them with the proper values for a schedule and run */ async function replaceTemplateRunVariables(string, run) { if (string.indexOf("{{") < 0) { return string; } const data = { now: expandDates(new Date()), run: {}, previousRun: { id: "", creatorId: "", creatorType: "", error: null, state: "mocked", createdAt: expandDates(new Date(0)), updatedAt: expandDates(new Date(0)), }, }; if (run) { data.run = { id: run.id, creatorId: run.creatorId, creatorType: run.creatorType, state: run.state, error: run.error, createdAt: expandDates(run.createdAt), updatedAt: expandDates(run.updatedAt), }; const previousRun = await run.previousRun(); if (previousRun) { data.previousRun = { id: previousRun.id, creatorId: previousRun.creatorId, creatorType: previousRun.creatorType, state: previousRun.state, error: previousRun.error, createdAt: expandDates(previousRun.createdAt), updatedAt: expandDates(previousRun.updatedAt), }; } } return mustacheUtils_1.MustacheUtils.strictlyRender(string, data); } plugin_1.replaceTemplateRunVariables = replaceTemplateRunVariables; /** * Takes a record and returns data with the values from the properties and current time. */ async function getRecordData(record) { // TODO: we could do these types better to be string | number | etc | string[] | etc> const dates = { now: expandDates(new Date()), createdAt: expandDates(record.createdAt), updatedAt: expandDates(record.updatedAt), }; const properties = await record.getProperties(); const propertyData = {}; for (const [key, property] of Object.entries(properties)) { propertyData[key] = property.values.length === 1 ? property.values[0] instanceof Date ? expandDates(property.values[0]) : property.values[0] : property.values.map((value) => (value || "").toString()).join(", "); } return Object.assign(dates, propertyData); } plugin_1.getRecordData = getRecordData; /** * Takes a string with mustache variables and replaces them with the proper values for a record */ async function replaceTemplateRecordVariables(string, record, strict = true) { if (string.indexOf("{{") < 0) return string; const data = await getRecordData(record); if (strict === true) return mustacheUtils_1.MustacheUtils.strictlyRender(string, data); return mustacheUtils_1.MustacheUtils.render(string, data); } plugin_1.replaceTemplateRecordVariables = replaceTemplateRecordVariables; /** * Takes a string with mustache variable (keys) and replaces them with the record property ids * ie: `select * where id = {{{ userId }}}` => `select * where id = {{{ ppr_abc123 }}}` */ async function replaceTemplateRecordPropertyKeysWithRecordPropertyId(string, modelId) { //though we default to 3 brackets, if someone inputs the double bracket notation, we should accept it if (string.indexOf("{{") < 0) return string; const properties = (await propertiesCache_1.PropertiesCache.findAllWithCache(modelId, "ready")).filter((p) => p.isArray === false); const data = {}; properties.forEach((rule) => { data[rule.key] = `{{{ ${rule.id} }}}`; }); return mustacheUtils_1.MustacheUtils.strictlyRender(string, data); } plugin_1.replaceTemplateRecordPropertyKeysWithRecordPropertyId = replaceTemplateRecordPropertyKeysWithRecordPropertyId; /** * Takes a string with mustache variable (ids) and replaces them with the record property keys * ie: `select * where id = {{{ ppr_abc123 }}}` => `select * where id = {{{ userId }}}` */ async function replaceTemplateRecordPropertyIdsWithRecordPropertyKeys(string, modelId) { //though we default to 3 brackets, if someone inputs the double bracket notation, we should accept it if (string.indexOf("{{") < 0) return string; const properties = await propertiesCache_1.PropertiesCache.findAllWithCache(modelId, "ready"); const data = {}; properties.forEach((rule) => { data[rule.id] = `{{{ ${rule.key} }}}`; }); return mustacheUtils_1.MustacheUtils.strictlyRender(string, data); } plugin_1.replaceTemplateRecordPropertyIdsWithRecordPropertyKeys = replaceTemplateRecordPropertyIdsWithRecordPropertyKeys; function setApmWrap(f) { actionhero_1.api.apm.wrap = f; } plugin_1.setApmWrap = setApmWrap; /** * Returns the access token for an OAuth-based plugin app that uses refresh tokens. * Manages cache and expiration of the token. * In order to use this, app OAuth access must first be setup by the Grouparoo team. * * @param providerName the name of the provider (e.g. hubspot) * @param refreshToken the refresh token stored by the app options * @returns the access token */ async function getOAuthAppAccessToken(providerName, refreshToken) { let getter = _oAuthAccessTokenGetters[providerName]; if (!getter) { getter = new oAuth_1.oAuthAccessTokenGetter(providerName, refreshToken); _oAuthAccessTokenGetters[providerName] = getter; } else if (getter.refreshToken !== refreshToken) { getter.refreshToken = refreshToken; } return await getter.getAccessToken(); } plugin_1.getOAuthAppAccessToken = getOAuthAppAccessToken; })(plugin = exports.plugin || (exports.plugin = {}));