diff --git a/core/activity/handler.go b/core/activity/handler.go index 897562e..593c4ca 100644 --- a/core/activity/handler.go +++ b/core/activity/handler.go @@ -28,9 +28,18 @@ import ( // Handler acts as the interface for the client program to define actions on various events from connector service. type Handler interface { - OnMessage(context *TurnContext) (schema.Activity, error) - OnInvoke(context *TurnContext) (schema.Activity, error) - OnConversationUpdate(context *TurnContext) (schema.Activity, error) + On(context *TurnContext) (schema.Activity, error) +} + +// HandlerFuncsMap is an adaptor to let client program handler functions +// for all activity types, including not supported by HandlerFuncs adaptor +type HandlerFuncsMap map[schema.ActivityTypes]func(turn *TurnContext) (schema.Activity, error) + +func (hf HandlerFuncsMap) On(context *TurnContext) (schema.Activity, error) { + if handler, ok := hf[context.Activity.Type]; ok { + return handler(context) + } + return schema.Activity{}, fmt.Errorf("Activity type %s not supported", context.Activity.Type) } // HandlerFuncs is an adaptor to let client program specify as many or @@ -42,6 +51,18 @@ type HandlerFuncs struct { OnConversationUpdateFunc func(turn *TurnContext) (schema.Activity, error) } +func (r HandlerFuncs) On(context *TurnContext) (schema.Activity, error) { + switch context.Activity.Type { + case schema.Message: + return r.OnMessage(context) + case schema.Invoke: + return r.OnInvoke(context) + case schema.ConversationUpdate: + return r.OnConversationUpdate(context) + } + return schema.Activity{}, fmt.Errorf("Activity type %s not supported yet", context.Activity.Type) +} + // OnMessage handles a 'message' event from connector service. func (r HandlerFuncs) OnMessage(turn *TurnContext) (schema.Activity, error) { if r.OnMessageFunc != nil { @@ -69,13 +90,5 @@ func (r HandlerFuncs) OnInvoke(turn *TurnContext) (schema.Activity, error) { // PrepareActivityContext routes the received Activity to respective handler function. // Returns the result of the handler function. func PrepareActivityContext(handler Handler, context *TurnContext) (schema.Activity, error) { - switch context.Activity.Type { - case schema.Message: - return handler.OnMessage(context) - case schema.Invoke: - return handler.OnInvoke(context) - case schema.ConversationUpdate: - return handler.OnConversationUpdate(context) - } - return schema.Activity{}, fmt.Errorf("Activity type %s not supported yet", context.Activity.Type) + return handler.On(context) } diff --git a/core/bot_framework_adapter_test.go b/core/bot_framework_adapter_test.go index 6e80657..749564f 100644 --- a/core/bot_framework_adapter_test.go +++ b/core/bot_framework_adapter_test.go @@ -177,3 +177,101 @@ func TestActivityUpdate(t *testing.T) { handler.ServeHTTP(rr, req) assert.Equal(t, rr.Code, 200, "Expect 200 response status") } + +func TestActivityCustom(t *testing.T) { + srv := serverMock(t) + + type args struct { + Activity schema.Activity + Handler activity.Handler + } + + tests := []struct { + name string + args args + wantErr bool + }{ + { + args: args{ + Activity: schema.Activity{ + Type: schema.InstallationUpdate, + Conversation: schema.ConversationAccount{ + ID: "abcd1234", + Name: "Convo1", + }, + MembersAdded: []schema.ChannelAccount{ + { + ID: "123456", + Name: "Some member name", + Role: schema.BOT, + }, + }, + Text: "Message from Teams Client", + ReplyToID: "5d5cdc723", + ServiceURL: srv.URL, + }, + Handler: activity.HandlerFuncsMap{ + schema.InstallationUpdate: func(turn *activity.TurnContext) (schema.Activity, error) { + return turn.SendActivity(activity.MsgOptionText("supported")) + }, + }, + }, + }, + { + args: args{ + Activity: schema.Activity{ + Type: schema.InstallationUpdate, + Conversation: schema.ConversationAccount{ + ID: "abcd1234", + Name: "Convo1", + }, + MembersAdded: []schema.ChannelAccount{ + { + ID: "123456", + Name: "Some member name", + Role: schema.BOT, + }, + }, + Text: "Message from Teams Client", + ReplyToID: "5d5cdc723", + ServiceURL: srv.URL, + }, + Handler: activity.HandlerFuncs{}, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + ctx := context.Background() + setting := core.AdapterSetting{ + AppID: "asdasd", + AppPassword: "cfg.MicrosoftTeams.AppPassword", + } + setting.CredentialProvider = auth.SimpleCredentialProvider{ + AppID: setting.AppID, + Password: setting.AppPassword, + } + clientConfig, err := client.NewClientConfig(setting.CredentialProvider, auth.ToChannelFromBotLoginURL[0]) + assert.Nil(t, err, fmt.Sprintf("Failed with error %s", err)) + connectorClient, err := client.NewClient(clientConfig) + assert.Nil(t, err, fmt.Sprintf("Failed with error %s", err)) + adapter := core.BotFrameworkAdapter{setting, &core.MockTokenValidator{}, connectorClient} + act, err := adapter.ParseRequest(ctx, req) + + err = adapter.ProcessActivity(ctx, act, tt.args.Handler) + assert.True(t, (err != nil) == tt.wantErr, fmt.Sprintf("Failed with error %s", err)) + }) + rr := httptest.NewRecorder() + bodyJSON, err := json.Marshal(tt.args.Activity) + assert.Nil(t, err, fmt.Sprintf("Failed with error %s", err)) + bodyBytes := bytes.NewReader(bodyJSON) + req, err := http.NewRequest(http.MethodPost, "/api/messages", bodyBytes) + assert.Nil(t, err, fmt.Sprintf("Failed with error %s", err)) + req.Header.Set("Authorization", "Bearer abc123") + handler.ServeHTTP(rr, req) + assert.Equal(t, rr.Code, 200, "Expect 200 response status") + }) + } +}