Skip to content
This repository was archived by the owner on Dec 4, 2023. It is now read-only.

Commit 1961cca

Browse files
authored
Added Teams meeting start/end (#1260)
* Added Teams meeting start/end * Switched to using OffsetDateTime instead of String for Teams meeting models * Accept case insensitive properties in JSON * Corrected unit test after case insensitive JSON change * Corrected MeetingEndEventDetails superclass * Added TeamsInfo.getMeetingInfo overload to allow optional meetingId
1 parent 5a9d1cf commit 1961cca

File tree

11 files changed

+532
-249
lines changed

11 files changed

+532
-249
lines changed

libraries/bot-builder/src/main/java/com/microsoft/bot/builder/teams/TeamsActivityHandler.java

Lines changed: 221 additions & 161 deletions
Large diffs are not rendered by default.

libraries/bot-builder/src/main/java/com/microsoft/bot/builder/teams/TeamsInfo.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,15 @@ public static CompletableFuture<TeamsMeetingParticipant> getMeetingParticipant(
270270
);
271271
}
272272

273+
/**
274+
* Gets the information for the given meeting id.
275+
* @param turnContext Turn context.
276+
* @return Meeting Details.
277+
*/
278+
public static CompletableFuture<MeetingInfo> getMeetingInfo(TurnContext turnContext) {
279+
return getMeetingInfo(turnContext, null);
280+
}
281+
273282
/**
274283
* Gets the information for the given meeting id.
275284
* @param turnContext Turn context.

libraries/bot-builder/src/test/java/com/microsoft/bot/builder/teams/TeamsActivityHandlerTests.java

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,13 @@
2424
import com.microsoft.bot.schema.ConversationReference;
2525
import com.microsoft.bot.schema.ConversationResourceResponse;
2626
import com.microsoft.bot.schema.ResourceResponse;
27+
import com.microsoft.bot.schema.Serialization;
2728
import com.microsoft.bot.schema.teams.AppBasedLinkQuery;
2829
import com.microsoft.bot.schema.teams.ChannelInfo;
2930
import com.microsoft.bot.schema.teams.FileConsentCardResponse;
3031
import com.microsoft.bot.schema.teams.FileUploadInfo;
32+
import com.microsoft.bot.schema.teams.MeetingEndEventDetails;
33+
import com.microsoft.bot.schema.teams.MeetingStartEventDetails;
3134
import com.microsoft.bot.schema.teams.MessagingExtensionAction;
3235
import com.microsoft.bot.schema.teams.MessagingExtensionActionResponse;
3336
import com.microsoft.bot.schema.teams.MessagingExtensionQuery;
@@ -39,6 +42,7 @@
3942
import com.microsoft.bot.schema.teams.TeamInfo;
4043
import com.microsoft.bot.schema.teams.TeamsChannelAccount;
4144
import com.microsoft.bot.schema.teams.TeamsChannelData;
45+
import java.io.IOException;
4246
import org.apache.commons.lang3.NotImplementedException;
4347
import org.junit.Assert;
4448
import org.junit.Test;
@@ -857,6 +861,80 @@ public void TestSigninVerifyState() {
857861
);
858862
}
859863

864+
@Test
865+
public void TestOnEventActivity() {
866+
// Arrange
867+
Activity activity = new Activity(ActivityTypes.EVENT);
868+
activity.setChannelId(Channels.DIRECTLINE);
869+
870+
TurnContext turnContext = new TurnContextImpl(new SimpleAdapter(), activity);
871+
872+
// Act
873+
TestActivityHandler bot = new TestActivityHandler();
874+
bot.onTurn(turnContext).join();
875+
876+
// Assert
877+
Assert.assertEquals(1, bot.record.size());
878+
Assert.assertEquals("onEventActivity", bot.record.get(0));
879+
}
880+
881+
@Test
882+
public void TestMeetingStartEvent() throws IOException {
883+
// Arrange
884+
Activity activity = new Activity(ActivityTypes.EVENT);
885+
activity.setChannelId(Channels.MSTEAMS);
886+
activity.setName("application/vnd.microsoft.meetingStart");
887+
activity.setValue(Serialization.jsonToTree("{\"StartTime\": \"2021-06-05T00:01:02.0Z\"}"));
888+
889+
AtomicReference<List<Activity>> activitiesToSend = new AtomicReference<>();
890+
891+
TurnContext turnContext = new TurnContextImpl(
892+
new SimpleAdapter(activitiesToSend::set),
893+
activity
894+
);
895+
896+
// Act
897+
TestActivityHandler bot = new TestActivityHandler();
898+
bot.onTurn(turnContext).join();
899+
900+
// Assert
901+
Assert.assertEquals(2, bot.record.size());
902+
Assert.assertEquals("onEventActivity", bot.record.get(0));
903+
Assert.assertEquals("onTeamsMeetingStart", bot.record.get(1));
904+
905+
Assert.assertNotNull(activitiesToSend.get());
906+
Assert.assertEquals(1, activitiesToSend.get().size());
907+
Assert.assertTrue(activitiesToSend.get().get(0).getText().contains("00:01:02"));
908+
}
909+
910+
@Test
911+
public void TestMeetingEndEvent() throws IOException {
912+
// Arrange
913+
Activity activity = new Activity(ActivityTypes.EVENT);
914+
activity.setChannelId(Channels.MSTEAMS);
915+
activity.setName("application/vnd.microsoft.meetingEnd");
916+
activity.setValue(Serialization.jsonToTree("{\"EndTime\": \"2021-06-05T01:02:03.0Z\"}"));
917+
918+
AtomicReference<List<Activity>> activitiesToSend = new AtomicReference<>();
919+
920+
TurnContext turnContext = new TurnContextImpl(
921+
new SimpleAdapter(activitiesToSend::set),
922+
activity
923+
);
924+
925+
// Act
926+
TestActivityHandler bot = new TestActivityHandler();
927+
bot.onTurn(turnContext).join();
928+
929+
// Assert
930+
Assert.assertEquals(2, bot.record.size());
931+
Assert.assertEquals("onEventActivity", bot.record.get(0));
932+
Assert.assertEquals("onTeamsMeetingEnd", bot.record.get(1));
933+
Assert.assertNotNull(activitiesToSend.get());
934+
Assert.assertEquals(1, activitiesToSend.get().size());
935+
Assert.assertTrue(activitiesToSend.get().get(0).getText().contains("1:02:03"));
936+
}
937+
860938
private static class NotImplementedAdapter extends BotAdapter {
861939

862940
@Override
@@ -1209,6 +1287,34 @@ protected CompletableFuture<Void> onTeamsTeamUnarchived(
12091287
record.add("onTeamsTeamUnarchived");
12101288
return super.onTeamsTeamUnarchived(channelInfo, teamInfo, turnContext);
12111289
}
1290+
1291+
@Override
1292+
protected CompletableFuture<Void> onEventActivity(
1293+
TurnContext turnContext
1294+
) {
1295+
record.add("onEventActivity");
1296+
return super.onEventActivity(turnContext);
1297+
}
1298+
1299+
@Override
1300+
protected CompletableFuture<Void> onTeamsMeetingStart(
1301+
MeetingStartEventDetails meeting,
1302+
TurnContext turnContext
1303+
) {
1304+
record.add("onTeamsMeetingStart");
1305+
return turnContext.sendActivity(meeting.getStartTime().toString())
1306+
.thenCompose(resourceResponse -> super.onTeamsMeetingStart(meeting, turnContext));
1307+
}
1308+
1309+
@Override
1310+
protected CompletableFuture<Void> onTeamsMeetingEnd(
1311+
MeetingEndEventDetails meeting,
1312+
TurnContext turnContext
1313+
) {
1314+
record.add("onTeamsMeetingEnd");
1315+
return turnContext.sendActivity(meeting.getEndTime().toString())
1316+
.thenCompose(resourceResponse -> super.onTeamsMeetingEnd(meeting, turnContext));
1317+
}
12121318
}
12131319

12141320
private static ConnectorClient getConnectorClient(String baseUri, AppCredentials credentials) {

libraries/bot-connector/src/main/java/com/microsoft/bot/restclient/serializer/JacksonAdapter.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.fasterxml.jackson.annotation.JsonInclude;
88
import com.fasterxml.jackson.databind.DeserializationFeature;
99
import com.fasterxml.jackson.databind.JavaType;
10+
import com.fasterxml.jackson.databind.MapperFeature;
1011
import com.fasterxml.jackson.databind.ObjectMapper;
1112
import com.fasterxml.jackson.databind.SerializationFeature;
1213
import com.fasterxml.jackson.databind.type.TypeBindings;
@@ -143,7 +144,8 @@ private static ObjectMapper initializeObjectMapper(ObjectMapper mapper) {
143144
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
144145
.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true)
145146
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
146-
.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true)
147+
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
148+
.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
147149
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
148150
.registerModule(new Jdk8Module())
149151
.registerModule(new JavaTimeModule())

libraries/bot-schema/src/main/java/com/microsoft/bot/schema/Serialization.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.fasterxml.jackson.core.JsonProcessingException;
77
import com.fasterxml.jackson.databind.DeserializationFeature;
88
import com.fasterxml.jackson.databind.JsonNode;
9+
import com.fasterxml.jackson.databind.MapperFeature;
910
import com.fasterxml.jackson.databind.ObjectMapper;
1011

1112
import com.fasterxml.jackson.databind.node.ArrayNode;
@@ -27,6 +28,7 @@ private Serialization() {
2728
static {
2829
objectMapper = new ObjectMapper();
2930
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
31+
objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
3032
objectMapper.findAndRegisterModules();
3133

3234
// NOTE: Undetermined if we should accommodate non-public fields. The normal

libraries/bot-schema/src/main/java/com/microsoft/bot/schema/teams/MeetingDetails.java

Lines changed: 16 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -4,59 +4,27 @@
44
package com.microsoft.bot.schema.teams;
55

66
import com.fasterxml.jackson.annotation.JsonProperty;
7+
import java.time.OffsetDateTime;
78

89
/**
910
* Specific details of a Teams meeting.
1011
*/
11-
public class MeetingDetails {
12-
@JsonProperty(value = "id")
13-
private String id;
14-
12+
public class MeetingDetails extends MeetingDetailsBase {
1513
@JsonProperty(value = "msGraphResourceId")
1614
private String msGraphResourceId;
1715

1816
@JsonProperty(value = "scheduledStartTime")
19-
private String scheduledStartTime;
17+
private OffsetDateTime scheduledStartTime;
2018

2119
@JsonProperty(value = "scheduledEndTime")
22-
private String scheduledEndTime;
23-
24-
@JsonProperty(value = "joinUrl")
25-
private String joinUrl;
26-
27-
@JsonProperty(value = "title")
28-
private String title;
20+
private OffsetDateTime scheduledEndTime;
2921

3022
@JsonProperty(value = "type")
3123
private String type;
3224

33-
/**
34-
* Initializes a new instance.
35-
*/
36-
public MeetingDetails() {
37-
}
38-
39-
/**
40-
* Gets the meeting's Id, encoded as a BASE64 String.
41-
*
42-
* @return The meeting's Id, encoded as a BASE64 String.
43-
*/
44-
public String getId() {
45-
return id;
46-
}
47-
48-
/**
49-
* Sets the meeting's Id, encoded as a BASE64 String.
50-
*
51-
* @param withId The meeting's Id, encoded as a BASE64 String.
52-
*/
53-
public void setId(String withId) {
54-
id = withId;
55-
}
56-
5725
/**
5826
* Gets the MsGraphResourceId, used specifically for MS Graph API calls.
59-
*
27+
*
6028
* @return The MsGraphResourceId, used specifically for MS Graph API calls.
6129
*/
6230
public String getMsGraphResourceId() {
@@ -65,7 +33,7 @@ public String getMsGraphResourceId() {
6533

6634
/**
6735
* Sets the MsGraphResourceId, used specifically for MS Graph API calls.
68-
*
36+
*
6937
* @param withMsGraphResourceId The MsGraphResourceId, used specifically for MS
7038
* Graph API calls.
7139
*/
@@ -75,79 +43,43 @@ public void setMsGraphResourceId(String withMsGraphResourceId) {
7543

7644
/**
7745
* Gets the meeting's scheduled start time, in UTC.
78-
*
46+
*
7947
* @return The meeting's scheduled start time, in UTC.
8048
*/
81-
public String getScheduledStartTime() {
49+
public OffsetDateTime getScheduledStartTime() {
8250
return scheduledStartTime;
8351
}
8452

8553
/**
8654
* Sets the meeting's scheduled start time, in UTC.
87-
*
55+
*
8856
* @param withScheduledStartTime The meeting's scheduled start time, in UTC.
8957
*/
90-
public void setScheduledStartTime(String withScheduledStartTime) {
58+
public void setScheduledStartTime(OffsetDateTime withScheduledStartTime) {
9159
scheduledStartTime = withScheduledStartTime;
9260
}
9361

9462
/**
9563
* Gets the meeting's scheduled end time, in UTC.
96-
*
64+
*
9765
* @return The meeting's scheduled end time, in UTC.
9866
*/
99-
public String getScheduledEndTime() {
67+
public OffsetDateTime getScheduledEndTime() {
10068
return scheduledEndTime;
10169
}
10270

10371
/**
10472
* Sets the meeting's scheduled end time, in UTC.
105-
*
73+
*
10674
* @param withScheduledEndTime The meeting's scheduled end time, in UTC.
10775
*/
108-
public void setScheduledEndTime(String withScheduledEndTime) {
76+
public void setScheduledEndTime(OffsetDateTime withScheduledEndTime) {
10977
scheduledEndTime = withScheduledEndTime;
11078
}
11179

112-
/**
113-
* Gets the URL used to join the meeting.
114-
*
115-
* @return The URL used to join the meeting.
116-
*/
117-
public String getJoinUrl() {
118-
return joinUrl;
119-
}
120-
121-
/**
122-
* Sets the URL used to join the meeting.
123-
*
124-
* @param withJoinUrl The URL used to join the meeting.
125-
*/
126-
public void setJoinUrl(String withJoinUrl) {
127-
joinUrl = withJoinUrl;
128-
}
129-
130-
/**
131-
* Gets the title of the meeting.
132-
*
133-
* @return The title of the meeting.
134-
*/
135-
public String getTitle() {
136-
return title;
137-
}
138-
139-
/**
140-
* Sets the title of the meeting.
141-
*
142-
* @param withTitle The title of the meeting.
143-
*/
144-
public void setTitle(String withTitle) {
145-
title = withTitle;
146-
}
147-
14880
/**
14981
* Gets the meeting's type.
150-
*
82+
*
15183
* @return The meeting's type.
15284
*/
15385
public String getType() {
@@ -156,7 +88,7 @@ public String getType() {
15688

15789
/**
15890
* Sets the meeting's type.
159-
*
91+
*
16092
* @param withType The meeting's type.
16193
*/
16294
public void setType(String withType) {

0 commit comments

Comments
 (0)