diff --git a/examples/typescript/README.md b/examples/typescript/README.md index 6ccb27e6a..1291847bf 100644 --- a/examples/typescript/README.md +++ b/examples/typescript/README.md @@ -31,6 +31,8 @@ These examples assume that a `looker.ini` has been created in the root of the re - `yarn run-generate-api-credentials` - runs bulk generate api credentials example. - `yarn run-test-connections` - runs test connections example. - `yarn run-pdt-mapping` - runs pdt mapping example. + - `yarn run-create-slack-alert` - runs create slack alert example. + - `yarn bulk-delete-alerts` - runs bulk delete alerts example. Some other dependencies may be required for the projects to build and run correctly on your local clone. @@ -65,12 +67,14 @@ A very brief descriptions of the examples, and the link to the main example/proj | [sudo as user](sudoAsUser.ts) | Uses several User management SDK methods and shows how to `sudo` as a different user than the default API credentials user. Once the auth session is set to that user, subsequent SDK requests will be "as user ``" when submitted to the API.| | [bulk generate api credentials](generateApiCredentials.ts) | Allows an admin to generate api credentials in bulk given a Looker role ID as input (Ex: generate api credentials for all users with the "Developer" role). -### Schedules +### Schedules & Alerts |   Example Topic   | Discussion | | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [bulk disable schedules](bulkDisableSchedules.ts) | This script allows an admin user to disable all user schedules OR just the schedules of a specific user. | -| [bulk reassign schedules](bulkReassignSchedules.ts) | This script allows allows an admin user to either reassign all user schedules OR a single user's schedules to a specified user. +| [bulk reassign schedules](bulkReassignSchedules.ts) | This script allows allows an admin user to either reassign all user schedules OR a single user's schedules to a specified user. | +| [bulk delete alerts](bulkDeleteAlerts.ts) | This script allows an admin user to bulk delete alerts for a specific user on the instance. | +| [create slack alert](createSlackAlert.ts) | This script allows a user to create an alert on a tile of a given dashboard element that sends an alert message to slack when triggered. Users will need at least the `create_alerts` role to be able to run this call. Configuration variables are outlined in the script. ### Git / LookML Project Validation diff --git a/examples/typescript/bulkDeleteAlerts.ts b/examples/typescript/bulkDeleteAlerts.ts new file mode 100644 index 000000000..0c9ad4b02 --- /dev/null +++ b/examples/typescript/bulkDeleteAlerts.ts @@ -0,0 +1,58 @@ +import { LookerNodeSDK } from '@looker/sdk-node' + +/** +Admin Script to Bulk Delete Alerts for a given user +**/ + +/** +Pulls from Environment Variables, see env sample in sdk-codegen root directory +An ini file can be used as well. See ./downloadDashboard.ts file for an example of this approach. + */ +const sdk = LookerNodeSDK.init40() + +/** + * @param {number} userId: the user who's alerts one wants to fetch + * @returns {Promise}: Object containing number of alerts deleted and user + */ + +const bulkDeleteAlerts = async (userId: number) => { + if (!userId) { + throw new Error('Please specify a specific user id to disable alerts for.') + } + try { + // return all alerts, then filter for specific user + const alertResponse = await sdk.ok( + sdk.search_alerts({ + group_by: 'owner_id', + fields: 'id,owner_id', + all_owners: true, + }) + ) + const alertsToDelete = alertResponse.filter( + (alert) => alert.owner_id === userId + ) + if (alertsToDelete.length > 0) { + alertsToDelete.forEach(async (alert) => { + try { + await sdk.ok(sdk.delete_alert(alert.id)) + console.log(`Deleted Alert ${alert.id}`) + } catch (e) { + throw new Error( + `There was an error trying to delete alert ${alert.id}. Full message here: ${e}` + ) + } + }) + return { alertsDeleted: alertsToDelete.length, user: userId } + } else { + console.log(`User ${userId}, has no alerts saved. Aborting.`) + return { alertsDeleted: 0, user: userId } + } + } catch (e) { + throw new Error( + `There was an error fetching all alerts for a user ${userId}. Make sure a user by that ID exists OR that you have permissions to make this call.` + ) + } +} + +// Example +// bulkDeleteAlerts(938) diff --git a/examples/typescript/createSlackAlert.ts b/examples/typescript/createSlackAlert.ts new file mode 100644 index 000000000..654457405 --- /dev/null +++ b/examples/typescript/createSlackAlert.ts @@ -0,0 +1,161 @@ +import { LookerNodeSDK } from '@looker/sdk-node' +import { ComparisonType, DestinationType } from '@looker/sdk' + +/** +Creating an Alert to Send to Slack +Currently Leverages the Default Workspace of the Instance +**/ + +/** +Pulls from Environment Variables, see env sample in sdk-codegen root directory +An ini file can be used as well. See ./downloadDashboard.ts file for an example of this approach. + */ +const sdk = LookerNodeSDK.init40() + +/** +Below are some sample variables to mock creating an alert + */ +const integration = '1::slack_app' +const channelType = 'users' +const channelSearch = '@test.user' +const dashboardElementId = 873 + +/** +Fetches the default slack workspace and ID for the Slack Destination. Can be either a user or channel depending on Function input. Then creates an alert to slack with a hard coded config. +required variables: +* @param {string} integrationId: the action integration id for your instances' Slack App +* @param {string} channelType: either "users" to send to users in your slack workspace OR "channel" to send to channels in your slack workspace +* @param {string} channelSearch: search string representing channel name OR user name in Slack workspace +* @param {number} dashboardElementId: id of the dashboard element to set the alert on +* @returns {Promise>}: returns response object with owner id of alert and the alert id +**/ + +const createSlackAlert = async ( + integrationId: string, + channelSearch: string, + channelType: string, + dashboardElementId: number +) => { + const slackDestinationObject = {} + let formResponse + slackDestinationObject.channelType = channelType + // programmatically retrieve workspace id and channel id for alert creation + try { + formResponse = await sdk.ok( + sdk.fetch_integration_form(integrationId, { channelType: channelType }) + ) + } catch (e) { + throw new Error(`Error Fetching Action Form. Full message here: ${e}.`) + } + if (formResponse.fields.length > 0) { + // first create key for workspace to be used + if (formResponse.fields[0].name === 'workspace') { + slackDestinationObject.workspace = formResponse.fields[0].default + } else { + const workspaceObject = formResponse.fields.filter( + (value) => value.name === 'workspace' + ) + slackDestinationObject.workspace = workspaceObject[0].default + } + // filtered array for given channelSearch string, if multiple channels or users OR resulting array is 0 throw error + const getChannel = formResponse.fields.filter( + (channelForm) => channelForm.name === 'channel' + ) + const resultChannel = getChannel[0].options.filter( + (channel) => channel.label === channelSearch + ) + if (resultChannel.length === 0) + throw new Error( + `There are no users or channels that match ${channelSearch}.` + ) + if (resultChannel.length > 1) + throw new Error( + `The ${channelSearch} returned multiple ${ + channelType === 'users' ? 'users' : 'channels' + }. Please search for a specific id.` + ) + // return just the id to be used later + const { name } = resultChannel[0] + slackDestinationObject.channel = name + console.log(slackDestinationObject) + const data = await createAlert( + dashboardElementId, + JSON.stringify(slackDestinationObject), + integrationId + ) + if (data.id) { + return { owner_id: data.owner_id, alert: data.id } + } + } + throw new Error( + `No Fields exist for ${integrationId} given ${channelType} search. Perhaps your user doesn't have the appropriate permissions to this workspace` + ) +} + +/** +Configures the alert body/configuration to be passed to the create alert endpoint, in this example most of the attributes are hard coded, but this could be updated so they are passed dynamically +* @param {number} dashboardElementId: id of the dashboard element to set the alert on +* @param {string} formParams: json string containing workspace id, channel type (user or channel) and id of destination +* @param {string} integrationId: the action integration id for your instances' Slack App +* @returns {IWriteAlert}: returns alert body object +**/ + +const alertConfig = ( + dashbordElementId: number, + formParams: string, + integrationId: string +) => { + // example config + return { + comparison_type: ComparisonType.GREATER_THAN, + cron: '0 5 1 * *', + custom_title: 'Test Test 00000', + dashboard_element_id: dashbordElementId, + destinations: [ + { + destination_type: DestinationType.ACTION_HUB, + action_hub_integration_id: integrationId, + action_hub_form_params_json: formParams, + }, + ], + field: { + title: 'Any History', + name: 'history.count', + }, + is_disabled: false, + is_public: true, + owner_id: 938, + threshold: 10000, + } +} + +/** +Fetches the default slack workspace and ID for the Slack Destination. Can be either a user or channel depending on Function input. +required variables: +* @param {number} dashboardElementId: id of the dashboard element to set the alert on +* @param {string} formParams: json string containing workspace id, channel type (user or channel) and id of destination +* @param {string} integrationId: the action integration id for your instances' Slack App +* @returns {Promise}: returns a promise of IAlert (created alert response body) +**/ +const createAlert = async ( + dashboardElementId: number, + formParams: string, + integrationId: string +) => { + try { + const alertResponse = await sdk.ok( + sdk.create_alert( + alertConfig(dashboardElementId, formParams, integrationId) + ) + ) + console.log(alertResponse) + return alertResponse + } catch (e) { + throw new Error( + `There was an error creating the alert. Full message here: ${e}` + ) + } +} + +// Example +// createSlackAlert(integration, channelSearch, channelType, dashboardElementId)