@atomist/automation-client
Version:
Atomist API for software low-level client
303 lines • 10.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const flat_1 = require("flat");
const _ = require("lodash");
const metadataReading_1 = require("../../internal/metadata/metadataReading");
const MessageClientSupport_1 = require("./MessageClientSupport");
/**
* Message Destination for the Web App.
*/
class WebDestination {
constructor() {
this.userAgent = WebDestination.WEB_USER_AGENT;
}
}
exports.WebDestination = WebDestination;
WebDestination.WEB_USER_AGENT = "web";
/**
* Message Destination for the Web App.
*/
class SourceDestination {
constructor(source, system) {
this.source = source;
this.system = system;
this.userAgent = SourceDestination.SOURCE_USER_AGENT;
}
}
exports.SourceDestination = SourceDestination;
SourceDestination.SOURCE_USER_AGENT = "source";
function addressWeb() {
return new WebDestination();
}
exports.addressWeb = addressWeb;
/**
* Message Destination for Slack.
*/
class SlackDestination {
/**
* Create a Destination suitable for sending messages to a Slack
* workspace.
*
* @param team Slack workspace ID, which typically starts with the
* letter "T", consists of numbers and upper-case letters,
* and is nine characters long. It can be obtained by
* sending the Atomist Slack bot the message "team".
* @return {SlackDestination} A MessageClient suitable for sending messages.
*/
constructor(team) {
this.team = team;
this.userAgent = SlackDestination.SLACK_USER_AGENT;
/** Slack user names to send message to. */
this.users = [];
/** Slack channel names to send message to. */
this.channels = [];
}
/**
* Address user by Slack user name. This method appends the
* provided user to a list of users that will be sent the message
* via this Destination. In other words, calling repeatedly with
* differing Slack user names results in the message being sent to
* all such users.
*
* @param {string} user Slack user name.
* @returns {SlackDestination} MessageClient Destination that results
* in message being send to user.
*/
addressUser(user) {
this.users.push(user);
return this;
}
/**
* Address channel by Slack channel name. This method appends the
* provided channel to a list of channels that will be sent the
* message via this Destination. In other words, calling
* repeatedly with differing Slack channel names results in the
* message being sent to all such channels.
*
* @param {string} channel Slack channel name.
* @returns {SlackDestination} MessageClient Destination that results
* in message being send to channel.
*/
addressChannel(channel) {
this.channels.push(channel);
return this;
}
}
exports.SlackDestination = SlackDestination;
SlackDestination.SLACK_USER_AGENT = "slack";
/**
* Shortcut for creating a SlackDestination which addresses the given
* users.
*
* @param {string} team Slack workspace ID to create Destination for.
* @param {string} users Slack user names to send message to.
* @returns {SlackDestination} MessageClient Destination to pass to `send`.
*/
function addressSlackUsers(team, ...users) {
const sd = new SlackDestination(team);
users.forEach(u => sd.addressUser(u));
return sd;
}
exports.addressSlackUsers = addressSlackUsers;
/**
* Shortcut for creating a SlackDestination which addresses the given
* users in all Slack teams connected to the context.
*
* @param {HandlerContext} ctx Handler context as passed to the Handler handle method.
* @param {string} users Slack user names to send message to.
* @returns {Promise<SlackDestination>} MessageClient Destination to pass to `send`.
*/
function addressSlackUsersFromContext(ctx, ...users) {
return MessageClientSupport_1.lookupChatTeam(ctx.graphClient)
.then(chatTeamId => {
return addressSlackUsers(chatTeamId, ...users);
});
}
exports.addressSlackUsersFromContext = addressSlackUsersFromContext;
/**
* Shortcut for creating a SlackDestination which addresses the given
* channels.
*
* @param {string} team Slack workspace ID to create Destination for.
* @param {string} channels Slack channel names to send messages to.
* @returns {SlackDestination} MessageClient Destination to pass to `send`.
*/
function addressSlackChannels(team, ...channels) {
const sd = new SlackDestination(team);
channels.forEach(c => sd.addressChannel(c));
return sd;
}
exports.addressSlackChannels = addressSlackChannels;
/**
* Shortcut for creating a SlackDestination which addresses the given
* channels in all Slack teams connected to the context.
*
* @param {HandlerContext} ctx Handler context as passed to the Handler handle method.
* @param {string} channels Slack channel names to send messages to.
* @returns {Promise<SlackDestination>} MessageClient Destination to pass to `send`.
*/
function addressSlackChannelsFromContext(ctx, ...channels) {
return MessageClientSupport_1.lookupChatTeam(ctx.graphClient)
.then(chatTeamId => {
return addressSlackChannels(chatTeamId, ...channels);
});
}
exports.addressSlackChannelsFromContext = addressSlackChannelsFromContext;
/**
* Message Destination for Custom Event types.
*/
class CustomEventDestination {
/**
* Constructur returning a Destination for creating an instance of
* the Custom Event type `rootType`.
*/
constructor(rootType) {
this.rootType = rootType;
this.userAgent = CustomEventDestination.INGESTER_USER_AGENT;
}
}
exports.CustomEventDestination = CustomEventDestination;
CustomEventDestination.INGESTER_USER_AGENT = "ingester";
/**
* Helper wrapping the constructor for CustomEventDestination.
*/
function addressEvent(rootType) {
return new CustomEventDestination(rootType);
}
exports.addressEvent = addressEvent;
/** Valid MessageClient types. */
exports.MessageMimeTypes = {
SLACK_JSON: "application/x-atomist-slack+json",
SLACK_FILE_JSON: "application/x-atomist-slack-file+json",
PLAIN_TEXT: "text/plain",
APPLICATION_JSON: "application/json",
};
/**
* Create a slack button that invokes a command handler.
*/
function buttonForCommand(buttonSpec, command, parameters = {}) {
const cmd = commandName(command);
const params = mergeParameters(command, parameters);
const id = cmd.toLocaleLowerCase();
const action = chatButtonFrom(buttonSpec, { id });
action.command = {
id,
name: cmd,
parameters: params,
};
return action;
}
exports.buttonForCommand = buttonForCommand;
/**
* Create a Slack menu that invokes a command handler.
*/
function menuForCommand(selectSpec, command, parameterName, parameters = {}) {
const cmd = commandName(command);
const params = mergeParameters(command, parameters);
const id = cmd.toLocaleLowerCase();
const action = chatMenuFrom(selectSpec, { id, parameterName });
action.command = {
id,
name: cmd,
parameters: params,
parameterName,
};
return action;
}
exports.menuForCommand = menuForCommand;
/**
* Check if the object is a valid Slack message.
*/
function isSlackMessage(object) {
return !!object && (object.text || object.attachments) && !object.content;
}
exports.isSlackMessage = isSlackMessage;
/**
* Check if the object is a valid Slack file message, i.e., a snippet.
*/
function isFileMessage(object) {
return !!object && !object.length && object.content;
}
exports.isFileMessage = isFileMessage;
/**
* Extract command name from the argument.
*/
function commandName(command) {
try {
if (typeof command === "string") {
return command;
}
else if (typeof command === "function") {
return command.prototype.constructor.name;
}
else {
return metadataReading_1.metadataFromInstance(command).name;
}
}
catch (e) {
throw new Error("Unable to determine the name of this command. " +
"Please pass the name as a string or an instance of the command");
}
}
exports.commandName = commandName;
/**
* Merge the provided parameters into any parameters provided as
* command object instance variables.
*/
function mergeParameters(command, parameters) {
// Reuse parameters defined on the instance
if (typeof command !== "string" && typeof command !== "function") {
const newParameters = _.merge(command, parameters);
return flat_1.flatten(newParameters);
}
return flat_1.flatten(parameters);
}
exports.mergeParameters = mergeParameters;
function chatButtonFrom(action, command) {
if (!command.id) {
throw new Error(`Please provide a valid non-empty command id`);
}
const button = {
text: action.text,
type: "button",
name: `automation-command::${command.id}`,
};
_.forOwn(action, (v, k) => {
button[k] = v;
});
return button;
}
function chatMenuFrom(action, command) {
if (!command.id) {
throw new Error("SelectableIdentifiableInstruction must have id set");
}
if (!command.parameterName) {
throw new Error("SelectableIdentifiableInstruction must have parameterName set");
}
const select = {
text: action.text,
type: "select",
name: `automation-command::${command.id}`,
};
if (typeof action.options === "string") {
select.data_source = action.options;
}
else if (action.options.length > 0) {
const first = action.options[0];
if (first.value) {
// then it's normal options
select.options = action.options;
}
else {
// then it's option groups
select.option_groups = action.options;
}
}
_.forOwn(action, (v, k) => {
if (k !== "options") {
select[k] = v;
}
});
return select;
}
//# sourceMappingURL=MessageClient.js.map