Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix class structure for meeting notification feature extensibility #6579

Merged
merged 4 commits into from
Feb 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions libraries/Microsoft.Bot.Builder/Teams/TeamsInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -326,8 +326,8 @@ await turnContext.Adapter.CreateConversationAsync(
/// <param name="cancellationToken">Cancellation token.</param>
/// <remarks>InvalidOperationException will be thrown if meetingId or notification have not been
/// provided, and also cannot be retrieved from turnContext.Activity.</remarks>
/// <returns>List of <see cref="TeamsMeetingNotificationRecipientFailureInfo"/> for whom the notification failed.</returns>
public static async Task<TeamsMeetingNotificationRecipientFailureInfos> SendMeetingNotificationAsync(ITurnContext turnContext, TeamsMeetingNotification notification, string meetingId = null, CancellationToken cancellationToken = default)
/// <returns> <see cref="MeetingNotificationResponse"/>.</returns>
public static async Task<MeetingNotificationResponse> SendMeetingNotificationAsync(ITurnContext turnContext, MeetingNotificationBase notification, string meetingId = null, CancellationToken cancellationToken = default)
{
meetingId ??= turnContext.Activity.TeamsGetMeetingInfo()?.Id ?? throw new InvalidOperationException("This method is only valid within the scope of a MS Teams Meeting.");
notification = notification ?? throw new InvalidOperationException($"{nameof(notification)} is required.");
Expand Down
6 changes: 3 additions & 3 deletions libraries/Microsoft.Bot.Connector/Teams/TeamsOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ public TeamsOperations(TeamsConnectorClient client)
/// <returns>
/// A response object containing the response body and response headers.
/// </returns>
public async Task<HttpOperationResponse<TeamsMeetingNotificationRecipientFailureInfos>> SendMeetingNotificationMessageAsync(string meetingId, TeamsMeetingNotification notification, Dictionary<string, List<string>> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken))
public async Task<HttpOperationResponse<MeetingNotificationResponse>> SendMeetingNotificationMessageAsync(string meetingId, MeetingNotificationBase notification, Dictionary<string, List<string>> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken))
{
if (meetingId == null)
{
Expand Down Expand Up @@ -351,7 +351,7 @@ public TeamsOperations(TeamsConnectorClient client)

// Create HTTP transport objects
#pragma warning disable CA2000 // Dispose objects before losing scope
var result = new HttpOperationResponse<TeamsMeetingNotificationRecipientFailureInfos>();
var result = new HttpOperationResponse<MeetingNotificationResponse>();
#pragma warning restore CA2000 // Dispose objects before losing scope
try
{
Expand Down Expand Up @@ -416,7 +416,7 @@ public TeamsOperations(TeamsConnectorClient client)
responseContent = await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false);
try
{
result.Body = Rest.Serialization.SafeJsonConvert.DeserializeObject<TeamsMeetingNotificationRecipientFailureInfos>(responseContent, Client.DeserializationSettings);
result.Body = Rest.Serialization.SafeJsonConvert.DeserializeObject<MeetingNotificationResponse>(responseContent, Client.DeserializationSettings);
}
catch (JsonException ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public static partial class TeamsOperationsExtensions
/// The cancellation token.
/// </param>
/// <returns>Information regarding which participant notifications failed.</returns>
public static async Task<TeamsMeetingNotificationRecipientFailureInfos> SendMeetingNotificationAsync(this ITeamsOperations operations, string meetingId, TeamsMeetingNotification notification, CancellationToken cancellationToken = default(CancellationToken))
public static async Task<MeetingNotificationResponse> SendMeetingNotificationAsync(this ITeamsOperations operations, string meetingId, MeetingNotificationBase notification, CancellationToken cancellationToken = default(CancellationToken))
{
if (operations is TeamsOperations teamsOperations)
{
Expand Down
90 changes: 90 additions & 0 deletions libraries/Microsoft.Bot.Schema/Converters/SurfaceConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using Microsoft.Bot.Schema.Teams;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Microsoft.Bot.Schema.Converters
yingduyingdu marked this conversation as resolved.
Show resolved Hide resolved
{
/// <summary>
/// Converter which allows json to be expression to object or static object.
/// </summary>
public class SurfaceConverter : JsonConverter
{
/// <summary>
/// Gets a value indicating whether this Converter can write JSON.
/// </summary>
/// <value>true if this Converter can write JSON; otherwise, false.</value>
public override bool CanWrite => false;

/// <summary>
/// Gets a value indicating whether this Converter can read JSON.
/// </summary>
/// <value>true if this Converter can read JSON; otherwise, false.</value>
public override bool CanRead => true;

/// <summary>
/// Determines whether this instance can convert the specified object type.
/// </summary>
/// <param name="objectType">Type of the object.</param>
/// <returns>
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
/// </returns>
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Surface);
}

/// <summary>
/// Reads the JSON representation of the object.
/// </summary>
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
/// <param name="objectType">Type of the object.</param>
/// <param name="existingValue">The existing value of object being read.</param>
/// <param name="serializer">The calling serializer.</param>
/// <returns>The object value.</returns>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var jsonObject = JObject.Load(reader);
var surfaceType = jsonObject.GetValue("surface", StringComparison.OrdinalIgnoreCase)?.ToObject<SurfaceType>();

Surface parsedSurface;
switch (surfaceType)
{
case SurfaceType.MeetingStage:
var contentType = jsonObject.GetValue("contentType", StringComparison.OrdinalIgnoreCase)?.ToObject<ContentType>();
parsedSurface = CreateMeetingStageSurfaceWithContentType(contentType);
break;
default:
throw new ArgumentException($"Invalid surface type: {surfaceType}");
}

serializer.Populate(jsonObject.CreateReader(), parsedSurface);
return parsedSurface;
}

/// <summary>
/// Writes the JSON representation of the object.
/// </summary>
/// <param name="writer">The Newtonsoft.Json.JsonWriter to write to.</param>
/// <param name="value">The value.</param>
/// <param name="serializer">The calling serializer.</param>
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotSupportedException();
}

private static Surface CreateMeetingStageSurfaceWithContentType(ContentType? contentType)
{
switch (contentType)
{
case ContentType.Task:
return new MeetingStageSurface<TaskModuleContinueResponse>();
default:
throw new ArgumentException($"Invalid content type: {contentType}");
}
}
}
}
21 changes: 21 additions & 0 deletions libraries/Microsoft.Bot.Schema/Teams/ContentType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

namespace Microsoft.Bot.Schema.Teams
{
/// <summary>
/// Defines content type. Depending on contentType, content field will have a different structure.
/// </summary>
public enum ContentType
{
/// <summary>
/// Content type is Unknown.
/// </summary>
Unknown,

/// <summary>
/// Content type is Task.
/// </summary>
Task
}
}
30 changes: 30 additions & 0 deletions libraries/Microsoft.Bot.Schema/Teams/MeetingNotification.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

namespace Microsoft.Bot.Schema.Teams
{
using Newtonsoft.Json;

/// <summary>
/// Specifies Bot meeting notification including meeting notification value.
/// </summary>
/// <typeparam name="T">The first generic type parameter.</typeparam>.
public class MeetingNotification<T> : MeetingNotificationBase
{
/// <summary>
/// Initializes a new instance of the <see cref="MeetingNotification{T}"/> class.
/// </summary>
protected MeetingNotification()
{
}

/// <summary>
/// Gets or sets Teams Bot meeting notification value.
/// </summary>
/// <value>
/// Teams Bot meeting notification value.
/// </value>
[JsonProperty(PropertyName = "value")]
public T Value { get; set; }
}
}
29 changes: 29 additions & 0 deletions libraries/Microsoft.Bot.Schema/Teams/MeetingNotificationBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Newtonsoft.Json;

namespace Microsoft.Bot.Schema.Teams
{
/// <summary>
/// Specifies Bot meeting notification base including channel data and type.
/// </summary>
public class MeetingNotificationBase
{
/// <summary>
/// Initializes a new instance of the <see cref="MeetingNotificationBase"/> class.
/// </summary>
protected MeetingNotificationBase()
{
}

/// <summary>
/// Gets or sets type of Bot meeting notification.
/// </summary>
/// <value>
/// Bot meeting notification type.
/// </value>
[JsonProperty("type")]
public string Type { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

namespace Microsoft.Bot.Schema.Teams
{
using System.Collections.Generic;
using Newtonsoft.Json;

/// <summary>
/// Specify Teams Bot meeting notification channel data.
/// </summary>
public class MeetingNotificationChannelData
{
/// <summary>
/// Initializes a new instance of the <see cref="MeetingNotificationChannelData"/> class.
/// </summary>
public MeetingNotificationChannelData()
{
}

/// <summary>
/// Gets or sets the OnBehalfOf list for user attribution.
/// </summary>
/// <value>The Teams Bot meeting notification's OnBehalfOf list.</value>
#pragma warning disable CA2227 // Collection properties should be read only (we can't change this without breaking binary compat)>
[JsonProperty(PropertyName = "OnBehalfOf")]
public IList<OnBehalfOf> OnBehalfOfList { get; set; }
#pragma warning restore CA2227 // Collection properties should be read only
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,28 @@
namespace Microsoft.Bot.Schema.Teams
{
/// <summary>
/// Information regarding failure to notify a recipient of a <see cref="TeamsMeetingNotification"/>.
/// Information regarding failure to notify a recipient of a meeting notification.
/// </summary>
public class TeamsMeetingNotificationRecipientFailureInfo
public class MeetingNotificationRecipientFailureInfo
{
/// <summary>
/// Gets or sets the mri for a recipient <see cref="TeamsMeetingNotification"/> failure.
/// Gets or sets the mri for a recipient meeting notification failure.
/// </summary>
/// <value>The type of this notification container.</value>
[JsonProperty(PropertyName = "recipientMri")]
public string RecipientMri { get; set; }

/// <summary>
/// Gets or sets the error code for a <see cref="TeamsMeetingNotification"/>.
/// Gets or sets the error code for a meeting notification.
/// </summary>
/// <value>The error code for a <see cref="TeamsMeetingNotification"/>.</value>
/// <value>The error code for a meeting notification.</value>
[JsonProperty(PropertyName = "errorcode")]
public string ErrorCode { get; set; }

/// <summary>
/// Gets or sets the failure reason for a <see cref="TeamsMeetingNotification"/> failure.
/// Gets or sets the failure reason for a meeting notification failure.
/// </summary>
/// <value>The reason why a participant <see cref="TeamsMeetingNotification"/> failed.</value>
/// <value>The reason why a participant meeting notification failed.</value>
[JsonProperty(PropertyName = "failureReason")]
public string FailureReason { get; set; }
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Collections.Generic;
using Newtonsoft.Json;

namespace Microsoft.Bot.Schema.Teams
{
/// <summary>
/// Specifies Bot meeting notification response.
/// Contains list of <see cref="MeetingNotificationRecipientFailureInfo"/>.
/// </summary>
public class MeetingNotificationResponse
{
/// <summary>
/// Initializes a new instance of the <see cref="MeetingNotificationResponse"/> class.
/// </summary>
public MeetingNotificationResponse()
{
}

/// <summary>
/// Gets or sets the list of <see cref="MeetingNotificationRecipientFailureInfo"/>.
/// </summary>
/// <value>The list of <see cref="MeetingNotificationRecipientFailureInfo"/>.</value>
[JsonProperty(PropertyName = "recipientsFailureInfo")]
#pragma warning disable CA2227 // Collection properties should be read only (we can't change this without breaking binary compat)>
public IList<MeetingNotificationRecipientFailureInfo> RecipientsFailureInfo { get; set; }
#pragma warning restore CA2227 // Collection properties should be read only
}
}
42 changes: 42 additions & 0 deletions libraries/Microsoft.Bot.Schema/Teams/MeetingStageSurface.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

namespace Microsoft.Bot.Schema.Teams
{
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

/// <summary>
/// Specifies meeting stage surface.
/// </summary>
/// <typeparam name="T">The first generic type parameter.</typeparam>.
public class MeetingStageSurface<T> : Surface
{
/// <summary>
/// Initializes a new instance of the <see cref="MeetingStageSurface{T}"/> class.
/// </summary>
public MeetingStageSurface()
: base(SurfaceType.MeetingStage)
yingduyingdu marked this conversation as resolved.
Show resolved Hide resolved
{
}

/// <summary>
/// Gets or sets the content type of this <see cref="MeetingStageSurface{T}"/>.
/// </summary>
/// <value>
/// The content type of this <see cref="MeetingStageSurface{T}"/>.
/// </value>
[JsonConverter(typeof(StringEnumConverter))]
[JsonProperty(PropertyName = "contentType")]
public ContentType ContentType { get; set; } = ContentType.Task;

/// <summary>
/// Gets or sets the content for this <see cref="MeetingStageSurface{T}"/>.
/// </summary>
/// <value>
/// The content of this <see cref="MeetingStageSurface{T}"/>.
/// </value>
[JsonProperty(PropertyName = "content")]
public T Content { get; set; }
}
}
10 changes: 2 additions & 8 deletions libraries/Microsoft.Bot.Schema/Teams/OnBehalfOf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,20 @@ namespace Microsoft.Bot.Schema.Teams
/// <summary>
/// Specifies attribution for notifications.
/// </summary>
public partial class OnBehalfOf
public class OnBehalfOf
{
/// <summary>
/// Initializes a new instance of the <see cref="OnBehalfOf"/> class.
/// </summary>
public OnBehalfOf()
{
CustomInit();
}

/// <summary>
/// Gets or sets the identification of the item. Default is 0.
/// </summary>
/// <value>The item id.</value>
[JsonProperty(PropertyName = "itemId")]
[JsonProperty(PropertyName = "itemid")]
public int ItemId { get; set; } = 0;

/// <summary>
Expand All @@ -46,10 +45,5 @@ public OnBehalfOf()
/// <value>The name of the person.</value>
[JsonProperty(PropertyName = "displayName")]
public string DisplayName { get; set; }

/// <summary>
/// An initialization method that performs custom operations like setting defaults.
/// </summary>
partial void CustomInit();
}
}
Loading