Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(typescript-sdk-examples): Adding some alert endpoint examples for sdkv4.0 #977

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
8 changes: 6 additions & 2 deletions examples/typescript/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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 `<x>`" 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

| &nbsp;&nbsp;Example&nbsp;Topic&nbsp;&nbsp; | 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

Expand Down
58 changes: 58 additions & 0 deletions examples/typescript/bulkDeleteAlerts.ts
Original file line number Diff line number Diff line change
@@ -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<string | string>}: 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)
161 changes: 161 additions & 0 deletions examples/typescript/createSlackAlert.ts
Original file line number Diff line number Diff line change
@@ -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<Record<string, number>>}: 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<IAlert>}: 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)