Added more tests and a way to send responses to the user without going through hubot

This commit is contained in:
Melanie Mendoza 2018-08-13 17:42:19 -07:00
Родитель a3871df3c9
Коммит 9007425105
7 изменённых файлов: 384 добавлений и 311 удалений

Просмотреть файл

@ -43,6 +43,15 @@ class TextMiddleware extends BaseMiddleware
return message
# Constructs a text message response to indicate an error to the user in the
# message channel they are using
constructErrorResponse: (activity, text) ->
payload =
type: 'message'
text: "#{text}"
address: activity?.address
return payload
# Indicates that the authorization isn't supported for this middleware
supportsAuth: () ->
return false

Просмотреть файл

@ -23,7 +23,7 @@ class BotFrameworkAdapter extends Adapter
constructor: (robot) ->
super robot
@appId = process.env.BOTBUILDER_APP_ID
@appPassword = process.env.BOTBUILDER_APP_PASSWORD
@appPassword = process.env.BOTBUILDER_APP_PASSWORD
@endpoint = process.env.BOTBUILDER_ENDPOINT || "/api/messages"
@enableAuth = process.env.HUBOT_TEAMS_ENABLE_AUTH || 'false'
robot.logger.info "#{LogPrefix} Adapter loaded. Using appId #{@appId}"
@ -49,12 +49,21 @@ class BotFrameworkAdapter extends Adapter
@connector.onEvent (events, cb) => @onBotEvents events, cb
@connector.onInvoke (events, cb) => @sendTextToHubot events, cb
@connector.onInvoke (events, cb) => @menuCardInvoke events, cb
sendTextToHubot: (invokeEvent, cb) ->
invokeEvent.text = invokeEvent.value.hubotMessage
delete invokeEvent.value
@handleActivity(invokeEvent)
# If the command for the invoke doesn't need user input, handle the command
# normally. If it does need user input, return a prompt for user input.
menuCardInvoke: (invokeEvent, cb) ->
middleware = @using(invokeEvent.source)
payload = middleware.maybeConstructUserInputPrompt(invokeEvent)
if payload == null
invokeEvent.text = invokeEvent.value.hubotMessage
delete invokeEvent.value
@handleActivity(invokeEvent)
else
@sendPayload(@robot, payload)
return
using: (name) ->
MiddlewareClass = Middleware.middlewareFor(name)
@ -68,7 +77,8 @@ class BotFrameworkAdapter extends Adapter
handleActivity: (activity) ->
console.log("handle activity")
console.log(activity)
@robot.logger.info "#{LogPrefix} Handling activity Channel: #{activity.source}; type: #{activity.type}"
@robot.logger.info "#{LogPrefix} Handling activity Channel:
#{activity.source}; type: #{activity.type}"
# Construct the middleware
middleware = @using(activity.source)
@ -79,17 +89,32 @@ class BotFrameworkAdapter extends Adapter
# the text middleware, otherwise use the Teams middleware
if not middleware.supportsAuth()
if @enableAuth == 'true'
@robot.logger.info "#{LogPrefix} Message source doesn't support authorization"
activity.text = "hubot return source authorization not supported error"
# This redundant section is included if we do the short circuit sendPayload thing
event = middleware.toReceivable activity
if event?
@robot.receive event
# @robot.logger.info "#{LogPrefix} Message source doesn't support authorization"
# activity.text = "hubot return source authorization not supported error"
# # This redundant section is included if we do the short circuit sendPayload thing
# event = middleware.toReceivable activity
# if event?
# @robot.receive event
# A payload has at least type and address
@robot.logger.info "#{LogPrefix} Authorization isn\'t supported for the channel"
text = "Authorization isn't supported for the channel"
payload = middleware.constructErrorResponse(activity, text)
@sendPayload(@robot, payload)
return
else
event = middleware.toReceivable activity
if event?
@robot.receive event
else
# Check for clicks from the dropdown menu
if activity?.value?.needsUserInput == 'true'
payload = middleware.maybeConstructUserInputPrompt(activity)
if payload != null
@sendPayload(@robot, payload)
return
activity.text = activity.value.hubotMessage
delete activity.value
# Construct a TeamsChatConnector to pass to toReceivable
teamsConnector = new BotBuilderTeams.TeamsChatConnector {
appId: @robot.adapter.appId
@ -99,43 +124,18 @@ class BotFrameworkAdapter extends Adapter
if event?
console.log("********************************")
console.log(event)
# If unauthorized error occurred, overwrite the text
if unauthorizedError
event.text = "hubot return unauthorized user error"
@robot.logger.info "#{LogPrefix} Unauthorized user, sending error"
text = "You are not authorized to send commands to hubot.
To gain access, talk to your admins:"
payload = middleware.constructErrorResponse(activity, text, true)
@sendPayload(@robot, payload)
return
@robot.receive event
# # Return an error to the user if authorization is enabled and the message
# # is either from a channel that doesn't support auth or if the user who sent the
# # message isn't authorized
# authorizedUsers = @robot.brain.get("authorizedUsers")
# aadObjectId = activity?.address?.user?.aadObjectId
# if @enableAuth == 'true'
# if middleware.supportsAuth()
# if aadObjectId is undefined or authorizedUsers[aadObjectId] is undefined
# @robot.logger.info "#{LogPrefix} Unauthorized user; returning error"
# activity.text = "hubot return unauthorized user error"
# # Change this to make a call to a middleware function that returns
# # a payload with the error text to return
# else
# @robot.logger.info "#{LogPrefix} Message source doesn't support authorization"
# activity.text = "hubot return source authorization not supported error"
# # If authorization isn't supported by the activity source, use
# # the text middleware, otherwise use the Teams middleware
# if not middleware.supportsAuth()
# event = middleware.toReceivable activity
# if event?
# @robot.receive event
# else
# # Construct a TeamsChatConnector to pass to toReceivable
# teamsConnector = new BotBuilderTeams.TeamsChatConnector {
# appId: @robot.adapter.appId
# appPassword: @robot.adapter.appPassword
# }
# middleware.toReceivable activity, teamsConnector, (event) =>
# if event?
# @robot.receive event
send: (context, messages...) ->
@robot.logger.info "#{LogPrefix} send"
@reply context, messages...

Просмотреть файл

@ -3,12 +3,12 @@
HubotQueryParts = require './hubot-query-parts'
maybeConstructCard = (response, query) ->
maybeConstructResponseCard = (response, query) ->
# Check if the response is from a list commands follow up button press.
# If so, construct the needed input card and return it
index = query.search("generate input card")
if (index != -1)
return constructMenuInputCard(query.replace("generate input card", ""), response.text)
# index = query.search("generate input card")
# if (index != -1)
# return maybeConstructMenuInputCard(response.text)
# Check if response.text matches one of the reg exps in the LUT
for regex of HubotResponseCards
@ -20,10 +20,19 @@ maybeConstructCard = (response, query) ->
return card
return null
# Constructs an input card
constructMenuInputCard = (query, text) ->
card = initializeAdaptiveCard(query)
queryParts = HubotQueryParts[text]
# Constructs an input card if needed or returns null if the
# query doesn't need user input
maybeConstructMenuInputCard = (query) ->
queryParts = HubotQueryParts[query]
# Check if the query needs a user input card
console.log(queryParts.inputParts is undefined)
console.log(queryParts.inputParts == undefined)
if queryParts.inputParts is undefined
return null
shortQuery = constructShortQuery(query)
card = initializeAdaptiveCard(shortQuery)
# Create the input fields of the sub card
for i in [0 ... queryParts.inputParts.length]
@ -38,7 +47,8 @@ constructMenuInputCard = (query, text) ->
# Create selector
if index != -1
card.content.body.push(addSelector(query, inputPart.substring(index + 1), query + " - input" + "#{i}"))
card.content.body.push(addSelector(query, inputPart.substring(index + 1),
query + " - input" + "#{i}"))
# Create text input
else
card.content.body.push(addTextInput(query + " - input" + "#{i}", inputPart))
@ -126,13 +136,7 @@ addTextInput = (id, inputPart) ->
getFollowUpButtons = (query, regex) ->
actions = []
for followUpQuery in HubotResponseCards[regex]
# Create a short version of the command by including only the
# start of the command to the first user input marked by ( or <
shortQueryEnd = followUpQuery.search(new RegExp("[(<]"))
if shortQueryEnd == -1
shortQueryEnd = followUpQuery.length
shortQuery = followUpQuery.substring(0, shortQueryEnd)
shortQuery = constructShortQuery(followUpQuery)
action = {
'title': shortQuery
}
@ -246,6 +250,15 @@ appendCardActions = (card1, card2) ->
return card1
# Create a short version of the command by including only the
# start of the command to the first user input marked by ( or <
constructShortQuery = (query) ->
shortQueryEnd = query.search(new RegExp("[(<]"))
if shortQueryEnd == -1
shortQueryEnd = query.length
shortQuery = query.substring(0, shortQueryEnd)
return shortQuery.trim()
# HubotResponseCards maps from regex's of hubot queries to an array of follow up hubot
# queries stored as strings
HubotResponseCards = {
@ -285,7 +298,8 @@ HubotResponseCards = {
}
module.exports = {
maybeConstructCard,
maybeConstructResponseCard,
maybeConstructMenuInputCard,
appendCardBody,
appendCardActions
}

Просмотреть файл

@ -25,7 +25,7 @@
BotBuilder = require 'botbuilder'
BotBuilderTeams = require 'botbuilder-teams'
HubotResponseCards = require './hubot-response-cards'
#MicrosoftGraph = require '@microsoft/microsoft-graph-client'
HubotQueryParts = require './hubot-query-parts'
{ Robot, TextMessage, Message, User } = require 'hubot'
{ BaseMiddleware, registerMiddleware } = require './adapter-middleware'
LogPrefix = "hubot-msteams:"
@ -41,7 +41,8 @@ class MicrosoftTeamsMiddleware extends BaseMiddleware
@allowedTenants = []
if process.env.HUBOT_OFFICE365_TENANT_FILTER?
@allowedTenants = process.env.HUBOT_OFFICE365_TENANT_FILTER.split(",")
@robot.logger.info("#{LogPrefix} Restricting tenants to #{JSON.stringify(@allowedTenants)}")
@robot.logger.info("#{LogPrefix} Restricting tenants to \
#{JSON.stringify(@allowedTenants)}")
toReceivable: (activity, teamsConnector, authEnabled, cb) ->
@robot.logger.info "#{LogPrefix} toReceivable"
@ -54,45 +55,43 @@ class MicrosoftTeamsMiddleware extends BaseMiddleware
# Get the user
user = getUser(activity)
user = @robot.brain.userForId(user.id, user)
console.log("++++++++++++++++++++++++++++++++++++++++++++++")
console.log(user)
# We don't want to save the activity or room in the brain since its something that changes per chat.
# We don't want to save the activity or room in the brain since its
# something that changes per chat.
user.activity = activity
user.room = getRoomId(activity)
if activity.type != 'message' && activity.type != 'invoke'
return new Message(user)
else
# Fetch the roster of members to do authorization based on UPN
teamsConnector.fetchMembers activity?.address?.serviceUrl, activity?.address?.conversation?.id, (err, chatMembers) =>
if err
return
console.log("==========================================")
console.log(chatMembers)
# Set the unauthorizedError to true if auth is enabled and the user who sent
# the message is not authorized
unauthorizedError = false
if authEnabled
authorizedUsers = @robot.brain.get("authorizedUsers")
console.log("---------------")
console.log(chatMembers[0].userPrincipalName)
# Get the sender's UPN
senderUPN = getSenderUPN(user, chatMembers)
console.log(senderUPN)
if senderUPN is undefined or authorizedUsers[senderUPN] is undefined
@robot.logger.info "#{LogPrefix} Unauthorized user; returning error"
unauthorizedError = true
# activity.text = "hubot return unauthorized user error"
# Change this to make a call to a middleware function that returns
# a payload with the error text to return
# Add the sender's UPN to user
user.userPrincipalName = senderUPN
# Fetch the roster of members to do authorization based on UPN
teamsConnector.fetchMembers activity?.address?.serviceUrl, \
activity?.address?.conversation?.id, (err, chatMembers) =>
if err
console.log("YUP AN ERR")
return
activity = fixActivityForHubot(activity, @robot, chatMembers)
message = new TextMessage(user, activity.text, activity.address.id)
cb(message, unauthorizedError)
# Set the unauthorizedError to true if auth is enabled and the user who sent
# the message is not authorized
unauthorizedError = false
if authEnabled
authorizedUsers = @robot.brain.get("authorizedUsers")
# Get the sender's UPN
senderUPN = getSenderUPN(user, chatMembers)
if senderUPN is undefined or authorizedUsers[senderUPN] is undefined
@robot.logger.info "#{LogPrefix} Unauthorized user; returning error"
unauthorizedError = true
# activity.text = "hubot return unauthorized user error"
# Change this to make a call to a middleware function that returns
# a payload with the error text to return
# Add the sender's UPN to user
user.userPrincipalName = senderUPN
# Return a generic message if the activity isn't a message or invoke
if activity.type != 'message' && activity.type != 'invoke'
cb(new Message(user), unauthorizedError)
activity = fixActivityForHubot(activity, @robot, chatMembers)
message = new TextMessage(user, activity.text, activity.address.id)
cb(message, unauthorizedError)
toSendable: (context, message) ->
@robot.logger.info "#{LogPrefix} toSendable"
@ -109,7 +108,7 @@ class MicrosoftTeamsMiddleware extends BaseMiddleware
# If the query sent by the user should trigger a card,
# construct the card to attach to the response
# and remove sentQuery from the brain
card = HubotResponseCards.maybeConstructCard(response, activity.text)
card = HubotResponseCards.maybeConstructResponseCard(response, activity.text)
if card != null
delete response.text
response.attachments = [card]
@ -156,7 +155,7 @@ class MicrosoftTeamsMiddleware extends BaseMiddleware
return true
# Combines the text and attachments of multiple hubot messages sent in succession.
# Most of the first received response is kept, and the text and attachments of
# Most of the first received response is kept, and the text and attachments of
# subsequent responses received within 500ms of the first are combined into the
# first response.
combineResponses: (storedPayload, newPayload) ->
@ -197,9 +196,53 @@ class MicrosoftTeamsMiddleware extends BaseMiddleware
if attachment.contentType != "application/vnd.microsoft.card.adaptive"
storedMessage.attachments.push(attachment)
else
storedCard = HubotResponseCards.appendCardBody(storedCard, attachment)
storedCard = HubotResponseCards.appendCardActions(storedCard, attachment)
storedCard = HubotResponseCards.appendCardBody(storedCard, \
attachment)
storedCard = HubotResponseCards.appendCardActions(storedCard, \
attachment)
# Constructs a text message response to indicate an error to the user in the
# message channel they are using
constructErrorResponse: (activity, text, appendAdmins) ->
if appendAdmins
authorizedUsers = @robot.brain.get("authorizedUsers")
for userKey, isAdmin of authorizedUsers
if isAdmin
text = """#{text}
#{userKey}"""
typing =
type: 'typing'
address: activity?.address
payload =
type: 'message'
text: "#{text}"
address: activity?.address
return [typing, payload]
# Constructs a response containing a card for user input if needed or null
# if user input is not needed
maybeConstructUserInputPrompt: (event) ->
query = event.value.hubotMessage
# Remove the hubot prefix, if there is one
query = query.replace("hubot ", "")
console.log(query)
card = HubotResponseCards.maybeConstructMenuInputCard(query)
if card is null
console.log("CARD IS NULL")
return null
response =
type: 'message'
address: event?.address
attachments: [
card
]
return response
#############################################################################
# Helper methods for generating richer messages
@ -256,7 +299,8 @@ class MicrosoftTeamsMiddleware extends BaseMiddleware
entities = activity?.entities || []
if not Array.isArray(entities)
entities = [entities]
return entities.filter((entity) -> entity.type == "mention" && (not userId? || userId == entity.mentioned?.id))
return entities.filter((entity) -> entity.type == "mention" && \
(not userId? || userId == entity.mentioned?.id))
# Returns the provided user's userPrincipalName (UPN) or null if one cannot be found
getSenderUPN = (user, chatMembers) ->
@ -270,14 +314,16 @@ class MicrosoftTeamsMiddleware extends BaseMiddleware
# Fixes the activity to have the proper information for Hubot
# 1. Constructs the text command to send to hubot if the event is from a
# submit on an adaptive card (containing the value property).
# 2. Replaces all occurrences of the channel's bot at mention name with the configured name in hubot.
# submit on an adaptive card (containing the value property).
# 2. Replaces all occurrences of the channel's bot at mention name with the configured
# name in hubot.
# The hubot's configured name might not be the same name that is sent from the chat service in
# the activity's text.
# 3. Replaces all occurrences of @ mentions to users with their aad object id if the user is
# on the roster of chanenl members from Teams. If a mentioned user is not in the chat roster,
# the mention is replaced with their name.
# 4. Prepends hubot's name to the message for personal messages if it's not already
# 4. Trims all whitespace and newlines from the beginning and end of the text.
# 5. Prepends hubot's name to the message for personal messages if it's not already
# there
fixActivityForHubot = (activity, robot, chatMembers) ->
# If activity.value exists, the command is from a card and the correct
@ -309,10 +355,11 @@ class MicrosoftTeamsMiddleware extends BaseMiddleware
# Set the constructed query as the text of the activity
activity.text = text
return activity
#return activity
if not activity?.text? || typeof activity.text isnt 'string'
return activity
myChatId = activity?.address?.bot?.id
if not myChatId?
return activity
@ -332,6 +379,9 @@ class MicrosoftTeamsMiddleware extends BaseMiddleware
replacement = member.userPrincipalName
# *** replacement = member.objectId
activity.text = activity.text.replace(mentionTextRegExp, replacement)
# Remove leading/trailing whitespace and newlines
activity.text = activity.text.trim()
# prepends the robot's name for direct messages if it's not already there
if getConversationType(activity) == 'personal' && activity.text.search(robot.name) != 0

Просмотреть файл

@ -4,15 +4,28 @@ expect = chai.expect
BotFrameworkAdapter = require '../src/adapter'
MockRobot = require './mock-robot'
describe 'Main Adapter', ->
describe 'Test Auth', ->
describe 'Test Authorization Setup', ->
beforeEach ->
process.env.HUBOT_TEAMS_INITIAL_ADMINS = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee,eight888-four-4444-fore-twelve121212'
process.env.BOTBUILDER_APP_ID = 'botbuilder-app-id'
process.env.BOTBUILDER_APP_PASSWORD = 'botbuilder-app-password'
process.env.HUBOT_DEBUG_LEVEL = 'error'
process.env.HUBOT_TEAMS_INITIAL_ADMINS = 'an-1_20@em.ail,authorized_user@email.la'
# process.env.BOTBUILDER_APP_ID = 'botbuilder-app-id'
# process.env.BOTBUILDER_APP_PASSWORD = 'botbuilder-app-password'
process.env.HUBOT_TEAMS_ENABLE_AUTH = 'true'
it 'should not set initial admins when auth enable is not set', ->
# Setup
delete process.env.HUBOT_TEAMS_ENABLE_AUTH
robot = new MockRobot
# Action
expect(() ->
adapter = BotFrameworkAdapter.use(robot)
).to.not.throw()
# Assert
expect(robot.brain.get("authorizedUsers")).to.be.null
it 'should not set initial admins when auth is not enabled', ->
# Setup
process.env.HUBOT_TEAMS_ENABLE_AUTH = 'false'
@ -25,6 +38,16 @@ describe 'Main Adapter', ->
# Assert
expect(robot.brain.get("authorizedUsers")).to.be.null
it 'should throw error when auth is enabled and initial admins', ->
# Setup
delete process.env.HUBOT_TEAMS_INITIAL_ADMINS
robot = new MockRobot
# Action and Assert
expect(() ->
adapter = BotFrameworkAdapter.use(robot)
).to.throw()
it 'should set initial admins when auth is enabled', ->
# Setup
@ -37,50 +60,22 @@ describe 'Main Adapter', ->
# Assert
expect(robot.brain.get("authorizedUsers")).to.eql {
'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee': true
'eight888-four-4444-fore-twelve121212': true
'an-1_20@em.ail': true
'authorized_user@email.la': true
}
it 'should not set initial admins when auth enable is not set', ->
# Setup
delete process.env.HUBOT_TEAMS_ENABLE_AUTH
robot = new MockRobot
# Action
expect(() ->
adapter = BotFrameworkAdapter.use(robot)
).to.not.throw()
# Assert
expect(robot.brain.get("authorizedUsers")).to.be.null
it 'should allow messages from authorized users', ->
# Setup
describe 'Test Authorization Support for Teams Channel', ->
robot = null
adapter = null
event = null
beforeEach ->
process.env.HUBOT_TEAMS_INITIAL_ADMINS = 'an-1_20@em.ail,authorized_user@email.la'
process.env.BOTBUILDER_APP_ID = 'botbuilder-app-id'
process.env.BOTBUILDER_APP_PASSWORD = 'botbuilder-app-password'
process.env.HUBOT_TEAMS_ENABLE_AUTH = 'true'
robot = new MockRobot
adapter = BotFrameworkAdapter.use(robot)
robot.adapter = adapter
adapter.connector.fetchMembers = (serviceUrl, teamId, callback) ->
members = [
{
id: 'id-1'
objectId: 'aad-object-id-1'
name: 'user1 one'
givenName: 'user1'
surname: 'one'
email: 'one@user.one'
userPrincipalName: 'one@user.one'
},
{
id: 'user-id'
objectId: 'eight888-four-4444-fore-twelve121212'
name: 'user-name'
givenName: 'user-'
surname: 'name'
email: 'em@ai.l'
userPrincipalName: 'em@ai.l'
}
]
callback false, members
event =
type: 'message'
text: '<at>Bot</at> do something <at>Bot</at> and tell <at>User</at> about it'
@ -112,88 +107,44 @@ describe 'Main Adapter', ->
id: "user-id"
name: "user-name"
aadObjectId: "eight888-four-4444-fore-twelve121212"
userPrincipalName: "user-UPN"
serviceUrl: 'url-serviceUrl/a-url'
it 'should return authorization not supported error for non-Teams channels', ->
# Setup
event.source = 'authorization-not-supported-source'
# Action
expect(() ->
result = adapter.handleActivity(event)
adapter.handleActivity(event)
).to.not.throw()
# Assert
expect(robot.brain.get("authorizedUsers")).to.eql {
'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee': true
'eight888-four-4444-fore-twelve121212': true
}
result = robot.brain.get("event")
expect(result.text).to.eql "hubot return source authorization not supported error"
# it 'should overwrite the hubot command text to return an error message to unauthorized users', ->
# # Setup
# robot = new Robot('../../hubot-botframework', 'botframework', false, 'hubot')
# adapter = BotFrameworkAdapter.use(robot)
# adapter.connector.fetchMembers = (serviceUrl, teamId, callback) ->
# members = [
# {
# id: 'id-1'
# objectId: 'aad-object-id-1'
# name: 'user1 one'
# givenName: 'user1'
# surname: 'one'
# email: 'one@user.one'
# userPrincipalName: 'one@user.one'
# },
# {
# id: 'user-id'
# objectId: 'eight888-four-4444-fore-twelve121212'
# name: 'user-name'
# givenName: 'user-'
# surname: 'name'
# email: 'em@ai.l'
# userPrincipalName: 'em@ai.l'
# }
# ]
# callback false, members
# event =
# type: 'message'
# text: '<at>Bot</at> do something <at>Bot</at> and tell <at>User</at> about it'
# agent: 'tests'
# source: 'msteams'
# entities: [
# type: "mention"
# text: "<at>Bot</at>"
# mentioned:
# id: "bot-id"
# name: "bot-name"
# ,
# type: "mention"
# text: "<at>User</at>"
# mentioned:
# id: "user-id"
# name: "user-name"
# ]
# attachments: []
# sourceEvent:
# tenant:
# id: "tenant-id"
# address:
# conversation:
# id: "19:conversation-id"
# bot:
# id: "bot-id"
# user:
# id: "id-1"
# name: "user1 one"
# aadObjectId: "aad-object-id-1"
# serviceUrl: 'url-serviceUrl/a-url'
it 'should work when authorization is enabled and message is from Teams', ->
# Setup
# # Action
# expect(() ->
# result = adapter.handleActivity(event)
# ).to.not.throw()
# Action
expect(() ->
adapter.handleActivity(event)
).to.not.throw()
# console.log("=======================================")
# console.log(adapter)
# Assert
result = robot.brain.get("event")
# # Assert
# expect(robot.brain.get("authorizedUsers")).to.eql {
# 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee': true
# 'eight888-four-4444-fore-twelve121212': true
# }
it 'should work when message is from invoke', ->
# Setup
event.type = 'invoke'
event.value =
hubotMessage: 'hubot do something'
delete event.text
# Action
expect(() ->
adapter.sendTextToHubot(event)
).to.not.throw()
# Assert

Просмотреть файл

@ -9,7 +9,19 @@ class MockRobot
"hubot b - does something b"
]
@brain =
userForId: -> {}
data: {}
userForId: (id, options) ->
user = {
id: "#{id}"
name: "a-hubot-user-name"
}
if options is null
return user
else
for key of options
user[key] = options[key]
return user
users: -> []
get: (key) ->
if @data is undefined
@ -18,16 +30,9 @@ class MockRobot
if key == storedKey
return @data[storedKey]
return null
set: (key, value) ->
@data[key] = value
if process.env.HUBOT_TEAMS_ENABLE_AUTH == 'true'
if process.env.HUBOT_TEAMS_INITIAL_ADMINS
@brain.data = {}
authorizedUsers = {}
for admin in process.env.HUBOT_TEAMS_INITIAL_ADMINS.split(",")
authorizedUsers[admin] = true
@brain.data["authorizedUsers"] = authorizedUsers
else
throw new Error("HUBOT_TEAMS_INITIAL_ADMINS is required")
receive: -> {}
receive: (event) ->
@brain.data["event"] = event
module.exports = MockRobot

Просмотреть файл

@ -11,15 +11,21 @@ describe 'MicrosoftTeamsMiddleware', ->
describe 'toReceivable', ->
robot = null
event = null
chatMembers = null
cb = -> {}
teamsChatConnector = null
authEnabled = false
cb = ->
robot.receive event
beforeEach ->
delete process.env.HUBOT_OFFICE365_TENANT_FILTER
robot = new MockRobot
adapter = BotFrameworkAdapter.use(robot)
robot.adapter = adapter
options = {
appId: 'botframework-app-id'
appPassword: 'botframework-app-password'
}
teamsChatConnector = new MockTeamsChatConnector(options)
authEnabled = false
event =
type: 'message'
text: '<at>Bot</at> do something <at>Bot</at> and tell <at>User</at> about it'
@ -52,97 +58,135 @@ describe 'MicrosoftTeamsMiddleware', ->
name: "user-name"
aadObjectId: 'eight888-four-4444-fore-twelve121212'
it 'should allow messages without tenant id when tenant filter is empty', ->
it 'should allow messages when auth is not enabled', ->
# Setup
console.log("**************************************")
console.log(MicrosoftTeamsMiddleware.toString())
delete event.sourceEvent
teamsMiddleware = new MicrosoftTeamsMiddleware(robot)
options = {
appId: 'botframework-app-id'
appPassword: 'botframework-app-password'
}
teamsChatConnector = new MockTeamsChatConnector(options)
# Action
receivable = null
expect(() ->
receivable = teamsMiddleware.toReceivable(event, teamsChatConnector, cb)
teamsMiddleware.toReceivable(event, teamsChatConnector, authEnabled, cb)
).to.not.throw()
# Assert
expect(receivable).to.be.a('Object')
result = robot.brain.get("event")
expect(result).to.be.a('Object')
# it 'should allow messages with tenant id when tenant filter is empty', ->
# # Setup
# teamsMiddleware = new MicrosoftTeamsMiddleware(robot)
it 'should set unauthorized error for message when user isn\'t authorized', ->
# Setup
robot.brain.data["authorizedUsers"] =
'an-1_20@em.ail': true
'authorized_user@email.la': false
teamsMiddleware = new MicrosoftTeamsMiddleware(robot)
authEnabled = true
cb = (event, unauthorizedError) ->
robot.brain.data["unauthError"] = unauthorizedError
robot.receive event
# # Action
# receivable = null
# expect(() ->
# receivable = teamsMiddleware.toReceivable(event, cb)
# ).to.not.throw()
# Action
expect(() ->
teamsMiddleware.toReceivable(event, teamsChatConnector, authEnabled, cb)
).to.not.throw()
# # Assert
# expect(receivable).to.be.a('Object')
# Assert
result = robot.brain.get("event")
expect(result).to.be.a('Object')
expect(robot.brain.get("unauthError")).to.be.true
# it 'should allow messages from allowed tenant ids', ->
# # Setup
# process.env.HUBOT_OFFICE365_TENANT_FILTER = event.sourceEvent.tenant.id
# teamsMiddleware = new MicrosoftTeamsMiddleware(robot)
it 'should allow messages without tenant id when tenant filter is empty', ->
# Setup
delete event.sourceEvent
teamsMiddleware = new MicrosoftTeamsMiddleware(robot)
# # Action
# receivable = null
# expect(() ->
# receivable = teamsMiddleware.toReceivable(event, cb)
# ).to.not.throw()
# Action
expect(() ->
teamsMiddleware.toReceivable(event, teamsChatConnector, authEnabled, cb)
).to.not.throw()
# # Assert
# expect(receivable).to.be.a('Object')
# Assert
result = robot.brain.get("event")
expect(result).to.be.a('Object')
# it 'should block messages from unallowed tenant ids', ->
# # Setup
# process.env.HUBOT_OFFICE365_TENANT_FILTER = event.sourceEvent.tenant.id
# event.sourceEvent.tenant.id = "different-tenant-id"
# teamsMiddleware = new MicrosoftTeamsMiddleware(robot)
it 'should allow messages with tenant id when tenant filter is empty', ->
# Setup
teamsMiddleware = new MicrosoftTeamsMiddleware(robot)
# # Action
# receivable = null
# expect(() ->
# receivable = teamsMiddleware.toReceivable(event, cb)
# ).to.not.throw()
# Action
expect(() ->
teamsMiddleware.toReceivable(event, teamsChatConnector, authEnabled, cb)
).to.not.throw()
# # Assert
# expect(receivable).to.be.null
# Assert
result = robot.brain.get("event")
expect(result).to.be.a('Object')
# it 'return generic message when appropriate type is not found', ->
# # Setup
# event.type = 'typing'
# teamsMiddleware = new MicrosoftTeamsMiddleware(robot)
it 'should allow messages from allowed tenant ids', ->
# Setup
process.env.HUBOT_OFFICE365_TENANT_FILTER = event.sourceEvent.tenant.id
teamsMiddleware = new MicrosoftTeamsMiddleware(robot)
# # Action
# receivable = null
# expect(() ->
# receivable = teamsMiddleware.toReceivable(event, cb)
# ).to.not.throw()
# Action
expect(() ->
teamsMiddleware.toReceivable(event, teamsChatConnector, authEnabled, cb)
).to.not.throw()
# # Assert
# expect(receivable).to.be.not.null
# Assert
result = robot.brain.get("event")
expect(result).to.be.a('Object')
# it 'should work when activity text is an object', ->
# # Setup
# event.text = event
# teamsMiddleware = new MicrosoftTeamsMiddleware(robot)
it 'should block messages from unallowed tenant ids', ->
# Setup
process.env.HUBOT_OFFICE365_TENANT_FILTER = event.sourceEvent.tenant.id
event.sourceEvent.tenant.id = "different-tenant-id"
teamsMiddleware = new MicrosoftTeamsMiddleware(robot)
# # Action
# receivable = null
# expect(() ->
# receivable = teamsMiddleware.toReceivable(event, cb)
# ).to.not.throw()
# Action
expect(() ->
teamsMiddleware.toReceivable(event, teamsChatConnector, authEnabled, cb)
).to.not.throw()
# # Assert
# expect(receivable.text).to.equal(event)
# Assert
result = robot.brain.get("event")
expect(result).to.be.null
it 'return generic message when appropriate type is not found', ->
# Setup
event.type = 'typing'
teamsMiddleware = new MicrosoftTeamsMiddleware(robot)
# Action
expect(() ->
teamsMiddleware.toReceivable(event, teamsChatConnector, authEnabled, cb)
).to.not.throw()
# Assert
result = robot.brain.get("event")
expect(result).to.be.not.null
# Test when message is from follow up button
it 'should work when activity value contains query parts', ->
# Setup
# Action
# Assert
it 'should work when activity text is an object', ->
# Setup
event.text = event
teamsMiddleware = new MicrosoftTeamsMiddleware(robot)
# Action
expect(() ->
teamsMiddleware.toReceivable(event, teamsChatConnector, authEnabled, cb)
).to.not.throw()
# Assert
result = robot.brain.get("event")
expect(result.text).to.equal(event)
# it 'should work when mentions not provided', ->
# # Setup