Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,3 @@ public class AutomationFrameworkSettings

public string[] LocalAdmins { get; set; } = [];
}

Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@ private async Task<T> InternalEvaluateAsync<T>(LambdaExpression invokeExpr, Func
{
await using var scope = rootServiceProvider.CreateAsyncScope();

var c = new DefaultHttpContext { RequestServices = scope.ServiceProvider };
var c = new DefaultHttpContext
{
RequestServices = scope.ServiceProvider,
RequestAborted = scope.ServiceProvider.GetService<IDefaultCancellationTokenSource>()?.CancellationToken ?? CancellationToken.None
};

await new WebApiInvoker(c, context => InvokeController(context, func))
.WithMiddleware(next => new ImpersonateMiddleware(next), (middleware, httpContext) => middleware.Invoke(httpContext, customUserCredential))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,25 @@ namespace Framework.Notification.DTO;
public class NotificationEventDTO
{
[DataMember]
public List<NotificationRecipientDTO> Recipients { get; set; }
public List<NotificationRecipientDTO> Recipients { get; set; } = [];

[DataMember]
public List<NotificationAttachmentDTO> Attachments { get; set; }
public List<NotificationAttachmentDTO> Attachments { get; set; } = [];

[DataMember]
public string From { get; set; }
public string From { get; set; } = null!;

[DataMember]
public string FromName { get; set; }
public string FromName { get; set; } = null!;

[DataMember]
public string Subject { get; set; }
public string Subject { get; set; } = null!;

[DataMember]
public NotificationMessage Message { get; set; }
public NotificationMessage Message { get; set; } = null!;

[DataMember]
public NotificationTechnicalInformationDTO TechnicalInformation { get; set; }
public NotificationTechnicalInformationDTO TechnicalInformation { get; set; } = null!;

public NotificationEventDTO()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ namespace Framework.Subscriptions;

public interface ISubscriptionService
{
IEnumerable<ITryResult<SubscriptionHeader>> Process(DomainObjectVersions versions);
IAsyncEnumerable<ITryResult<SubscriptionHeader>> ProcessAsync(DomainObjectVersions versions);
}

Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ public record DomainObjectVersions<TDomainObject>(TDomainObject? Previous, TDoma
/// <inheritdoc/>
public override string ToString() => $"DomainObjectType: {this.DomainObjectType}, Previous: {this.Previous}, Current: {this.Current}";

public DomainObjectVersions<TNewDomainObject> ChangeDomainObject<TNewDomainObject>(Func<TDomainObject, TNewDomainObject> selector)
where TNewDomainObject : class => new(this.Previous == null ? null : selector(this.Previous), this.Current == null ? null : selector(this.Current));
public async ValueTask<DomainObjectVersions<TNewDomainObject>> ChangeDomainObjectAsync<TNewDomainObject>(Func<TDomainObject, ValueTask<TNewDomainObject>> selector)
where TNewDomainObject : class => new(this.Previous == null ? null : await selector(this.Previous), this.Current == null ? null : await selector(this.Current));

private static DomainObjectChangeType GetChangeType(TDomainObject? previous, TDomainObject? current)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@ namespace Framework.Subscriptions.Metadata;
public interface IMessageTemplate<TRenderingObject>
where TRenderingObject : class
{
(string Subject, string Body) Render(IServiceProvider serviceProvider, DomainObjectVersions<TRenderingObject> versions);
ValueTask<(string Subject, string Body)> Render(IServiceProvider serviceProvider, DomainObjectVersions<TRenderingObject> versions, CancellationToken ct);
}

Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,21 @@ public interface ISubscription<TDomainObject, TRenderingObject> : ISubscription

Type ISubscription.RenderingObjectType => typeof(TRenderingObject);

bool IsProcessed(IServiceProvider serviceProvider, DomainObjectVersions<TDomainObject> versions);
ValueTask<bool> IsProcessed(IServiceProvider serviceProvider, DomainObjectVersions<TDomainObject> versions, CancellationToken ct);

TRenderingObject ConvertToRenderingObject(IServiceProvider serviceProvider, TDomainObject domainObject);
ValueTask<TRenderingObject> ConvertToRenderingObject(IServiceProvider serviceProvider, TDomainObject domainObject, CancellationToken ct);

IEnumerable<NotificationMessageGenerationInfo<TRenderingObject>> GetTo(IServiceProvider serviceProvider, DomainObjectVersions<TDomainObject> versions);
IAsyncEnumerable<NotificationMessageGenerationInfo<TRenderingObject>> GetTo(IServiceProvider serviceProvider, DomainObjectVersions<TDomainObject> versions);

IEnumerable<NotificationMessageGenerationInfo<TRenderingObject>> GetCopyTo(IServiceProvider serviceProvider, DomainObjectVersions<TDomainObject> versions);
IAsyncEnumerable<NotificationMessageGenerationInfo<TRenderingObject>> GetCopyTo(IServiceProvider serviceProvider, DomainObjectVersions<TDomainObject> versions);

IEnumerable<NotificationMessageGenerationInfo<TRenderingObject>> GetReplyTo(IServiceProvider serviceProvider, DomainObjectVersions<TDomainObject> versions);
IAsyncEnumerable<NotificationMessageGenerationInfo<TRenderingObject>> GetReplyTo(IServiceProvider serviceProvider, DomainObjectVersions<TDomainObject> versions);

IEnumerable<NotificationFilterGroup> GetNotificationFilterGroups(IServiceProvider serviceProvider, DomainObjectVersions<TDomainObject> versions);
IAsyncEnumerable<NotificationFilterGroup> GetNotificationFilterGroups(IServiceProvider serviceProvider, DomainObjectVersions<TDomainObject> versions);

(string Subject, string Body) GetMessage(IServiceProvider serviceProvider, DomainObjectVersions<TRenderingObject> versions);
ValueTask<(string Subject, string Body)> GetMessage(IServiceProvider serviceProvider, DomainObjectVersions<TRenderingObject> versions, CancellationToken ct);

IEnumerable<Attachment> GetAttachments(IServiceProvider serviceProvider, DomainObjectVersions<TRenderingObject> versions);
IAsyncEnumerable<Attachment> GetAttachments(IServiceProvider serviceProvider, DomainObjectVersions<TRenderingObject> versions);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,19 @@ public abstract partial class RazorTemplate<TRenderingObject> : IMessageTemplate
public abstract string Subject { get; }


public (string Subject, string Body) Render(IServiceProvider serviceProvider, DomainObjectVersions<TRenderingObject> versions)
public ValueTask<(string Subject, string Body)> Render(
IServiceProvider serviceProvider,
DomainObjectVersions<TRenderingObject> versions,
CancellationToken ct)
{
ct.ThrowIfCancellationRequested();

this.state = new RenderingState(new StringWriter(), serviceProvider, versions);

this.Execute();

return (this.Subject, this.State.Writer.ToString());
return new((this.Subject, this.State.Writer.ToString()));
}

protected record RenderingState(StringWriter Writer, IServiceProvider ServiceProvider, DomainObjectVersions<TRenderingObject> Versions);
}

37 changes: 24 additions & 13 deletions src/Subscriptions/Framework.Subscriptions.Metadata/Subscription.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,11 @@

namespace Framework.Subscriptions.Metadata;


public abstract class Subscription<TDomainObject, TMessageTemplate> : Subscription<TDomainObject, TDomainObject, TMessageTemplate>
where TDomainObject : class
where TMessageTemplate : IMessageTemplate<TDomainObject>
{
public sealed override TDomainObject ConvertToRenderingObject(IServiceProvider serviceProvider, TDomainObject domainObject) => domainObject;
public sealed override ValueTask<TDomainObject> ConvertToRenderingObject(IServiceProvider serviceProvider, TDomainObject domainObject, CancellationToken ct) => new(domainObject);
}

public abstract class Subscription<TDomainObject, TRenderingObject, TMessageTemplate> : ISubscription<TDomainObject, TRenderingObject>
Expand All @@ -40,22 +39,34 @@ public abstract class Subscription<TDomainObject, TRenderingObject, TMessageTemp

public virtual ImmutableArray<SecurityRole> SecurityRoles { get; } = [];

public (string Subject, string Body) GetMessage(IServiceProvider serviceProvider, DomainObjectVersions<TRenderingObject> versions) =>
serviceProvider.GetRequiredService<IServiceProxyFactory>().Create<TMessageTemplate>().Render(serviceProvider, versions);
public ValueTask<(string Subject, string Body)> GetMessage(
IServiceProvider serviceProvider,
DomainObjectVersions<TRenderingObject> versions,
CancellationToken ct) =>
serviceProvider.GetRequiredService<IServiceProxyFactory>().Create<TMessageTemplate>().Render(serviceProvider, versions, ct);

public abstract TRenderingObject ConvertToRenderingObject(IServiceProvider serviceProvider, TDomainObject domainObject);
public abstract ValueTask<TRenderingObject> ConvertToRenderingObject(IServiceProvider serviceProvider, TDomainObject domainObject, CancellationToken ct);

public virtual bool IsProcessed(IServiceProvider serviceProvider, DomainObjectVersions<TDomainObject> versions) => true;
public virtual ValueTask<bool> IsProcessed(IServiceProvider serviceProvider, DomainObjectVersions<TDomainObject> versions, CancellationToken ct) =>
new(true);

public virtual IEnumerable<NotificationMessageGenerationInfo<TRenderingObject>> GetTo(IServiceProvider serviceProvider, DomainObjectVersions<TDomainObject> versions) => [];
public virtual IAsyncEnumerable<NotificationMessageGenerationInfo<TRenderingObject>> GetTo(
IServiceProvider serviceProvider,
DomainObjectVersions<TDomainObject> versions) => AsyncEnumerable.Empty<NotificationMessageGenerationInfo<TRenderingObject>>();

public virtual IEnumerable<NotificationMessageGenerationInfo<TRenderingObject>> GetCopyTo(IServiceProvider serviceProvider, DomainObjectVersions<TDomainObject> versions) => [];
public virtual IAsyncEnumerable<NotificationMessageGenerationInfo<TRenderingObject>> GetCopyTo(
IServiceProvider serviceProvider,
DomainObjectVersions<TDomainObject> versions) => AsyncEnumerable.Empty<NotificationMessageGenerationInfo<TRenderingObject>>();

public virtual IEnumerable<NotificationMessageGenerationInfo<TRenderingObject>> GetReplyTo(IServiceProvider serviceProvider, DomainObjectVersions<TDomainObject> versions) =>
[];
public virtual IAsyncEnumerable<NotificationMessageGenerationInfo<TRenderingObject>> GetReplyTo(
IServiceProvider serviceProvider,
DomainObjectVersions<TDomainObject> versions) =>
AsyncEnumerable.Empty<NotificationMessageGenerationInfo<TRenderingObject>>();

public virtual IEnumerable<NotificationFilterGroup> GetNotificationFilterGroups(IServiceProvider serviceProvider, DomainObjectVersions<TDomainObject> versions) => [];
public virtual IAsyncEnumerable<NotificationFilterGroup> GetNotificationFilterGroups(
IServiceProvider serviceProvider,
DomainObjectVersions<TDomainObject> versions) => AsyncEnumerable.Empty<NotificationFilterGroup>();

public virtual IEnumerable<Attachment> GetAttachments(IServiceProvider serviceProvider, DomainObjectVersions<TRenderingObject> versions) => [];
public virtual IAsyncEnumerable<Attachment> GetAttachments(IServiceProvider serviceProvider, DomainObjectVersions<TRenderingObject> versions) =>
AsyncEnumerable.Empty<Attachment>();
}

Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Immutable;
using System.Runtime.CompilerServices;

using Anch.Core;
using Anch.GenericQueryable;
Expand All @@ -15,23 +16,28 @@ public class EmployeeEmailExtractor<TEmployee, TPrincipal>(
IVisualIdentityInfo<TPrincipal> principalVisualIdentityInfo,
IVisualIdentityInfo<TEmployee> employeeVisualIdentityInfo,
IQueryableSource queryableSource,
EmployeeInfo<TEmployee> employeeInfo,
IDefaultCancellationTokenSource? defaultCancellationTokenSource = null) : IEmployeeEmailExtractor
EmployeeInfo<TEmployee> employeeInfo) : IEmployeeEmailExtractor
where TEmployee : class
{
public ImmutableHashSet<string> GetEmails(ImmutableArray<SecurityRole> securityRoles, ImmutableArray<NotificationFilterGroup> notificationFilterGroups) =>
public IAsyncEnumerable<string> GetEmails(ImmutableArray<SecurityRole> securityRoles, ImmutableArray<NotificationFilterGroup> notificationFilterGroups) =>
this.GetEmailsInternal(securityRoles, notificationFilterGroups);

defaultCancellationTokenSource.RunSync(async ct =>
{
var principalNames = await notificationPrincipalExtractor.GetPrincipalsAsync(securityRoles, notificationFilterGroups)
.Select(principalVisualIdentityInfo.Name.Getter)
.ToHashSetAsync(null, ct);
private async IAsyncEnumerable<string> GetEmailsInternal(
ImmutableArray<SecurityRole> securityRoles,
ImmutableArray<NotificationFilterGroup> notificationFilterGroups,
[EnumeratorCancellation] CancellationToken ct = default)
{
var principalNames = await notificationPrincipalExtractor.GetPrincipalsAsync(securityRoles, notificationFilterGroups)
.Select(principalVisualIdentityInfo.Name.Getter)
.ToHashSetAsync(null, ct);

return await queryableSource.GetQueryable<TEmployee>()
.Where(employeeVisualIdentityInfo.Name.Path.Select(employeeName => principalNames.Contains(employeeName)))
.Select(employeeInfo.Email.Path)
.GenericAsAsyncEnumerable()
.ToImmutableHashSetAsync(ct);
});
await foreach (var email in queryableSource.GetQueryable<TEmployee>()
.Where(employeeVisualIdentityInfo.Name.Path.Select(employeeName => principalNames.Contains(employeeName)))
.Select(employeeInfo.Email.Path)
.GenericAsAsyncEnumerable()
.WithCancellation(ct))
{
yield return email;
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@ namespace Framework.Subscriptions;

public interface IEmployeeEmailExtractor
{
ImmutableHashSet<string> GetEmails(ImmutableArray<SecurityRole> securityRoles, ImmutableArray<NotificationFilterGroup> notificationFilterGroups);
IAsyncEnumerable<string> GetEmails(ImmutableArray<SecurityRole> securityRoles, ImmutableArray<NotificationFilterGroup> notificationFilterGroups);
}

Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

namespace Framework.Subscriptions;

public interface INotificationExtractor
public interface INotificationExtractor<TDomainObject>
where TDomainObject : class
{
IEnumerable<Notification.Domain.Notification> GetNotifications(DomainObjectVersions versions);
IAsyncEnumerable<Notification.Domain.Notification> GetNotifications(DomainObjectVersions<TDomainObject> versions);
}

Loading
Loading