33
44package com .microsoft .bot .sample .teamstaskmodule ;
55
6- import com .fasterxml .jackson .core .JsonProcessingException ;
76import com .fasterxml .jackson .databind .ObjectMapper ;
87import com .fasterxml .jackson .databind .node .ObjectNode ;
98import com .microsoft .bot .builder .MessageFactory ;
109import com .microsoft .bot .builder .TurnContext ;
1110import com .microsoft .bot .builder .teams .TeamsActivityHandler ;
12- import com .microsoft .bot .schema .Activity ;
11+ import com .microsoft .bot .integration .Async ;
12+ import com .microsoft .bot .integration .Configuration ;
13+ import com .microsoft .bot .sample .teamstaskmodule .models .AdaptiveCardTaskFetchValue ;
14+ import com .microsoft .bot .sample .teamstaskmodule .models .CardTaskFetchValue ;
15+ import com .microsoft .bot .sample .teamstaskmodule .models .TaskModuleIds ;
16+ import com .microsoft .bot .sample .teamstaskmodule .models .TaskModuleResponseFactory ;
17+ import com .microsoft .bot .sample .teamstaskmodule .models .TaskModuleUIConstants ;
18+ import com .microsoft .bot .sample .teamstaskmodule .models .UISettings ;
1319import com .microsoft .bot .schema .Attachment ;
20+ import com .microsoft .bot .schema .CardAction ;
1421import com .microsoft .bot .schema .HeroCard ;
22+ import com .microsoft .bot .schema .Serialization ;
1523import com .microsoft .bot .schema .teams .*;
24+ import java .io .IOException ;
25+ import java .util .ArrayList ;
26+ import java .util .HashMap ;
27+ import java .util .Map ;
1628import java .util .concurrent .CompletionException ;
29+ import java .util .stream .Collectors ;
1730import org .apache .commons .io .IOUtils ;
18- import org .json .JSONObject ;
1931import org .springframework .stereotype .Component ;
2032
2133import java .io .InputStream ;
3446 */
3547@ Component
3648public class TeamsTaskModuleBot extends TeamsActivityHandler {
49+ private final String baseUrl ;
50+ private final List <UISettings > actions = Arrays .asList (
51+ TaskModuleUIConstants .ADAPTIVECARD ,
52+ TaskModuleUIConstants .CUSTOMFORM ,
53+ TaskModuleUIConstants .YOUTUBE
54+ );
3755
38- @ Override
39- protected CompletableFuture <Void > onTeamsMembersAdded (
40- List <TeamsChannelAccount > membersAdded ,
41- TeamInfo teamInfo ,
42- TurnContext turnContext
43- ) {
44- return turnContext .sendActivity (MessageFactory .attachment (getTaskModuleHeroCard ()))
45- .thenApply (resourceResponse -> null );
56+ public TeamsTaskModuleBot (Configuration configuration ) {
57+ baseUrl = configuration .getProperty ("BaseUrl" );
4658 }
4759
4860 @ Override
4961 protected CompletableFuture <Void > onMessageActivity (
5062 TurnContext turnContext
5163 ) {
52- Attachment attachment = getTaskModuleHeroCard ();
53- return turnContext .sendActivity (MessageFactory .attachment (attachment ))
64+ // This displays two cards: A HeroCard and an AdaptiveCard. Both have the same
65+ // options. When any of the options are selected, `onTeamsTaskModuleFetch`
66+ // is called.
67+ return turnContext .sendActivity (MessageFactory .attachment (Arrays .asList (
68+ getTaskModuleHeroCardOptions (),
69+ getTaskModuleAdaptiveCardOptions ()
70+ ))
71+ )
5472 .thenApply (resourceResponse -> null );
5573 }
5674
@@ -59,92 +77,127 @@ protected CompletableFuture<TaskModuleResponse> onTeamsTaskModuleFetch(
5977 TurnContext turnContext ,
6078 TaskModuleRequest taskModuleRequest
6179 ) {
62- Activity reply ;
63- try {
64- reply = MessageFactory .text (
65- "onTeamsTaskModuleFetch TaskModuleRequest: " +
66- new ObjectMapper ().writeValueAsString (taskModuleRequest ));
67- } catch (JsonProcessingException e ) {
68- CompletableFuture <TaskModuleResponse > result = new CompletableFuture <>();
69- result .completeExceptionally (new CompletionException (e ));
70- return result ;
71- }
80+ // Called when the user selects an options from the displayed HeroCard or
81+ // AdaptiveCard. The result is the action to perform.
82+ return Async .tryCompletion (() -> {
83+ CardTaskFetchValue <String > value = Serialization
84+ .safeGetAs (taskModuleRequest .getData (), CardTaskFetchValue .class );
85+
86+ TaskModuleTaskInfo taskInfo = new TaskModuleTaskInfo ();
87+ switch (value .getData ()) {
88+ // Display the YouTube.html page
89+ case TaskModuleIds .YOUTUBE : {
90+ String url = baseUrl + "/" + TaskModuleIds .YOUTUBE ;
91+ taskInfo .setUrl (url );
92+ taskInfo .setFallbackUrl (url );
93+ setTaskInfo (taskInfo , TaskModuleUIConstants .YOUTUBE );
94+ break ;
95+ }
96+
97+ // Display the CustomForm.html page, and post the form data back via
98+ // onTeamsTaskModuleSubmit.
99+ case TaskModuleIds .CUSTOMFORM : {
100+ String url = baseUrl + "/" + TaskModuleIds .CUSTOMFORM ;
101+ taskInfo .setUrl (url );
102+ taskInfo .setFallbackUrl (url );
103+ setTaskInfo (taskInfo , TaskModuleUIConstants .CUSTOMFORM );
104+ break ;
105+ }
72106
73- return turnContext .sendActivity (reply )
74- .thenApply (resourceResponse -> {
75- Attachment adaptiveCard = getTaskModuleAdaptiveCard ();
76-
77- return new TaskModuleResponse () {{
78- setTask (new TaskModuleContinueResponse () {{
79- setType ("continue" );
80- setValue (new TaskModuleTaskInfo () {{
81- setCard (adaptiveCard );
82- setHeight (200 );
83- setWidth (400 );
84- setTitle ("Adaptive Card: Inputs" );
85- }});
86- }});
87- }};
88- });
107+ // Display an AdaptiveCard to prompt user for text, and post it back via
108+ // onTeamsTaskModuleSubmit.
109+ case TaskModuleIds .ADAPTIVECARD :
110+ taskInfo .setCard (createAdaptiveCardAttachment ());
111+ setTaskInfo (taskInfo , TaskModuleUIConstants .ADAPTIVECARD );
112+ break ;
113+
114+ default :
115+ break ;
116+ }
117+
118+ return taskInfo ;
119+ })
120+ .thenApply (TaskModuleResponseFactory ::toTaskModuleResponse );
89121 }
90122
91123 @ Override
92124 protected CompletableFuture <TaskModuleResponse > onTeamsTaskModuleSubmit (
93125 TurnContext turnContext ,
94126 TaskModuleRequest taskModuleRequest
95127 ) {
96- Activity reply ;
97- try {
98- reply = MessageFactory .text (
99- "onTeamsTaskModuleSubmit TaskModuleRequest: " +
100- new ObjectMapper ().writeValueAsString (taskModuleRequest ));
101- } catch (JsonProcessingException e ) {
102- CompletableFuture <TaskModuleResponse > result = new CompletableFuture <>();
103- result .completeExceptionally (new CompletionException (e ));
104- return result ;
105- }
106-
107- turnContext .sendActivity (reply )
108- .thenApply (resourceResponse -> null );
128+ // Called when data is being returned from the selected option (see `onTeamsTaskModuleFetch').
129+ return Async .tryCompletion (() ->
130+ // Echo the users input back. In a production bot, this is where you'd add behavior in
131+ // response to the input.
132+ MessageFactory .text (
133+ "onTeamsTaskModuleSubmit TaskModuleRequest: "
134+ + new ObjectMapper ().writeValueAsString (taskModuleRequest )
135+ )
136+ )
137+ .thenCompose (turnContext ::sendActivity )
138+ .thenApply (resourceResponse -> TaskModuleResponseFactory .createResponse ("Thanks!" ));
139+ }
109140
110- return CompletableFuture .completedFuture (new TaskModuleResponse () {{
111- setTask (new TaskModuleMessageResponse () {{
112- setType ("message" );
113- setValue ("Thanks!" );
114- }});
115- }});
141+ private void setTaskInfo (TaskModuleTaskInfo taskInfo , UISettings uiSettings ) {
142+ taskInfo .setHeight (uiSettings .getHeight ());
143+ taskInfo .setWidth (uiSettings .getWidth ());
144+ taskInfo .setTitle (uiSettings .getTitle ());
116145 }
117146
118- private Attachment getTaskModuleHeroCard () {
147+ private Attachment getTaskModuleHeroCardOptions () {
148+ List <CardAction > buttons = actions .stream ().map (cardType ->
149+ new TaskModuleAction (cardType .getButtonTitle (),
150+ new CardTaskFetchValue <String >() {{
151+ setData (cardType .getId ());
152+ }})
153+ ).collect (Collectors .toCollection (ArrayList ::new ));
154+
119155 HeroCard card = new HeroCard () {{
120156 setTitle ("Task Module Invocation from Hero Card" );
121- setSubtitle (
122- "This is a hero card with a Task Module Action button. Click the button to show an Adaptive Card within a Task Module." );
123- setButtons (Arrays .asList (
124- new TaskModuleAction (
125- "Adaptive Card" ,
126- new JSONObject ().put (
127- "data" ,
128- "adaptivecard"
129- ).toString ()
130- )
131- ));
157+ setButtons (buttons );
132158 }};
133159 return card .toAttachment ();
134160 }
135161
136- private Attachment getTaskModuleAdaptiveCard () {
137- try {
138- InputStream inputStream = getClass ().getClassLoader ()
139- .getResourceAsStream ("adaptivecard.json" );
140- String result = IOUtils .toString (inputStream , StandardCharsets .UTF_8 );
162+ private Attachment getTaskModuleAdaptiveCardOptions () {
163+ try (InputStream inputStream = getClass ().getClassLoader ()
164+ .getResourceAsStream ("adaptiveTemplate.json" )
165+ ) {
166+ String cardTemplate = IOUtils .toString (inputStream , StandardCharsets .UTF_8 );
167+
168+ List <Map <String ,Object >> cardActions = actions .stream ().map (cardType -> {
169+ Map <String , Object > a = new HashMap <>();
170+ a .put ("type" , "Action.Submit" );
171+ a .put ("title" , cardType .getButtonTitle ());
172+ a .put ("data" , new AdaptiveCardTaskFetchValue <String >() {{
173+ setData (cardType .getId ());
174+ }});
175+ return a ;
176+ }).collect (Collectors .toCollection (ArrayList ::new ));
177+
178+ String adaptiveCardJson = String .format (cardTemplate , Serialization .toString (cardActions ));
141179
142- return new Attachment () {{
143- setContentType ("application/vnd.microsoft.card.adaptive" );
144- setContent (new ObjectMapper ().readValue (result , ObjectNode .class ));
145- }};
180+ return adaptiveCardAttachmentFromJson (adaptiveCardJson );
146181 } catch (Throwable t ) {
147182 throw new CompletionException (t );
148183 }
149184 }
185+
186+ private Attachment createAdaptiveCardAttachment () {
187+ try (InputStream inputStream = getClass ().getClassLoader ()
188+ .getResourceAsStream ("adaptivecard.json" )
189+ ) {
190+ String result = IOUtils .toString (inputStream , StandardCharsets .UTF_8 );
191+ return adaptiveCardAttachmentFromJson (result );
192+ } catch (Throwable t ) {
193+ throw new CompletionException (t );
194+ }
195+ }
196+
197+ private Attachment adaptiveCardAttachmentFromJson (String json ) throws IOException {
198+ return new Attachment () {{
199+ setContentType ("application/vnd.microsoft.card.adaptive" );
200+ setContent (new ObjectMapper ().readValue (json , ObjectNode .class ));
201+ }};
202+ }
150203}
0 commit comments