Merged branch with changes for last reviews

This commit is contained in:
Melanie Mendoza 2018-08-24 16:11:22 -07:00
Родитель d9a5e46f41 0f80d01b94
Коммит 17b2f2f785
7 изменённых файлов: 409 добавлений и 105 удалений

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

@ -21,6 +21,10 @@ class BaseMiddleware
throw new Error('toSendable not implemented')
class TextMiddleware extends BaseMiddleware
# TextMiddleware doesn't use invokes currently, so just return null
handleInvoke: (invokeEvent, connector) ->
return null
toReceivable: (activity) ->
@robot.logger.info "#{LogPrefix} TextMiddleware toReceivable"
address = activity.address
@ -56,6 +60,22 @@ class TextMiddleware extends BaseMiddleware
supportsAuth: () ->
return false
# Sends an error message back to the user if authorization isn't supported for the
# channel or prepares and sends the message to hubot for reception
maybeReceive: (activity, connector, authEnabled) ->
# Return an error to the user if the message channel doesn't support authorization
# and authorization is enabled
if authEnabled
@robot.logger.info "#{LogPrefix} Authorization isn\'t supported
for the channel error"
text = "Authorization isn't supported for this channel"
payload = @constructErrorResponse(activity, text)
@send(connector, payload)
else
event = @toReceivable activity
if event?
@robot.receive event
# Sends the payload to the bot framework messaging channel
send: (connector, payload) ->
if !Array.isArray(payload)

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

@ -27,11 +27,12 @@ class BotFrameworkAdapter extends Adapter
@enableAuth = false
if process.env.HUBOT_TEAMS_ENABLE_AUTH? and process.env.HUBOT_TEAMS_ENABLE_AUTH == 'true'
@enableAuth = true
@initialAdmins = process.env.HUBOT_TEAMS_INITIAL_ADMINS
robot.logger.info "#{LogPrefix} Adapter loaded. Using appId #{@appId}"
# Initial Admins should be required when auth is enabled
if @enableAuth
if process.env.HUBOT_TEAMS_INITIAL_ADMINS
if @initialAdmins?
# If there isn't a list of authorized users in the brain, populate
# it with admins from the environment variable
if robot.brain.get("authorizedUsers") is null
@ -50,22 +51,15 @@ class BotFrameworkAdapter extends Adapter
@connector.onEvent (events, cb) => @onBotEvents events, cb
@connector.onInvoke (events, cb) => @menuCardInvoke events, cb
@connector.onInvoke (events, cb) => @onInvoke events, cb
# 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) ->
console.log(invokeEvent)
# Handles the invoke and passes an event to be handled, if needed
onInvoke: (invokeEvent, cb) ->
middleware = @using(invokeEvent.source)
payload = middleware.maybeConstructUserInputPrompt(invokeEvent)
if payload == null
invokeEvent.text = invokeEvent.value.hubotMessage
delete invokeEvent.value
@handleActivity(invokeEvent)
else
middleware.sendPayload(@robot, @connector, payload)
return
event = middleware.handleInvoke(invokeEvent, @connector)
if event != null
@handleActivity(event)
using: (name) ->
MiddlewareClass = Middleware.middlewareFor(name)
@ -86,26 +80,10 @@ class BotFrameworkAdapter extends Adapter
# If authorization isn't supported by the activity source, use
# the text middleware, otherwise use the Teams middleware
if not middleware.supportsAuth()
# Return an error to the user if the message channel doesn't support authorization
# and authorization is enabled
if @enableAuth
@robot.logger.info "#{LogPrefix} Authorization isn\'t supported
for the channel error"
text = "Authorization isn't supported for this channel"
payload = middleware.constructErrorResponse(activity, text)
middleware.send(@robot.adapter.connector, payload)
return
else
event = middleware.toReceivable activity
if event?
@robot.receive event
middleware.maybeReceive(activity, @connector, @enableAuth)
else
middleware.toReceivable activity, @enableAuth, @appId, @appPassword, \
(event, response) =>
if response?
middleware.send(@robot.adapter.connector, response)
else if event?
@robot.receive event
middleware.maybeReceive(activity, @connector, @enableAuth, \
@appId, @appPassword)
send: (context, messages...) ->
@robot.logger.info "#{LogPrefix} send"
@ -118,7 +96,7 @@ class BotFrameworkAdapter extends Adapter
activity = context.user.activity
middleware = @using(activity.source)
payload = middleware.toSendable(context, msg)
middleware.send(@robot.adapter.connector, payload)
middleware.send(@connector, payload)
run: ->
@robot.router.post @endpoint, @connector.listen()

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

@ -42,6 +42,18 @@ class MicrosoftTeamsMiddleware extends BaseMiddleware
@robot.logger.info("#{LogPrefix} Restricting tenants to \
#{JSON.stringify(@allowedTenants)}")
# If the invoke is due to a command that needs user input, sends a user input card
# otherwise, returns an event to handle, if needed, or null
handleInvoke: (invokeEvent, connector) ->
payload = @maybeConstructUserInputPrompt(invokeEvent)
if payload != null
@sendPayload(connector, payload)
return null
else
invokeEvent.text = invokeEvent.value.hubotMessage
delete invokeEvent.value
return invokeEvent
toReceivable: (activity, authEnabled, appId, appPassword, cb) ->
@robot.logger.info "#{LogPrefix} toReceivable"
@ -68,7 +80,6 @@ class MicrosoftTeamsMiddleware extends BaseMiddleware
activity?.address?.conversation?.id, (err, chatMembers) =>
if err
return
# Return with unauthorized error as true if auth is enabled and the user who sent
# the message is not authorized
if authEnabled
@ -132,6 +143,14 @@ class MicrosoftTeamsMiddleware extends BaseMiddleware
supportsAuth: () ->
return true
maybeReceive: (activity, connector, authEnabled, appId, appPassword) ->
@toReceivable activity, authEnabled, appId, appPassword,
(event, response) =>
if response?
@send(connector, response)
else if event?
@robot.receive event
# Combines payloads then sends the combined payload to MS Teams
send: (connector, payload) ->
# The message is from Teams, so combine hubot responses
@ -140,18 +159,18 @@ class MicrosoftTeamsMiddleware extends BaseMiddleware
if @robot.brain.get("justReceivedResponse") is null
@robot.brain.set("teamsResponse", payload)
@robot.brain.set("justReceivedResponse", true)
setTimeout(@sendPayload, 100, @robot, connector, @robot.brain.get("teamsResponse"))
setTimeout(@sendPayload.bind(this), 100, connector, @robot.brain.get("teamsResponse"))
else
@combineResponses(@robot.brain.get("teamsResponse"), payload)
sendPayload: (robot, connector, payload) ->
sendPayload: (connector, payload) ->
if !Array.isArray(payload)
payload = [payload]
connector.send payload, (err, _) ->
connector.send payload, (err, _) =>
if err
throw err
robot.brain.remove("teamsResponse")
robot.brain.remove("justReceivedResponse")
@robot.brain.remove("teamsResponse")
@robot.brain.remove("justReceivedResponse")
# 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

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

@ -77,6 +77,41 @@ describe 'BaseMiddleware', ->
).to.throw()
describe 'TextMiddleware', ->
describe 'handleInvoke', ->
robot = null
event = null
connector = null
beforeEach ->
robot = new MockRobot
event =
type: 'invoke'
text: 'Bot do something and tell User about it'
agent: 'tests'
source: '*'
address:
conversation:
id: "conversation-id"
bot:
id: "bot-id"
user:
id: "user-id"
name: "user-name"
connector =
send: () -> {}
it 'should return null', ->
# Setup
middleware = new TextMiddleware(robot)
# Action
result = null
expect(() ->
result = middleware.handleInvoke(event, connector)
).to.not.throw()
# Assert
expect(result).to.be.null
describe 'toReceivable', ->
robot = null
event = null
@ -191,6 +226,85 @@ describe 'TextMiddleware', ->
# Action and Assert
expect(middleware.supportsAuth()).to.be.false
describe 'maybeReceive', ->
robot = null
middleware = null
authEnabled = true
connector = null
event = null
beforeEach ->
robot = new MockRobot
middleware = new TextMiddleware(robot)
connector =
send: (payload, cb) ->
robot.brain.set("payload", payload)
authEnabled = true
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"
]
sourceEvent:
tenant:
id: "tenant-id"
address:
conversation:
id: "19:conversation-id"
bot:
id: "bot-id"
user:
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 when auth is enabled', ->
# Setup
# Action
expect(() ->
middleware.maybeReceive(event, connector, authEnabled)
).to.not.throw()
# Assert
resultEvent = robot.brain.get("event")
expect(resultEvent).to.be.null
resultPayload = robot.brain.get("payload")
expect(resultPayload).to.be.a('Array')
expect(resultPayload.length).to.eql 1
expect(resultPayload[0].text).to.eql "Authorization isn't supported for this channel"
it 'should work when auth is not enabled', ->
# Setup
authEnabled = false
# Action
expect(() ->
middleware.maybeReceive(event, connector, authEnabled)
).to.not.throw()
# Assert
resultEvent = robot.brain.get("event")
expect(resultEvent).to.not.be.null
expect(resultEvent).to.be.a('Object')
resultPayload = robot.brain.get("payload")
expect(resultPayload).to.be.null
describe 'constructErrorResponse', ->
it 'return a proper payload with the text of the error', ->
# Setup

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

@ -62,67 +62,67 @@ describe 'Main Adapter', ->
'authorized_user@email.la': true
}
describe 'Test Authorization Not Suppported Error', ->
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'
# describe 'Test Authorization Not Supported Error', ->
# 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.send = (payload, cb) ->
robot.brain.set("payload", payload)
# robot = new MockRobot
# adapter = BotFrameworkAdapter.use(robot)
# robot.adapter = adapter
# adapter.connector.send = (payload, cb) ->
# robot.brain.set("payload", payload)
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: "user-id"
name: "user-name"
aadObjectId: "eight888-four-4444-fore-twelve121212"
userPrincipalName: "user-UPN"
serviceUrl: 'url-serviceUrl/a-url'
# 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: "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'
# it 'should return authorization not supported error for non-Teams channels', ->
# # Setup
# event.source = 'authorization-not-supported-source'
# Action
expect(() ->
adapter.handleActivity(event)
).to.not.throw()
# # Action
# expect(() ->
# adapter.handleActivity(event)
# ).to.not.throw()
# Assert
result = robot.brain.get("payload")
expect(result).to.be.a('Array')
expect(result.length).to.eql 1
expect(result[0].text).to.eql "Authorization isn't supported for this channel"
# # Assert
# result = robot.brain.get("payload")
# expect(result).to.be.a('Array')
# expect(result.length).to.eql 1
# expect(result[0].text).to.eql "Authorization isn't supported for this channel"

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

@ -26,9 +26,6 @@ class TeamsChatConnector
]
callback false, members
send: (payload) ->
robot.brain.set("payload", payload)
BotBuilderTeams = {
TeamsChatConnector: TeamsChatConnector

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

@ -3,10 +3,103 @@ expect = chai.expect
{ TextMessage, Message, User } = require 'hubot'
rewiremock = require('rewiremock/node').default
MockRobot = require './mock-robot'
BotFrameworkAdapter = require '../src/adapter'
MicrosoftTeamsMiddleware = require '../src/msteams-middleware'
describe 'MicrosoftTeamsMiddleware', ->
describe 'handleInvoke', ->
rewiremock('botbuilder-teams').with(require('./mock-botbuilder-teams'))
BotBuilderTeams = null
robot = null
event = null
options = null
teamsChatConnector = null
authEnabled = false
cb = () -> {}
beforeEach ->
rewiremock.enable()
BotBuilderTeams = require 'botbuilder-teams'
MicrosoftTeamsMiddleware = require '../src/msteams-middleware'
robot = new MockRobot
options = {
appId: 'botframework-app-id'
appPassword: 'botframework-app-password'
}
teamsChatConnector = new BotBuilderTeams.TeamsChatConnector(options)
teamsChatConnector.send = (payload) ->
robot.brain.set("payload", payload)
event =
type: 'invoke'
text: '<at>Bot</at> do something <at>Bot</at> and tell <at>User</at> about it'
value:
hubotMessage: 'gho list (teams|repos|members)'
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"
]
sourceEvent:
tenant:
id: "tenant-id"
address:
conversation:
isGroup: 'true'
conversationType: 'channel'
id: "19:conversation-id"
bot:
id: "bot-id"
user:
id: "user-id"
name: "user-name"
aadObjectId: 'eight888-four-4444-fore-twelve121212'
userPrincipalName: 'em@ai.l'
afterEach ->
rewiremock.disable()
it 'should send user input card for specific queries', ->
# Setup
teamsMiddleware = new MicrosoftTeamsMiddleware(robot)
# Action
result = null
expect(() ->
result = teamsMiddleware.handleInvoke(event, teamsChatConnector)
).to.not.throw()
# Assert
expect(result).to.be.null
response = robot.brain.get("payload")
expect(response).to.be.a('Array')
expect(response.length).to.eql(2)
it 'should return event to handle', ->
# Setup
event.value.hubotMessage = "gho list public repos"
teamsMiddleware = new MicrosoftTeamsMiddleware(robot)
# Action
result = null
expect(() ->
result = teamsMiddleware.handleInvoke(event, teamsChatConnector)
).to.not.throw()
# Assert
expect(result).to.not.be.null
expect(result).to.be.a('Object')
response = robot.brain.get("payload")
expect(response).to.be.null
describe 'toReceivable', ->
rewiremock('botbuilder-teams').with(require('./mock-botbuilder-teams'))
@ -834,6 +927,89 @@ describe 'MicrosoftTeamsMiddleware', ->
# Action and Assert
expect(teamsMiddleware.supportsAuth()).to.be.true
describe 'maybeReceive', ->
rewiremock('botbuilder-teams').with(require('./mock-botbuilder-teams'))
BotBuilderTeams = null
robot = null
teamsMiddleware = null
connector = null
authEnabled = true
event = null
payload = null
cb = () -> {}
beforeEach ->
rewiremock.enable()
MicrosoftTeamsMiddleware = require '../src/msteams-middleware'
BotBuilderTeams = require 'botbuilder-teams'
robot = new MockRobot
robot.brain.set("authorizedUsers", {
'an-1_20@em.ail': true
'em@ai.l': false
'user-UPN': true
})
teamsMiddleware = new MicrosoftTeamsMiddleware(robot)
connector = new BotBuilderTeams.TeamsChatConnector({
appId: 'a-app-id'
appPassword: 'a-app-password'
})
connector.send = (payload, cb) ->
robot.brain.set("payload", payload)
authEnabled = true
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:
isGroup: 'true'
conversationType: 'channel'
id: "19:conversation-id"
bot:
id: "bot-id"
user:
id: "user-id"
name: "user-name"
aadObjectId: 'eight888-four-4444-fore-twelve121212'
userPrincipalName: 'em@ai.l'
afterEach ->
rewiremock.disable()
it 'hubot can receive a message', ->
# Setup
# Action
expect(() ->
teamsMiddleware.maybeReceive(event, connector, authEnabled, \
'a-app-id', 'a-app-password')
).to.not.throw()
# Assert
resultEvent = robot.brain.get("event")
expect(resultEvent).to.not.be.null
expect(resultEvent).to.be.a('Object')
describe 'send', ->
rewiremock('botbuilder-teams').with(require('./mock-botbuilder-teams'))
BotBuilderTeams = null
@ -1106,7 +1282,7 @@ describe 'MicrosoftTeamsMiddleware', ->
# Action
expect(() ->
teamsMiddleware.sendPayload(robot, connector, payload)
teamsMiddleware.sendPayload(connector, payload)
).to.not.throw()
# Assert
@ -1135,7 +1311,7 @@ describe 'MicrosoftTeamsMiddleware', ->
# Action
expect(() ->
teamsMiddleware.sendPayload(robot, connector, payload)
teamsMiddleware.sendPayload(connector, payload)
).to.not.throw()
# Assert