Skip to content

Commit f04e24f

Browse files
authored
Add DNC Registry for Omnichannels (#467)
1 parent 13fa0e8 commit f04e24f

175 files changed

Lines changed: 10588 additions & 1052 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CrestApps.OrchardCore.slnx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
<Folder Name="/src/Abstractions/">
1919
<Project Path="src/Abstractions/CrestApps.OrchardCore.Abstractions/CrestApps.OrchardCore.Abstractions.csproj" />
2020
<Project Path="src/Abstractions/CrestApps.OrchardCore.ContentTransfer.Abstractions/CrestApps.OrchardCore.ContentTransfer.Abstractions.csproj" />
21+
<Project Path="src/Abstractions/CrestApps.OrchardCore.DncRegistry.Abstractions/CrestApps.OrchardCore.DncRegistry.Abstractions.csproj" />
22+
<Project Path="src/Abstractions/CrestApps.OrchardCore.PhoneNumbers.Abstractions/CrestApps.OrchardCore.PhoneNumbers.Abstractions.csproj" />
2123
<Project Path="src/Abstractions/CrestApps.OrchardCore.Users.Abstractions/CrestApps.OrchardCore.Users.Abstractions.csproj" />
2224
</Folder>
2325
<Folder Name="/src/Core/">
@@ -59,13 +61,17 @@
5961
<Project Path="src/Modules/CrestApps.OrchardCore.AzureAIInference/CrestApps.OrchardCore.AzureAIInference.csproj" />
6062
<Project Path="src/Modules/CrestApps.OrchardCore.ContentAccessControl/CrestApps.OrchardCore.ContentAccessControl.csproj" />
6163
<Project Path="src/Modules/CrestApps.OrchardCore.ContentTransfer/CrestApps.OrchardCore.ContentTransfer.csproj" />
64+
<Project Path="src/Modules/CrestApps.OrchardCore.ContentTransfer.OpenXml/CrestApps.OrchardCore.ContentTransfer.OpenXml.csproj" />
65+
<Project Path="src/Modules/CrestApps.OrchardCore.DncRegistry.Azure/CrestApps.OrchardCore.DncRegistry.Azure.csproj" />
66+
<Project Path="src/Modules/CrestApps.OrchardCore.DncRegistry/CrestApps.OrchardCore.DncRegistry.csproj" />
6267
<Project Path="src/Modules/CrestApps.OrchardCore.Ollama/CrestApps.OrchardCore.Ollama.csproj" />
6368
<Project Path="src/Modules/CrestApps.OrchardCore.Omnichannel.EventGrid/CrestApps.OrchardCore.Omnichannel.EventGrid.csproj" />
6469
<Project Path="src/Modules/CrestApps.OrchardCore.Omnichannel.Managements/CrestApps.OrchardCore.Omnichannel.Managements.csproj" />
6570
<Project Path="src/Modules/CrestApps.OrchardCore.Omnichannel.Sms/CrestApps.OrchardCore.Omnichannel.Sms.csproj" />
6671
<Project Path="src/Modules/CrestApps.OrchardCore.Omnichannel/CrestApps.OrchardCore.Omnichannel.csproj" />
6772
<Project Path="src/Modules/CrestApps.OrchardCore.OpenAI.Azure/CrestApps.OrchardCore.OpenAI.Azure.csproj" />
6873
<Project Path="src/Modules/CrestApps.OrchardCore.OpenAI/CrestApps.OrchardCore.OpenAI.csproj" />
74+
<Project Path="src/Modules/CrestApps.OrchardCore.PhoneNumbers/CrestApps.OrchardCore.PhoneNumbers.csproj" />
6975
<Project Path="src/Modules/CrestApps.OrchardCore.Recipes/CrestApps.OrchardCore.Recipes.csproj" />
7076
<Project Path="src/Modules/CrestApps.OrchardCore.Resources/CrestApps.OrchardCore.Resources.csproj" />
7177
<Project Path="src/Modules/CrestApps.OrchardCore.Roles/CrestApps.OrchardCore.Roles.csproj" />

Directory.Packages.props

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<PackageVersion Include="DocumentFormat.OpenXml" Version="3.5.1" />
1313
<PackageVersion Include="Elastic.Clients.Elasticsearch" Version="8.19.21" />
1414
<PackageVersion Include="Fluid.Core" Version="2.31.0" />
15+
<PackageVersion Include="libphonenumber-csharp" Version="9.0.31" />
1516
<PackageVersion Include="JsonSchema.Net" Version="8.0.5" />
1617
<PackageVersion Include="Lucene.Net.Analysis.Common" Version="4.8.0-beta00017" />
1718
<PackageVersion Include="Markdig" Version="1.1.3" />
@@ -152,14 +153,15 @@
152153
</ItemGroup>
153154
<ItemGroup>
154155
<!-- Aspire Packages -->
155-
<PackageVersion Include="Aspire.Hosting.AppHost" Version="13.3.5" />
156+
<PackageVersion Include="Aspire.Hosting.AppHost" Version="13.4.2" />
156157
<PackageVersion Include="Aspire.Hosting.Elasticsearch" Version="13.3.0" />
157-
<PackageVersion Include="Aspire.Hosting.Redis" Version="13.3.5" />
158-
<PackageVersion Include="CommunityToolkit.Aspire.Hosting.Ollama" Version="13.3.0" />
158+
<PackageVersion Include="Aspire.Hosting.Redis" Version="13.4.2" />
159+
<PackageVersion Include="CommunityToolkit.Aspire.Hosting.Ollama" Version="13.4.0" />
159160
</ItemGroup>
160161
<ItemGroup>
161162
<!-- Transitive Packages -->
162163
<PackageVersion Include="MailKit" Version="4.16.0" />
164+
<PackageVersion Include="Nerdbank.MessagePack" Version="1.2.4" />
163165
</ItemGroup>
164166
<ItemGroup>
165167
<!-- Sample Packages -->

src/Abstractions/CrestApps.OrchardCore.ContentTransfer.Abstractions/ContentFieldImportMapContext.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ namespace CrestApps.OrchardCore.ContentTransfer;
44

55
public sealed class ContentFieldImportMapContext : ImportContentFieldContext
66
{
7+
public ContentTransferEntry Entry { get; set; }
8+
79
public DataColumnCollection Columns { get; set; }
810

911
public DataRow Row { get; set; }
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using OrchardCore.ContentManagement.Metadata.Models;
2+
3+
namespace CrestApps.OrchardCore.ContentTransfer;
4+
5+
/// <summary>
6+
/// Context passed to <see cref="IContentImportRowFilter.PrepareBatchAsync(ContentImportRowFilterBatchContext)"/>
7+
/// so a filter can preload state for the next import batch.
8+
/// </summary>
9+
public sealed class ContentImportRowFilterBatchContext
10+
{
11+
/// <summary>
12+
/// Gets or sets the content type definition for the import.
13+
/// </summary>
14+
public ContentTypeDefinition ContentTypeDefinition { get; set; }
15+
16+
/// <summary>
17+
/// Gets or sets the content transfer entry associated with the import.
18+
/// </summary>
19+
public ContentTransferEntry Entry { get; set; }
20+
21+
/// <summary>
22+
/// Gets or sets the rows that will be evaluated in the current batch.
23+
/// </summary>
24+
public IReadOnlyList<ContentImportRowFilterContext> Rows { get; set; }
25+
26+
/// <summary>
27+
/// Gets or sets the cancellation token for the current batch operation.
28+
/// </summary>
29+
public CancellationToken CancellationToken { get; set; }
30+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System.Data;
2+
using OrchardCore.ContentManagement.Metadata.Models;
3+
4+
namespace CrestApps.OrchardCore.ContentTransfer;
5+
6+
/// <summary>
7+
/// Context passed to <see cref="IContentImportRowFilter.ShouldSkipRowAsync"/> to evaluate a single row.
8+
/// </summary>
9+
public sealed class ContentImportRowFilterContext
10+
{
11+
/// <summary>
12+
/// Gets or sets the data row being evaluated.
13+
/// </summary>
14+
public DataRow Row { get; set; }
15+
16+
/// <summary>
17+
/// Gets or sets the data columns in the file.
18+
/// </summary>
19+
public DataColumnCollection Columns { get; set; }
20+
21+
/// <summary>
22+
/// Gets or sets the content type definition.
23+
/// </summary>
24+
public ContentTypeDefinition ContentTypeDefinition { get; set; }
25+
26+
/// <summary>
27+
/// Gets or sets the content transfer entry associated with this import.
28+
/// </summary>
29+
public ContentTransferEntry Entry { get; set; }
30+
31+
/// <summary>
32+
/// Gets or sets the row index (1-based).
33+
/// </summary>
34+
public int RowIndex { get; set; }
35+
36+
/// <summary>
37+
/// Gets or sets the reason the row should be skipped.
38+
/// </summary>
39+
public string SkipReason { get; set; }
40+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using OrchardCore.ContentManagement.Metadata.Models;
2+
3+
namespace CrestApps.OrchardCore.ContentTransfer;
4+
5+
/// <summary>
6+
/// Context passed to <see cref="IContentImportRowFilter.InitializeAsync"/> before import processing begins.
7+
/// </summary>
8+
public sealed class ContentImportRowFilterInitContext
9+
{
10+
/// <summary>
11+
/// Gets or sets the content type definition.
12+
/// </summary>
13+
public ContentTypeDefinition ContentTypeDefinition { get; set; }
14+
15+
/// <summary>
16+
/// Gets or sets the content transfer entry associated with this import.
17+
/// </summary>
18+
public ContentTransferEntry Entry { get; set; }
19+
}

src/Abstractions/CrestApps.OrchardCore.ContentTransfer.Abstractions/ContentPartImportMapContext.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ public sealed class ContentPartImportMapContext : ImportContentPartContext
77
{
88
public ContentItem ContentItem { get; set; }
99

10+
public ContentTransferEntry Entry { get; set; }
11+
1012
public DataColumnCollection Columns { get; set; }
1113

1214
public DataRow Row { get; set; }

src/Abstractions/CrestApps.OrchardCore.ContentTransfer.Abstractions/ContentTransferEntry.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,14 @@ public sealed class ContentTransferEntry : Entity
6969

7070
public enum ContentTransferEntryStatus
7171
{
72-
New,
73-
Processing,
74-
Completed,
75-
CompletedWithErrors,
76-
Canceled,
77-
CanceledWithImportedRecords,
78-
Failed,
72+
New = 0,
73+
Processing = 1,
74+
Completed = 2,
75+
CompletedWithErrors = 3,
76+
Failed = 6,
77+
Pending = 7,
78+
Paused = 8,
79+
Deleting = 9,
7980
}
8081

8182
public enum ContentTransferDirection
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
namespace CrestApps.OrchardCore.ContentTransfer;
2+
3+
/// <summary>
4+
/// Provides helpers for interpreting import-specific content transfer entry statuses.
5+
/// </summary>
6+
public static class ContentTransferEntryStatusExtensions
7+
{
8+
/// <summary>
9+
/// Determines whether the status represents a queued import waiting to start.
10+
/// </summary>
11+
/// <param name="status">The status to evaluate.</param>
12+
/// <returns><c>true</c> when the import is pending; otherwise, <c>false</c>.</returns>
13+
public static bool IsPendingImport(this ContentTransferEntryStatus status)
14+
=> status == ContentTransferEntryStatus.Pending
15+
|| status == ContentTransferEntryStatus.New;
16+
17+
/// <summary>
18+
/// Determines whether the status represents a paused import.
19+
/// </summary>
20+
/// <param name="status">The status to evaluate.</param>
21+
/// <returns><c>true</c> when the import is paused; otherwise, <c>false</c>.</returns>
22+
public static bool IsPausedImport(this ContentTransferEntryStatus status)
23+
=> status == ContentTransferEntryStatus.Paused;
24+
25+
/// <summary>
26+
/// Determines whether the status can be resumed for import processing.
27+
/// </summary>
28+
/// <param name="status">The status to evaluate.</param>
29+
/// <returns><c>true</c> when the import can be resumed; otherwise, <c>false</c>.</returns>
30+
public static bool CanResumeImport(this ContentTransferEntryStatus status)
31+
=> status.IsPendingImport()
32+
|| status.IsPausedImport()
33+
|| status == ContentTransferEntryStatus.Failed;
34+
35+
/// <summary>
36+
/// Determines whether the status should stop import processing.
37+
/// </summary>
38+
/// <param name="status">The status to evaluate.</param>
39+
/// <returns><c>true</c> when background import processing should stop; otherwise, <c>false</c>.</returns>
40+
public static bool ShouldStopImport(this ContentTransferEntryStatus status)
41+
=> status.IsPausedImport()
42+
|| status == ContentTransferEntryStatus.Deleting;
43+
44+
/// <summary>
45+
/// Maps import statuses to the normalized status used by the admin UI.
46+
/// </summary>
47+
/// <param name="status">The status to normalize.</param>
48+
/// <returns>The normalized import status for display and filtering.</returns>
49+
public static ContentTransferEntryStatus NormalizeImportStatus(this ContentTransferEntryStatus status)
50+
{
51+
if (status.IsPendingImport())
52+
{
53+
return ContentTransferEntryStatus.Pending;
54+
}
55+
56+
if (status.IsPausedImport())
57+
{
58+
return ContentTransferEntryStatus.Paused;
59+
}
60+
61+
return status;
62+
}
63+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#nullable enable
2+
3+
using System.Data;
4+
using OrchardCore.ContentManagement.Metadata.Models;
5+
6+
namespace CrestApps.OrchardCore.ContentTransfer;
7+
8+
/// <summary>
9+
/// Filters rows during content import. Implementations can reject rows before
10+
/// they are processed by the import pipeline (e.g., duplicate detection, DNC list checks).
11+
/// </summary>
12+
public interface IContentImportRowFilter
13+
{
14+
/// <summary>
15+
/// Called once before import processing begins to allow the filter to initialize state
16+
/// for the active import.
17+
/// </summary>
18+
/// <param name="context">The context containing the entry metadata and content type information.</param>
19+
/// <returns>
20+
/// <see langword="true"/> when the filter should participate in row filtering for the
21+
/// current import; otherwise, <see langword="false"/>.
22+
/// </returns>
23+
Task<bool> InitializeAsync(ContentImportRowFilterInitContext context);
24+
25+
/// <summary>
26+
/// Prepares filter state for the next import batch.
27+
/// </summary>
28+
/// <param name="context">The context containing the rows that are about to be evaluated.</param>
29+
/// <returns>A task that completes when the batch state is ready.</returns>
30+
Task PrepareBatchAsync(ContentImportRowFilterBatchContext context);
31+
32+
/// <summary>
33+
/// Determines whether a row should be skipped during import.
34+
/// </summary>
35+
/// <param name="context">The context containing the row data, entry metadata, and content type information.</param>
36+
/// <returns>
37+
/// <c>true</c> if the row should be skipped; <c>false</c> if it should be processed normally.
38+
/// </returns>
39+
Task<bool> ShouldSkipRowAsync(ContentImportRowFilterContext context);
40+
}

0 commit comments

Comments
 (0)