Skip to content

Commit

Permalink
async loops
Browse files Browse the repository at this point in the history
  • Loading branch information
ninjapiratica committed Jan 25, 2025
1 parent e5b58be commit 521c038
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 19 deletions.
2 changes: 1 addition & 1 deletion NP.Lti13Platform.Core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ The expiration time of the access tokens handed out to the tools.

The LTI specs allow for messages to be extended with custom data. This is handled by adding `Populators` in the setup of the platform. To extend the message, create an interface with the properties that will be used to extend the message, and create a `Populator<T>` to fill those properties when the request for that message is generated.

Multiple populators can be added to the same interface. Multiple interfaces can be added to the same message type. The populator interface properties support the System.Text.Json attributes for serialization.
Multiple populators can be added to the same interface. Multiple interfaces can be added to the same message type. The populator interface properties support the System.Text.Json attributes for serialization. Populators must be thread safe or have a Transient Dependency Injection strategy.

```csharp
interface ICustomMessage
Expand Down
2 changes: 1 addition & 1 deletion NP.Lti13Platform.Core/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ public static IEndpointRouteBuilder UseLti13PlatformCore(this IEndpointRouteBuil
messageHintString);

var services = serviceProvider.GetKeyedServices<Populator>(messageTypeString);
foreach (var service in services) // TODO: await in list
foreach (var service in services)
{
await service.PopulateAsync(ltiMessage, scope, cancellationToken);
}
Expand Down
2 changes: 1 addition & 1 deletion NP.Lti13Platform.NameRoleProvisioningServices/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ The base url used to tell tools where the service is located.

## Member Message

The IMS [Name and Role Provisioning Services](https://www.imsglobal.org/spec/lti-nrps/v2p0#message-section) spec defines a way to give tools access to the parts of LTI messages that are specific to members. This project includes the specifics for the core message and known properties defined within the spec. Additional message can be added by calling `ExtendNameRoleProvisioningMessage` on startup. This follows the same pattern as [Populators](../NP.Lti13Platform.Core/README.md#populators) from the core spec. These messages should only contain the user specific message properties of the given message. Multiple populators may be added for the same interface and multiple interfaces may be added for the same <message_type>.
The IMS [Name and Role Provisioning Services](https://www.imsglobal.org/spec/lti-nrps/v2p0#message-section) spec defines a way to give tools access to the parts of LTI messages that are specific to members. This project includes the specifics for the core message and known properties defined within the spec. Additional message can be added by calling `ExtendNameRoleProvisioningMessage` on startup. This follows the same pattern as [Populators](../NP.Lti13Platform.Core/README.md#populators) from the core spec. These messages should only contain the user specific message properties of the given message. Multiple populators may be added for the same interface and multiple interfaces may be added for the same <message_type>. Populators must be thread safe or have a Transient Dependency Injection strategy.

```csharp
builder.Services
Expand Down
37 changes: 21 additions & 16 deletions NP.Lti13Platform.NameRoleProvisioningServices/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ public static IEndpointRouteBuilder UseLti13PlatformNameRoleProvisioningServices
.Select(x => x.OrderByDescending(y => y.IsCurrent).First());
}

var messages = new Dictionary<string, ICollection<NameRoleProvisioningMessage>>();
var messages = new Dictionary<string, IEnumerable<NameRoleProvisioningMessage>>();
if (!string.IsNullOrWhiteSpace(rlid))
{
var resourceLink = await coreDataService.GetResourceLinkAsync(rlid, cancellationToken);
Expand All @@ -173,38 +173,43 @@ public static IEndpointRouteBuilder UseLti13PlatformNameRoleProvisioningServices
return Results.BadRequest(new { Error = "resource link unavailable", Error_Description = "resource link does not exist in the context", Error_Uri = "https://www.imsglobal.org/spec/lti-nrps/v2p0#access-restriction" });
}

var messageTypes = LtiMessageTypes.ToDictionary(mt => mt.Key, mt => serviceProvider.GetKeyedServices<Populator>(mt.Key));

foreach (var currentUser in currentUsers) // TODO: await in list
IEnumerable<(MessageType MessageType, NameRoleProvisioningMessage Message, MessageScope Scope)> GetUserMessages(User user)
{
ICollection<NameRoleProvisioningMessage> userMessages = [];
messages.Add(currentUser.User.Id, userMessages);

var scope = new MessageScope(
new UserScope(currentUser.User, ActualUser: null, IsAnonymous: false),
new UserScope(user, ActualUser: null, IsAnonymous: false),
tool,
deployment,
context,
resourceLink,
MessageHint: null);

foreach (var messageType in messageTypes) // TODO: await in list
foreach (var messageType in LtiMessageTypes)
{
var message = serviceProvider.GetKeyedService<NameRoleProvisioningMessage>(messageType.Key);

if (message != null)
{
message.MessageType = messageType.Key.Name;

foreach (var populator in messageType.Value) // TODO: await in list
{
await populator.PopulateAsync(message, scope, cancellationToken);
}

userMessages.Add(message);
yield return (messageType.Key, message, scope);
}
}
}

var userMessages = currentUsers.SelectMany(currentUser => GetUserMessages(currentUser.User));

var tasks = userMessages.Select(async userMessage =>
{
var populators = serviceProvider.GetKeyedServices<Populator>(userMessage.MessageType.Name);

foreach (var populator in populators)
{
await populator.PopulateAsync(userMessage.Message, userMessage.Scope, cancellationToken);
}

return (userMessage.Scope.UserScope.User.Id, userMessage.Message);
});

messages = (await Task.WhenAll(tasks)).GroupBy(x => x.Id).ToDictionary(x => x.Key, x => x.Select(y => y.Message));
}

var usersWithRoles = currentUsers.Where(u => u.Membership.Roles.Any());
Expand Down

0 comments on commit 521c038

Please sign in to comment.