Skip to content

Commit

Permalink
Company Communicator v4.1.4 (#498)
Browse files Browse the repository at this point in the history
  • Loading branch information
priyank29 authored Sep 13, 2021
1 parent db17cfc commit f6ccd25
Show file tree
Hide file tree
Showing 45 changed files with 1,436 additions and 741 deletions.
2 changes: 1 addition & 1 deletion Manifest/manifest_authors.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.5/MicrosoftTeams.schema.json",
"manifestVersion": "1.5",
"version": "4.1.3",
"version": "4.1.4",
"id": "1c07cd26-a088-4db8-8928-ace382fa219f",
"packageName": "com.microsoft.teams.companycommunicator.authors",
"developer": {
Expand Down
2 changes: 1 addition & 1 deletion Manifest/manifest_users.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.5/MicrosoftTeams.schema.json",
"manifestVersion": "1.5",
"version": "4.1.3",
"version": "4.1.4",
"id": "148a66bb-e83d-425a-927d-09f4299a9274",
"packageName": "com.microsoft.teams.companycommunicator",
"developer": {
Expand Down
11 changes: 11 additions & 0 deletions Source/CompanyCommunicator.Common/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,16 @@ public static class Constants
/// get the OData next page link.
/// </summary>
public const string ODataNextPageLink = "@odata.nextLink";

/// <summary>
/// get the maximum number of recipients in a batch.
/// </summary>
public const int MaximumNumberOfRecipientsInBatch = 1000;

/// <summary>
/// get the Microsoft Graph api batch request size.
/// https://docs.microsoft.com/en-us/graph/known-issues#limit-on-batch-size.
/// </summary>
public const int MaximumGraphAPIBatchSize = 15;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,38 @@ select Task.Run(async () =>
}
}));
}

/// <summary>
/// Extension method to separate a list of objects into batches (a list of lists).
/// </summary>
/// <typeparam name="T">An object type.</typeparam>
/// <param name="sourceCollection">the source list.</param>
/// <param name="batchSize">the batch size.</param>
/// <returns>group list of user id list.</returns>
public static IEnumerable<IEnumerable<T>> AsBatches<T>(this IEnumerable<T> sourceCollection, int batchSize)
{
_ = sourceCollection ?? throw new ArgumentNullException(nameof(sourceCollection));
if (batchSize <= 0)
{
throw new ArgumentOutOfRangeException(nameof(batchSize));
}

var buffer = new List<T>(batchSize);
var sourceList = sourceCollection.ToList();
for (int i = 0; i < sourceList.Count; i++)
{
buffer.Add(sourceList[i]);
if (((i + 1) % batchSize) == 0 && buffer.Count > 0)
{
yield return buffer;
buffer = new List<T>(batchSize);
}
}

if (buffer.Count > 0)
{
yield return buffer;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// <copyright file="SendQueueMessageContentExtension.cs" company="Microsoft">
// <copyright file="SendQueueMessageContentExtensions.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// </copyright>
Expand All @@ -12,7 +12,7 @@ namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Extensions
/// <summary>
/// Extension class for <see cref="SendQueueMessageContent"/>.
/// </summary>
public static class SendQueueMessageContentExtension
public static class SendQueueMessageContentExtensions
{
/// <summary>
/// Get service url.
Expand Down Expand Up @@ -58,7 +58,7 @@ public static bool IsRecipientGuestUser(this SendQueueMessageContent message)
{
if (string.IsNullOrEmpty(recipient.UserData.UserType))
{
throw new ArgumentNullException(nameof(recipient.UserData.UserType));
throw new InvalidOperationException(nameof(recipient.UserData.UserType));
}
else if (recipient.UserData.UserType.Equals(UserType.Guest, StringComparison.OrdinalIgnoreCase))
{
Expand Down
31 changes: 0 additions & 31 deletions Source/CompanyCommunicator.Common/Extensions/UserExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,45 +6,14 @@
namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Extensions
{
using System;
using System.Collections.Generic;
using Microsoft.Graph;
using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories.UserData;
using Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.MicrosoftGraph;

/// <summary>
/// Extensions for User Ids.
/// </summary>
public static class UserExtensions
{
/// <summary>
/// this is as per microsoft graph api filter size.
/// </summary>
private static readonly int MaxGroupSize = 15;

/// <summary>
/// Break the list in groups.
/// </summary>
/// <param name="userIds">the user ids.</param>
/// <returns>group list of user id list.</returns>
public static IEnumerable<IEnumerable<string>> AsGroups(this IList<string> userIds)
{
var buffer = new List<string>(MaxGroupSize);
for (int i = 0; i < userIds.Count; i++)
{
buffer.Add(userIds[i]);
if (((i + 1) % MaxGroupSize) == 0 && buffer.Count > 0)
{
yield return buffer;
buffer = new List<string>(MaxGroupSize);
}
}

if (buffer.Count > 0)
{
yield return buffer;
}
}

/// <summary>
/// Get the userType for a user.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// <copyright file="IRecipientsService.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// </copyright>

namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.Recipients
{
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories.SentNotificationData;

/// <summary>
/// Recipient service.
/// </summary>
public interface IRecipientsService
{
/// <summary>
/// Batch the list of recipients.
/// </summary>
/// <param name="recipients">list of recipients.</param>
/// <returns>recipients information.</returns>
Task<RecipientsInfo> BatchRecipients(IEnumerable<SentNotificationDataEntity> recipients);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// <copyright file="RecipientsInfo.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// </copyright>

namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.Recipients
{
using System;
using System.Collections.Generic;

/// <summary>
/// Recipient information.
/// </summary>
public class RecipientsInfo
{
/// <summary>
/// Initializes a new instance of the <see cref="RecipientsInfo"/> class.
/// </summary>
/// <param name="notificationId">notification id.</param>
public RecipientsInfo(string notificationId)
{
if (string.IsNullOrEmpty(notificationId))
{
throw new ArgumentNullException(nameof(notificationId));
}

// Initialize properties.
this.TotalRecipientCount = 0;
this.BatchKeys = new List<string>();
this.HasRecipientsPendingInstallation = false;
this.NotificationId = notificationId;
}

/// <summary>
/// Gets the notification id.
/// </summary>
public string NotificationId { get; private set; }

/// <summary>
/// Gets or sets the total recipient count of the message.
/// </summary>
public int TotalRecipientCount { get; set; }

/// <summary>
/// Gets or sets a value indicating whether there are user app installations pending(recipients who have no conversation id in database) for recipients.
/// </summary>
public bool HasRecipientsPendingInstallation { get; set; }

/// <summary>
/// Gets or sets the batch keys of the recipients.
/// </summary>
public List<string> BatchKeys { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// <copyright file="RecipientsService.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// </copyright>

namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Services.Recipients
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Teams.Apps.CompanyCommunicator.Common.Extensions;
using Microsoft.Teams.Apps.CompanyCommunicator.Common.Repositories.SentNotificationData;
using Microsoft.Teams.Apps.CompanyCommunicator.Common.Utilities;

/// <summary>
/// Recipients service.
/// </summary>
public class RecipientsService : IRecipientsService
{
private readonly ISentNotificationDataRepository sentNotificationDataRepository;

/// <summary>
/// Initializes a new instance of the <see cref="RecipientsService"/> class.
/// </summary>
/// <param name="sentNotificationDataRepository">sent notification data repository.</param>
public RecipientsService(ISentNotificationDataRepository sentNotificationDataRepository)
{
this.sentNotificationDataRepository = sentNotificationDataRepository ?? throw new ArgumentNullException(nameof(sentNotificationDataRepository));
}

/// <inheritdoc/>
public async Task<RecipientsInfo> BatchRecipients(IEnumerable<SentNotificationDataEntity> recipients)
{
if (recipients == null)
{
throw new ArgumentNullException(nameof(IEnumerable<SentNotificationDataEntity>));
}

var notificationId = recipients.FirstOrDefault().PartitionKey;

var recipientBatches = recipients.AsBatches(Constants.MaximumNumberOfRecipientsInBatch);
var recipientInfo = new RecipientsInfo(notificationId)
{
TotalRecipientCount = recipients.ToList().Count,
};
int batchIndex = 1;
foreach (var recipientBatch in recipientBatches)
{
var recipientBatchList = recipientBatch.ToList();

// Update PartitionKey to Batch Key
recipientBatchList.ForEach(s =>
{
s.PartitionKey = PartitionKeyUtility.CreateBatchPartitionKey(s.PartitionKey, batchIndex);

// Update if there is any recipient which has no conversation id.
recipientInfo.HasRecipientsPendingInstallation |= string.IsNullOrEmpty(s.ConversationId);
});

// Store.
await this.sentNotificationDataRepository.BatchInsertOrMergeAsync(recipientBatch);
recipientInfo.BatchKeys.Add(recipientBatch.FirstOrDefault().PartitionKey);
batchIndex++;
}

return recipientInfo;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,7 @@ public async Task UpdateUserTypeForExistingUserListAsync(IEnumerable<UserDataEnt
var users = await this.usersService.GetBatchByUserIds(
userDataEntitiesWithNoUserType
.Select(user => user.AadId)
.ToList()
.AsGroups());
.AsBatches(Common.Constants.MaximumGraphAPIBatchSize));

if (!users.IsNullOrEmpty())
{
Expand Down
58 changes: 58 additions & 0 deletions Source/CompanyCommunicator.Common/Utilities/PartitionKeyUtility.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// <copyright file="PartitionKeyUtility.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// </copyright>

namespace Microsoft.Teams.Apps.CompanyCommunicator.Common.Utilities
{
using System;

/// <summary>
/// Partition Key utility.
/// </summary>
public static class PartitionKeyUtility
{
/// <summary>
/// Create the partition key from notification id.
/// </summary>
/// <param name="notificationId">notification id.</param>
/// <param name="batchIndex">batch index.</param>
/// <returns>partition key.</returns>
public static string CreateBatchPartitionKey(string notificationId, int batchIndex)
{
return $"{notificationId}:{batchIndex}";
}

/// <summary>
/// Get the notification id from partition key.
/// </summary>
/// <param name="partitionKey">partition key.</param>
/// <returns>notification id.</returns>
public static string GetNotificationIdFromBatchPartitionKey(string partitionKey)
{
var result = partitionKey.Split(":");
if (result.Length != 2)
{
throw new FormatException("Invalid format of batch partition key");
}

return result[0];
}

/// <summary>
/// Get the notification id from partition key.
/// </summary>
/// <param name="partitionKey">partition key.</param>
/// <returns>notification id.</returns>
public static string GetBatchIdFromBatchPartitionKey(string partitionKey)
{
var result = partitionKey.Split(":");
if (result.Length != 2)
{
throw new FormatException("Invalid format of batch partition key");
}

return result[1];
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@ public async IAsyncEnumerable<IEnumerable<UserData>> GetUserDataStreamAsync(stri
// Group the recipients as per the Graph batch api.
var groupRecipientsByAadId = recipients?
.Select(notitification => notitification.RowKey)
.ToList()
.AsGroups();
.AsBatches(Common.Constants.MaximumGraphAPIBatchSize);

if (!groupRecipientsByAadId.IsNullOrEmpty())
{
Expand Down
Loading

0 comments on commit f6ccd25

Please sign in to comment.