Typeahead fields for Slack Users

Sym can prompt users to select one or many Slack users when they make a request.

Overview

Sym workflows support various types of prompts, which are presented to users in a modal form when they make a request. This guide covers two of those types, slack_user and slack_user_list, and how to utilize them in the SDK.

The slack_user prompt field is, as the name suggests, a dropdown that allows for selecting a single user in your Slack workspace. The slack_user_list prompt field likewise allows for selecting one or more users. In both cases, the dropdown options are automatically populated with Slack data for easy typeahead.

Configuring the Flow

To use the slack_user or slack_user_list prompt fields, simply add it to the params block of a sym_flow resource in Terraform, using slack_user or slack_user_list as the type of the prompt field:

params {
  strategy_id = sym_strategy.this.id
    
  prompt_field {
    name = "reason"
    type = "string"
    required = true
  }
    
  prompt_field {
    name = "approver"
    type = "slack_user"
    required = true
  }
  
  prompt_field {
    name = "peers"
    type = "slack_user_list"
    required = true
}

🚧

Some prompt_field options do not apply

Because slack_user and slack_user_list dropdowns are automatically populated by Slack with users in your Slack workspace, the allowed_values, default, and prefetch options for the prompt_field do not apply; specifying them will result in an error.

The required option can be combined with the slack_user and slack_user_list prompt field types. If required is true, then slack_user prompt fields must have a single user selected, and slack_user_list prompt fields must have at least one user selected. If required is false, then slack_user prompt fields may have zero or one users selected, and slack_user_list prompt fields may have zero or more users selected.

Accessing in the SDK

The selection of a slack_user or slack_user_list dropdown is exposed in the SDK via the event.payload.fields dictionary, as with other field data. For instance, to access the "approver" field from the above example, one would use event.payload.fields["approver"].

For slack_user fields, the SDK will contain a single User object, while slack_user_list fields will contain a list of User objects. These Users are automatically populated based on the mapping of Slack identities to users in your Sym organization (see Managing User Identity for details).

If a slack_user prompt field is marked as required = false and no user is selected, its corresponding value in evt.payload.fields will be None. If a slack_user_list prompt field is marked as required = false and no users are selected, the corresponding value in evt.payload.fields will be an empty list.

Examples

Send requests directly to the user's selected approver for review:

from sym.sdk.annotations import reducer
from sym.sdk.integrations import slack


@reducer
def get_approvers(evt):
    approver = evt.payload.fields["approver"]
    return slack.user(approver)

Or, still send the request to a central channel, but also send a message mentioning the selected approver:

from sym.sdk.annotations import reducer, hook
from sym.sdk.integrations import slack


@reducer
def get_approvers(evt):
    return slack.channel("#sym-access", allow_self=False)


@hook
def on_request(evt):
    approver = evt.payload.fields["approver"]
    slack.send_message(slack.channel("#sym-access"), f"Hey {slack.mention(approver)}, you have a new access request!")

Require that the user must not select themselves in the "peers" list, but if a request is approved, group DM the users in the "peers" list to ask them to observe the escalated access session:

from sym.sdk import ApprovalTemplate
from sym.sdk.annotations import reducer, hook
from sym.sdk.integrations import slack


@reducer
def get_approvers(evt):
    return slack.channel("#sym-access", allow_self=False)


@hook
def on_request(evt):
    peers = evt.payload.fields["peers"]
    if evt.user in peers:
        return ApprovalTemplate.ignore(message="You cannot include yourself in the peer list.")


@hook
def after_approve(evt):
    requester = evt.get_actor("request")
    slack.send_message(
        slack.group(evt.payload.fields["peers"]),
        f"You have been asked to observe {slack.mention(requester)}'s escalated access.",
    )