Connect Bot to Box
Connect Bot to Box
We're now handling and processing events coming from Slack, then obtaining all information needed to connect with Box users and groups. We now need to connect that functionality to Box functions.
In this step we'll expand several functions from the last step to incorporate new Box features.
- Instantiate a Box client.
- Add a Box user to a Box group.
- Remove a Box user from a Box group.
- Fetch a Box group ID from a group name.
- Add content that is shared to a group.
Instantiate a Box Client
To make calls to the Box APIs, you'll first need to set up a Box client.
Within process.js
, replace the // INSTANTIATE BOX CLIENT
comment at the top
with the following.
const boxConfig = require("./boxConfig.json");
const sdk = box.getPreconfiguredInstance(boxConfig);
const client = sdk.getAppAuthClient("enterprise");
The boxConfig
assignment line will use the boxConfig.json
file you
downloaded from your Box app at the end of step 2. The sample above is
assuming that you have it stored in the same folder as process.js
. If that's
not the case, change the path to point to where your boxConfig.json
file is,
and what it may be named.
The last client
assignment line is creating a Box client object which may be
used to make API calls. At this point it is scoped to the
service account of the application, and not a specific user.
Within Application.java
, replace the // INSTANTIATE BOX CLIENT
comment
within the processEvent
method with the following.
this.fileReader = new FileReader("boxConfig.json");
this.boxConfig = BoxConfig.readFrom(fileReader);
this.boxAPI = BoxDeveloperEditionAPIConnection.getAppEnterpriseConnection(boxConfig);
The boxConfig
assignment line will use the boxConfig.json
file you
downloaded from your Box app at the end of step 2. The sample above is
assuming that you have it stored at the root of the Java project. If that's
not the case, change the path in the fileReader
assignment to point to where
your boxConfig.json
file is, and what it may be named.
The last boxAPI
assignment line is creating a Box client object which may be
used to make API calls. At this point it is scoped to the
service account of the application, and not a specific user.
Add a Box user to a group
Let's add a function that adds a Box user to a group. When a bot is added to a channel and needs to create a Box group with all users of the channel, or when a single user joins the channel after that action, this function will perform that task.
Replace the addGroupUser
function with the following.
function addGroupUser(groupId, email) {
client.enterprise.getUsers({ filter_term: email }).then((users) => {
if (users.entries.length > 0) {
const userId = users.entries[0].id;
const groupRole = client.groups.userRoles.MEMBER;
client.groups
.addUser(groupId, userId, { role: groupRole })
.then((membership) => {
if (membership.id) {
console.log(`Member added with membership ID: ${membership.id}`);
} else {
console.log(`Member not added`);
}
})
.catch(function (err) {
console.log(err.response.body);
});
} else {
console.log("No Box user found to add to group");
}
});
}
Replace the addGroupUser
method with the following.
public void addGroupUser(String groupId, String userEmail) {
Iterable<BoxUser.Info> users = BoxUser.getAllEnterpriseUsers(this.boxAPI, userEmail);
for (BoxUser.Info user : users) {
if (user.getLogin().toUpperCase().equals(userEmail.toUpperCase())) {
try {
BoxGroup group = new BoxGroup(boxAPI, groupId);
BoxUser boxUser = new BoxUser(this.boxAPI, user.getID());
BoxGroupMembership.Info groupMembershipInfo = group.addMembership(boxUser);
} catch (Exception ex) {
System.err.println("User already present");
}
}
}
}
Since we're matching a Slack user to a Box user via their email address, we first find a matching Box user using the Slack profile email. If found, a call is made to add that user to the channel group. The group was created when the bot was first added.
Remove a Box user to a group
When a user leaves or is removed from a Slack channel, we also want to remove them from the Box group so that they can no longer access the shared group content.
Replace the removeGroupUser
function with the following.
function removeGroupUser(groupId, email) {
client.groups.getMemberships(groupId).then(memberships => {
for (let i = 0; i < memberships.entries.length; i++) {
if (memberships.entries[i].user.login === email) {
client.groups
.removeMembership(memberships.entries[i].id)
.then(() => {
console.log('Group user removed')
});
break;
}
}
});
}
Replace the removeGroupUser
method with the following.
public void removeGroupUser(String groupId, String userEmail) {
BoxGroup boxGroup = new BoxGroup(this.boxAPI, groupId);
Iterable<BoxGroupMembership.Info> memberships = boxGroup.getAllMemberships();
for (BoxGroupMembership.Info membershipInfo : memberships) {
if (membershipInfo.getUser().getLogin().toUpperCase().equals(userEmail.toUpperCase())) {
BoxGroupMembership membership = new BoxGroupMembership(this.boxAPI, membershipInfo.getID());
membership.delete();
}
}
}
This code will take the group ID, which will be the Slack channel ID, and get all members of the group. If a matching member is found for the person that left the Slack channel, based on email address, that person is removed from the group using their membership ID.
Fetch a Box group ID for a group name
The next Box function we need has two main purposes.
- Return the Box group ID of an existing group.
- If a group doesn't exist, create the Box group and return the ID.
Replace the getGroupId
function with the following.
function getGroupId(groupName, callback) {
client.groups.getAll().then((groups) => {
const group = groups.entries.filter((g) => g.name === groupName)[0];
if (!group) {
client.groups
.create(groupName, {
description: "Slack channel collaboration group",
invitability_level: "all_managed_users",
})
.then((group) => {
callback(group.id);
});
} else {
callback(group.id);
}
});
}
Replace the getGroupId
method with the following.
public String getGroupId(String groupName) {
String groupId = new String();
Iterable<BoxGroup.Info> groups = BoxGroup.getAllGroups(this.boxAPI);
for (BoxGroup.Info groupInfo : groups) {
if (groupInfo.getName().toUpperCase().equals(groupName)) {
groupId = groupInfo.getID();
}
}
if (groupId.isEmpty()) {
BoxGroup.Info groupInfo = BoxGroup.createGroup(boxAPI, groupName);
groupId = groupInfo.getID();
}
return groupId;
}
The code fetches all the groups in the enterprise, and then tries to match the Slack channel ID to the group name. If any of the groups matches, the group ID is returned.
If there are no matches, a new Box group is created and the ID of the group is returned for use. The group will be named after the Slack channel ID since that is a constant that is returned with both slash commands and user events, making it easier to lookup without additional functions.
Add shared content to a group
Finally, the main purpose of our whole application is to allow users to share files and folders from their own Box accounts with everyone else in the group.
Building upon all previous functionality, the following function performs that task.
Replace the processContent
function with the following.
function processContent(user, channel, itemType, itemId) {
getGroupId(channel, function (groupId) {
const email = user.profile.email;
client.enterprise.getUsers({ filter_term: email }).then((users) => {
if (users.entries.length > 0) {
client.asUser(users.entries[0].id);
const collabRole = client.collaborationRoles.VIEWER;
const collabOptions = { type: itemType };
client.collaborations
.createWithGroupID(groupId, itemId, collabRole, collabOptions)
.then((collaboration) => {
console.log(
`Content added with collaboration ID ${collaboration.id}`
);
})
.catch(function (err) {
console.log(
util.inspect(err.response.body, {
showHidden: false,
depth: null,
})
);
});
}
});
});
}
Replace the processContent
method with the following.
public void processContent(JSONObject userResponse, String channel, String fType, String fId) {
String groupId = getGroupId(channel);
JSONObject userObj = (JSONObject) userResponse.get("user");
JSONObject userProfile = (JSONObject) userObj.get("profile");
String userEmail = (String) userProfile.get("email");
Iterable<BoxUser.Info> users = BoxUser.getAllEnterpriseUsers(this.boxAPI, userEmail);
for (BoxUser.Info user : users) {
if (user.getLogin().toUpperCase().equals(userEmail.toUpperCase())) {
String uid = user.getID();
boxAPI.asUser(uid);
BoxCollaborator collabGroup = new BoxGroup(boxAPI, groupId);
try {
if (fType.equals("file")) {
BoxFile file = new BoxFile(boxAPI, fId);
file.collaborate(collabGroup, BoxCollaboration.Role.VIEWER, false, false);
} else if (fType.equals("folder")) {
BoxFolder folder = new BoxFolder(boxAPI, fId);
folder.collaborate(collabGroup, BoxCollaboration.Role.VIEWER);
}
} catch (Exception ex) {
System.err.println("Collaboration failed");
}
boxAPI.asSelf();
}
}
}
The code starts by capturing the Box group ID for the Slack channel, which is where content will be shared to.
Since we want to share files and folders from the Box account of the person who sent the slash command, we next capture their Box user profile based on their email address.
Lastly, we make a call to collaborate content with the group via the group ID.
Summary
- You've instantiated a Box client
- You've created Box group user add and remove functions.
- You've created a function to share content with the group.