From 5a9d1cf104d1b69da552e631b45e8ee1265dd0bf Mon Sep 17 00:00:00 2001 From: tracyboehrer Date: Thu, 17 Jun 2021 08:04:03 -0500 Subject: [PATCH] Added TeamsInfo.fetchMeetingInfo (#1233) --- .../bot/builder/teams/TeamsInfo.java | 19 ++ .../bot/builder/teams/TeamsInfoTests.java | 59 +++++++ .../connector/rest/RestTeamsOperations.java | 43 +++++ .../bot/connector/teams/TeamsOperations.java | 12 ++ .../bot/schema/teams/MeetingDetails.java | 165 ++++++++++++++++++ .../bot/schema/teams/MeetingInfo.java | 81 +++++++++ 6 files changed, 379 insertions(+) create mode 100644 libraries/bot-schema/src/main/java/com/microsoft/bot/schema/teams/MeetingDetails.java create mode 100644 libraries/bot-schema/src/main/java/com/microsoft/bot/schema/teams/MeetingInfo.java diff --git a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/teams/TeamsInfo.java b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/teams/TeamsInfo.java index 65f65c780..5b93c4688 100644 --- a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/teams/TeamsInfo.java +++ b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/teams/TeamsInfo.java @@ -17,6 +17,7 @@ import com.microsoft.bot.schema.Serialization; import com.microsoft.bot.schema.teams.ChannelInfo; import com.microsoft.bot.schema.teams.ConversationList; +import com.microsoft.bot.schema.teams.MeetingInfo; import com.microsoft.bot.schema.teams.TeamDetails; import com.microsoft.bot.schema.teams.TeamsChannelAccount; import com.microsoft.bot.schema.teams.TeamsChannelData; @@ -269,6 +270,24 @@ public static CompletableFuture getMeetingParticipant( ); } + /** + * Gets the information for the given meeting id. + * @param turnContext Turn context. + * @param meetingId The BASE64-encoded id of the Teams meeting. + * @return Meeting Details. + */ + public static CompletableFuture getMeetingInfo(TurnContext turnContext, String meetingId) { + if (StringUtils.isEmpty(meetingId) && turnContext.getActivity().teamsGetMeetingInfo() != null) { + meetingId = turnContext.getActivity().teamsGetMeetingInfo().getId(); + } + + if (StringUtils.isEmpty(meetingId)) { + return illegalArgument("TeamsInfo.getMeetingInfo: method requires a meetingId"); + } + + return getTeamsConnectorClient(turnContext).getTeams().fetchMeetingInfo(meetingId); + } + private static CompletableFuture> getMembers( ConnectorClient connectorClient, String conversationId diff --git a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/teams/TeamsInfoTests.java b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/teams/TeamsInfoTests.java index cd47f251e..942590aa8 100644 --- a/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/teams/TeamsInfoTests.java +++ b/libraries/bot-builder/src/test/java/com/microsoft/bot/builder/teams/TeamsInfoTests.java @@ -29,10 +29,13 @@ import com.microsoft.bot.schema.Pair; import com.microsoft.bot.schema.teams.ChannelInfo; import com.microsoft.bot.schema.teams.ConversationList; +import com.microsoft.bot.schema.teams.MeetingDetails; +import com.microsoft.bot.schema.teams.MeetingInfo; import com.microsoft.bot.schema.teams.TeamDetails; import com.microsoft.bot.schema.teams.TeamInfo; import com.microsoft.bot.schema.teams.TeamsChannelAccount; import com.microsoft.bot.schema.teams.TeamsChannelData; +import com.microsoft.bot.schema.teams.TeamsMeetingInfo; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -176,6 +179,31 @@ public void TestGetChannels() { handler.onTurn(turnContext).join(); } + @Test + public void TestGetMeetingInfo() { + String baseUri = "https://test.coffee"; + MicrosoftAppCredentials credentials = MicrosoftAppCredentials.empty(); + ConnectorClient connectorClient = getConnectorClient(baseUri, credentials); + + Activity activity = new Activity(ActivityTypes.MESSAGE); + activity.setText("Test-GetMeetingInfoAsync"); + activity.setChannelId(Channels.MSTEAMS); + TeamsChannelData data = new TeamsChannelData(); + data.setMeeting(new TeamsMeetingInfo("meeting-id")); + activity.setChannelData(data); + + TurnContext turnContext = new TurnContextImpl(new SimpleAdapter(), activity); + turnContext.getTurnState().add(BotFrameworkAdapter.CONNECTOR_CLIENT_KEY, connectorClient); + turnContext.getTurnState().add( + BotFrameworkAdapter.TEAMSCONNECTOR_CLIENT_KEY, + getTeamsConnectorClient(connectorClient.baseUrl(), credentials) + ); + turnContext.getActivity().setServiceUrl("https://test.coffee"); + + ActivityHandler handler = new TestTeamsActivityHandler(); + handler.onTurn(turnContext).join(); + } + private class TestBotFrameworkAdapter extends BotFrameworkAdapter { public TestBotFrameworkAdapter(CredentialProvider withCredentialProvider) { @@ -213,6 +241,9 @@ public CompletableFuture onTurn(TurnContext turnContext) { case "Test-SendMessageToTeamsChannelAsync": return callSendMessageToTeamsChannel(turnContext); + case "Test-GetMeetingInfoAsync": + return callTeamsInfoGetMeetingInfo(turnContext); + default: Assert.fail(); } @@ -308,6 +339,16 @@ private CompletableFuture callGetChannels(TurnContext turnContext) { return CompletableFuture.completedFuture(null); } + + private CompletableFuture callTeamsInfoGetMeetingInfo(TurnContext turnContext) { + MeetingInfo meeting = TeamsInfo.getMeetingInfo(turnContext, null).join(); + + Assert.assertEquals("meeting-id", meeting.getDetails().getId()); + Assert.assertEquals("organizer-id", meeting.getOrganizer().getId()); + Assert.assertEquals("meetingConversationId-1", meeting.getConversation().getId()); + + return CompletableFuture.completedFuture(null); + } } private static ConnectorClient getConnectorClient(String baseUri, AppCredentials credentials) { @@ -412,6 +453,24 @@ private static TeamsConnectorClient getTeamsConnectorClient( CompletableFuture.completedFuture(details) ); + // fetchTeamDetails + MeetingInfo meetingInfo = new MeetingInfo(); + MeetingDetails meetingDetails = new MeetingDetails(); + meetingDetails.setId("meeting-id"); + meetingInfo.setDetails(meetingDetails); + + TeamsChannelAccount organizer = new TeamsChannelAccount(); + organizer.setId("organizer-id"); + meetingInfo.setOrganizer(organizer); + + ConversationAccount conversationAccount = new ConversationAccount(); + conversationAccount.setId("meetingConversationId-1"); + meetingInfo.setConversation(conversationAccount); + + Mockito.when(mockOperations.fetchMeetingInfo(Mockito.anyString())).thenReturn( + CompletableFuture.completedFuture(meetingInfo) + ); + TeamsConnectorClient mockConnectorClient = Mockito.mock(TeamsConnectorClient.class); Mockito.when(mockConnectorClient.getTeams()).thenReturn(mockOperations); Mockito.when(mockConnectorClient.baseUrl()).thenReturn(baseUri); diff --git a/libraries/bot-connector/src/main/java/com/microsoft/bot/connector/rest/RestTeamsOperations.java b/libraries/bot-connector/src/main/java/com/microsoft/bot/connector/rest/RestTeamsOperations.java index bf1367450..4c6c7caed 100644 --- a/libraries/bot-connector/src/main/java/com/microsoft/bot/connector/rest/RestTeamsOperations.java +++ b/libraries/bot-connector/src/main/java/com/microsoft/bot/connector/rest/RestTeamsOperations.java @@ -11,6 +11,7 @@ import com.microsoft.bot.connector.teams.TeamsOperations; import com.microsoft.bot.restclient.ServiceResponse; import com.microsoft.bot.schema.teams.ConversationList; +import com.microsoft.bot.schema.teams.MeetingInfo; import com.microsoft.bot.schema.teams.TeamDetails; import com.microsoft.bot.schema.teams.TeamsMeetingParticipant; import okhttp3.ResponseBody; @@ -162,6 +163,39 @@ private ServiceResponse fetchParticipantDelegate( .build(response); } + /** + * Fetches Teams meeting participant details. + * @param meetingId Teams meeting id + * @return TeamsParticipantChannelAccount + */ + @Override + public CompletableFuture fetchMeetingInfo(String meetingId) { + return service.fetchMeetingInfo( + meetingId, client.getAcceptLanguage(), client.getUserAgent() + ) + .thenApply(responseBodyResponse -> { + try { + return fetchMeetingInfoDelegate(responseBodyResponse).body(); + } catch (ErrorResponseException e) { + throw e; + } catch (Throwable t) { + throw new ErrorResponseException("fetchMeetingInfo", responseBodyResponse); + } + }); + } + + private ServiceResponse fetchMeetingInfoDelegate( + Response response + ) throws ErrorResponseException, IOException, IllegalArgumentException { + return client.restClient() + .responseBuilderFactory() + .newInstance(client.serializerAdapter()) + .register(HttpURLConnection.HTTP_OK, new TypeToken() { + }.getType()) + .registerError(ErrorResponseException.class) + .build(response); + } + /** * The interface defining all the services for TeamsOperations to be used by * Retrofit to perform actually REST calls. @@ -196,5 +230,14 @@ CompletableFuture> fetchParticipant( @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent ); + + @Headers({ "Content-Type: application/json; charset=utf-8", + "x-ms-logging-context: com.microsoft.bot.schema.Teams fetchMeetingInfo" }) + @GET("v1/meetings/{meetingId}") + CompletableFuture> fetchMeetingInfo( + @Path("meetingId") String meetingId, + @Header("accept-language") String acceptLanguage, + @Header("User-Agent") String userAgent + ); } } diff --git a/libraries/bot-connector/src/main/java/com/microsoft/bot/connector/teams/TeamsOperations.java b/libraries/bot-connector/src/main/java/com/microsoft/bot/connector/teams/TeamsOperations.java index 85889c789..b65d1fdd0 100644 --- a/libraries/bot-connector/src/main/java/com/microsoft/bot/connector/teams/TeamsOperations.java +++ b/libraries/bot-connector/src/main/java/com/microsoft/bot/connector/teams/TeamsOperations.java @@ -11,6 +11,7 @@ package com.microsoft.bot.connector.teams; import com.microsoft.bot.schema.teams.ConversationList; +import com.microsoft.bot.schema.teams.MeetingInfo; import com.microsoft.bot.schema.teams.TeamDetails; import com.microsoft.bot.schema.teams.TeamsMeetingParticipant; @@ -48,4 +49,15 @@ CompletableFuture fetchParticipant( String participantId, String tenantId ); + + /** + * Fetches information related to a Teams meeting. + * @param meetingId Meeting Id. + * @return The details related to a team. + */ + default CompletableFuture fetchMeetingInfo(String meetingId) { + CompletableFuture result = new CompletableFuture<>(); + result.completeExceptionally(new Exception("fetchMeetingInfo not implemented")); + return result; + } } diff --git a/libraries/bot-schema/src/main/java/com/microsoft/bot/schema/teams/MeetingDetails.java b/libraries/bot-schema/src/main/java/com/microsoft/bot/schema/teams/MeetingDetails.java new file mode 100644 index 000000000..04d309b6d --- /dev/null +++ b/libraries/bot-schema/src/main/java/com/microsoft/bot/schema/teams/MeetingDetails.java @@ -0,0 +1,165 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.bot.schema.teams; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Specific details of a Teams meeting. + */ +public class MeetingDetails { + @JsonProperty(value = "id") + private String id; + + @JsonProperty(value = "msGraphResourceId") + private String msGraphResourceId; + + @JsonProperty(value = "scheduledStartTime") + private String scheduledStartTime; + + @JsonProperty(value = "scheduledEndTime") + private String scheduledEndTime; + + @JsonProperty(value = "joinUrl") + private String joinUrl; + + @JsonProperty(value = "title") + private String title; + + @JsonProperty(value = "type") + private String type; + + /** + * Initializes a new instance. + */ + public MeetingDetails() { + } + + /** + * Gets the meeting's Id, encoded as a BASE64 String. + * + * @return The meeting's Id, encoded as a BASE64 String. + */ + public String getId() { + return id; + } + + /** + * Sets the meeting's Id, encoded as a BASE64 String. + * + * @param withId The meeting's Id, encoded as a BASE64 String. + */ + public void setId(String withId) { + id = withId; + } + + /** + * Gets the MsGraphResourceId, used specifically for MS Graph API calls. + * + * @return The MsGraphResourceId, used specifically for MS Graph API calls. + */ + public String getMsGraphResourceId() { + return msGraphResourceId; + } + + /** + * Sets the MsGraphResourceId, used specifically for MS Graph API calls. + * + * @param withMsGraphResourceId The MsGraphResourceId, used specifically for MS + * Graph API calls. + */ + public void setMsGraphResourceId(String withMsGraphResourceId) { + msGraphResourceId = withMsGraphResourceId; + } + + /** + * Gets the meeting's scheduled start time, in UTC. + * + * @return The meeting's scheduled start time, in UTC. + */ + public String getScheduledStartTime() { + return scheduledStartTime; + } + + /** + * Sets the meeting's scheduled start time, in UTC. + * + * @param withScheduledStartTime The meeting's scheduled start time, in UTC. + */ + public void setScheduledStartTime(String withScheduledStartTime) { + scheduledStartTime = withScheduledStartTime; + } + + /** + * Gets the meeting's scheduled end time, in UTC. + * + * @return The meeting's scheduled end time, in UTC. + */ + public String getScheduledEndTime() { + return scheduledEndTime; + } + + /** + * Sets the meeting's scheduled end time, in UTC. + * + * @param withScheduledEndTime The meeting's scheduled end time, in UTC. + */ + public void setScheduledEndTime(String withScheduledEndTime) { + scheduledEndTime = withScheduledEndTime; + } + + /** + * Gets the URL used to join the meeting. + * + * @return The URL used to join the meeting. + */ + public String getJoinUrl() { + return joinUrl; + } + + /** + * Sets the URL used to join the meeting. + * + * @param withJoinUrl The URL used to join the meeting. + */ + public void setJoinUrl(String withJoinUrl) { + joinUrl = withJoinUrl; + } + + /** + * Gets the title of the meeting. + * + * @return The title of the meeting. + */ + public String getTitle() { + return title; + } + + /** + * Sets the title of the meeting. + * + * @param withTitle The title of the meeting. + */ + public void setTitle(String withTitle) { + title = withTitle; + } + + /** + * Gets the meeting's type. + * + * @return The meeting's type. + */ + public String getType() { + return type; + } + + /** + * Sets the meeting's type. + * + * @param withType The meeting's type. + */ + public void setType(String withType) { + type = withType; + } +} diff --git a/libraries/bot-schema/src/main/java/com/microsoft/bot/schema/teams/MeetingInfo.java b/libraries/bot-schema/src/main/java/com/microsoft/bot/schema/teams/MeetingInfo.java new file mode 100644 index 000000000..cbf33948c --- /dev/null +++ b/libraries/bot-schema/src/main/java/com/microsoft/bot/schema/teams/MeetingInfo.java @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.bot.schema.teams; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.bot.schema.ConversationAccount; + +/** + * General information about a Teams meeting. + */ +public class MeetingInfo { + @JsonProperty(value = "details") + private MeetingDetails details; + + @JsonProperty(value = "conversation") + private ConversationAccount conversation; + + @JsonProperty(value = "organizer") + private TeamsChannelAccount organizer; + + /** + * Initializes a new instance. + */ + public MeetingInfo() { + } + + /** + * Gets the specific details of a Teams meeting. + * + * @return The specific details of a Teams meeting. + */ + public MeetingDetails getDetails() { + return details; + } + + /** + * Sets the specific details of a Teams meeting. + * + * @param withDetails The specific details of a Teams meeting. + */ + public void setDetails(MeetingDetails withDetails) { + details = withDetails; + } + + /** + * Gets the Conversation Account for the meeting. + * + * @return The Conversation Account for the meeting. + */ + public ConversationAccount getConversation() { + return conversation; + } + + /** + * Sets the Conversation Account for the meeting. + * + * @param withConversation The Conversation Account for the meeting. + */ + public void setConversation(ConversationAccount withConversation) { + conversation = withConversation; + } + + /** + * Gets the meeting organizer's user information. + * + * @return The organizer's user information. + */ + public TeamsChannelAccount getOrganizer() { + return organizer; + } + + /** + * Sets the meeting organizer's user information. + * + * @param withOrganizer The organizer's user information. + */ + public void setOrganizer(TeamsChannelAccount withOrganizer) { + organizer = withOrganizer; + } +}