Skip to content
This repository was archived by the owner on Jun 30, 2022. It is now read-only.

Commit 402f386

Browse files
KayMKMryanisgrig
authored andcommitted
[Calendar] return both tel number and meeting link when join meeting (#2338)
* add join meeting link * add test * add onlinemeetingurl check * rename EventJoinLink to OpenDefaultApp
1 parent 47643ef commit 402f386

File tree

10 files changed

+91
-5
lines changed

10 files changed

+91
-5
lines changed

skills/src/csharp/calendarskill/calendarskill/Dialogs/JoinEventDialog.cs

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
using Microsoft.Bot.Builder.Solutions.Util;
1717
using Microsoft.Bot.Connector.Authentication;
1818
using Microsoft.Bot.Schema;
19+
using Newtonsoft.Json;
1920

2021
namespace CalendarSkill.Dialogs
2122
{
@@ -94,6 +95,26 @@ private string GetDialInNumberFromMeeting(EventModel eventModel)
9495
return number.InnerText.Replace(telToken, string.Empty);
9596
}
9697

98+
private string GetTeamsMeetingLinkFromMeeting(EventModel eventModel)
99+
{
100+
if (string.IsNullOrEmpty(eventModel.Content))
101+
{
102+
return null;
103+
}
104+
105+
var body = eventModel.Content;
106+
var doc = new HtmlDocument();
107+
doc.LoadHtml(body);
108+
109+
var meetingLink = doc.DocumentNode.SelectSingleNode("//a[contains(string(), 'Join')][contains(string(), 'Microsoft')][contains(string(), 'Teams')][contains(string(), 'Meeting')]");
110+
if (meetingLink != null)
111+
{
112+
return meetingLink.GetAttributeValue("href", null);
113+
}
114+
115+
return null;
116+
}
117+
97118
private bool IsValidJoinTime(TimeZoneInfo userTimeZone, EventModel e)
98119
{
99120
var startTime = TimeZoneInfo.ConvertTime(e.StartTime, TimeZoneInfo.Utc, userTimeZone);
@@ -165,7 +186,7 @@ private async Task<DialogTurnResult> CheckValid(WaterfallStepContext sc, Cancell
165186
var validEvents = new List<EventModel>();
166187
foreach (var item in state.ShowMeetingInfor.ShowingMeetings)
167188
{
168-
if (IsValidJoinTime(state.GetUserTimeZone(), item) && GetDialInNumberFromMeeting(item) != null)
189+
if (IsValidJoinTime(state.GetUserTimeZone(), item) && (GetDialInNumberFromMeeting(item) != null || item.OnlineMeetingUrl != null || GetTeamsMeetingLinkFromMeeting(item) != null))
169190
{
170191
validEvents.Add(item);
171192
}
@@ -196,11 +217,16 @@ private async Task<DialogTurnResult> ConfirmNumber(WaterfallStepContext sc, Canc
196217

197218
var selectedEvent = state.ShowMeetingInfor.FocusedEvents.First();
198219
var phoneNumber = GetDialInNumberFromMeeting(selectedEvent);
220+
var meetingLink = selectedEvent.OnlineMeetingUrl ?? GetTeamsMeetingLinkFromMeeting(selectedEvent);
199221
var responseParams = new StringDictionary()
200222
{
201223
{ "PhoneNumber", phoneNumber },
224+
{ "MeetingLink", meetingLink }
202225
};
203-
return await sc.PromptAsync(Actions.TakeFurtherAction, new PromptOptions() { Prompt = ResponseManager.GetResponse(JoinEventResponses.ConfirmPhoneNumber, responseParams) });
226+
227+
var responseName = phoneNumber == null ? JoinEventResponses.ConfirmMeetingLink : JoinEventResponses.ConfirmPhoneNumber;
228+
229+
return await sc.PromptAsync(Actions.TakeFurtherAction, new PromptOptions() { Prompt = ResponseManager.GetResponse(responseName, responseParams) });
204230
}
205231
catch (Exception ex)
206232
{
@@ -222,8 +248,13 @@ private async Task<DialogTurnResult> AfterConfirmNumber(WaterfallStepContext sc,
222248
await sc.Context.SendActivityAsync(ResponseManager.GetResponse(JoinEventResponses.JoinMeeting));
223249
var replyEvent = sc.Context.Activity.CreateReply();
224250
replyEvent.Type = ActivityTypes.Event;
225-
replyEvent.Name = "JoinEvent.DialInNumber";
226-
replyEvent.Value = GetDialInNumberFromMeeting(selectedEvent);
251+
replyEvent.Name = "OpenDefaultApp";
252+
var eventJoinLink = new OpenDefaultApp
253+
{
254+
MeetingUri = selectedEvent.OnlineMeetingUrl ?? GetTeamsMeetingLinkFromMeeting(selectedEvent),
255+
TelephoneUri = GetDialInNumberFromMeeting(selectedEvent)
256+
};
257+
replyEvent.Value = JsonConvert.SerializeObject(eventJoinLink);
227258
await sc.Context.SendActivityAsync(replyEvent, cancellationToken);
228259
}
229260
else
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
6+
namespace CalendarSkill.Models
7+
{
8+
public class OpenDefaultApp
9+
{
10+
public string MeetingUri { get; set; }
11+
12+
public string TelephoneUri { get; set; }
13+
}
14+
}

skills/src/csharp/calendarskill/calendarskill/Responses/JoinEvent/JoinEventResponses.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public class JoinEventResponses : IResponseIdCollection
1616
public const string SelectMeeting = "SelectMeeting";
1717
public const string NotJoinMeeting = "NotJoinMeeting";
1818
public const string ConfirmPhoneNumber = "ConfirmPhoneNumber";
19+
public const string ConfirmMeetingLink = "ConfirmMeetingLink";
1920
public const string JoinMeeting = "JoinMeeting";
2021
public const string NoMeetingToConnect = "NoMeetingToConnect";
2122
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

skills/src/csharp/calendarskill/calendarskill/Responses/JoinEvent/JoinEventResponses.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@
3535
],
3636
"inputHint": "acceptingInput"
3737
},
38+
"ConfirmMeetingLink": {
39+
"replies": [
40+
{
41+
"text": "Here is the link I am about to join: {MeetingLink}. Please be aware that charges may apply. Do you want to proceed?",
42+
"speak": "Here is the link I am about to join: {MeetingLink}. Please be aware that charges may apply. Do you want to proceed?"
43+
}
44+
],
45+
"inputHint": "acceptingInput"
46+
},
3847
"JoinMeeting": {
3948
"replies": [
4049
{
Binary file not shown.

skills/src/csharp/calendarskill/calendarskilltest/Flow/ConnectToMeetingFlowTests.cs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public void SetupLuisService()
3333
}
3434

3535
[TestMethod]
36-
public async Task Test_CalendarJoinWithStartTimeEntity()
36+
public async Task Test_CalendarJoinNumberWithStartTimeEntity()
3737
{
3838
var now = DateTime.Now;
3939
var startTime = new DateTime(now.Year, now.Month, now.Day, 18, 0, 0);
@@ -58,11 +58,42 @@ await this.GetTestFlow()
5858
.StartTestAsync();
5959
}
6060

61+
[TestMethod]
62+
public async Task Test_CalendarJoinLinkWithStartTimeEntity()
63+
{
64+
var now = DateTime.Now;
65+
var startTime = new DateTime(now.Year, now.Month, now.Day, 18, 0, 0);
66+
startTime = startTime.AddDays(1);
67+
startTime = TimeZoneInfo.ConvertTimeToUtc(startTime);
68+
this.ServiceManager = MockServiceManager.SetMeetingsToSpecial(new List<EventModel>()
69+
{
70+
MockCalendarService.CreateEventModel(
71+
startDateTime: startTime,
72+
endDateTime: startTime.AddHours(1),
73+
content: "<a href=\"meetinglink\">Join Microsoft Teams Meeting</a>")
74+
});
75+
await this.GetTestFlow()
76+
.Send(ConnectToMeetingUtterances.JoinMeetingWithStartTime)
77+
.AssertReply(this.ShowAuth())
78+
.Send(this.GetAuthResponse())
79+
.AssertReplyOneOf(this.ConfirmMeetingLinkPrompt())
80+
.Send(Strings.Strings.ConfirmYes)
81+
.AssertReplyOneOf(this.JoinMeetingResponse())
82+
.AssertReply(this.JoinMeetingEvent())
83+
.AssertReply(this.ActionEndMessage())
84+
.StartTestAsync();
85+
}
86+
6187
private string[] ConfirmPhoneNumberPrompt()
6288
{
6389
return this.ParseReplies(JoinEventResponses.ConfirmPhoneNumber, new StringDictionary() { { "PhoneNumber", "12345678" } });
6490
}
6591

92+
private string[] ConfirmMeetingLinkPrompt()
93+
{
94+
return this.ParseReplies(JoinEventResponses.ConfirmMeetingLink, new StringDictionary() { { "MeetingLink", "meetinglink" } });
95+
}
96+
6697
private string[] JoinMeetingResponse()
6798
{
6899
return this.ParseReplies(JoinEventResponses.JoinMeeting, new StringDictionary());

0 commit comments

Comments
 (0)