Skip to content

Conversation

@dr-3lo
Copy link
Collaborator

@dr-3lo dr-3lo commented Oct 20, 2025

Motivation

Contact Exports API support into .NET client (issue #155)

Changes

  • Added Contact Exports management interfaces, models, requests, and validation
  • Added example project to demonstrate Contact Exports API usage
  • Updated Contacts interface to provide access to Contact Exports
  • Added Contact Exports unit tests and integration tests
  • Extended Contacts unit tests to cover new methods for accessing events
  • Sealed few classes from Contacts API

How to test

Summary by CodeRabbit

  • New Features
    • Contact export: create exports with flexible filters (by list ID and subscription status).
    • Export lifecycle tracking: status (created/started/finished), timestamps, and download URL when ready.
  • Tests
    • Added unit and integration tests covering export creation, validation, serialization, and retrieval.

- Added Contact Exports management interfaces, models, requests, and validation
- Added example project to demonstrate Contact Exports API usage
- Updated Contacts interface to provide access to Contact Exports
- Added Contact Exports unit tests and integration tests
- Extended Contacts unit tests to cover new methods for accessing events
- Sealed few classes from Contacts API
@coderabbitai
Copy link

coderabbitai bot commented Oct 20, 2025

Walkthrough

Adds Contact Exports feature: new example project, abstraction interfaces, models (filters, status, export), validators, resource implementations, defensive-copy utilities, sealed record adjustments, solution updates, and comprehensive unit and integration tests. Integrates Exports endpoints under Contacts collection.

Changes

Cohort / File(s) Summary
Solution & Example Project
Mailtrap.sln, examples/Mailtrap.Example.ContactExports/*
Registers new example project in solution and adds Program.cs, appsettings.json, and launchSettings.json demonstrating contact export usage.
Abstractions: Exports API
src/Mailtrap.Abstractions/ContactExports/IContactExportCollectionResource.cs, src/Mailtrap.Abstractions/ContactExports/IContactExportResource.cs
Adds interfaces for creating contact exports and retrieving export details.
Models: ContactExport & Enums
src/Mailtrap.Abstractions/ContactExports/Models/ContactExport.cs, .../ContactExportStatus.cs
Adds ContactExport record and ContactExportStatus string-enum-like values (Created, Started, Finished).
Filter Models & Names/Operators
src/Mailtrap.Abstractions/ContactExports/Models/ContactExportFilterBase.cs, .../ContactExportListIdFilter.cs, .../ContactExportSubscriptionStatusFilter.cs, .../ContactExportFilterName.cs, .../ContactExportFilterOperator.cs, .../ContactExportFilterSubscriptionStatus.cs
Introduces polymorphic filter base with discriminators and concrete filters for list_id and subscription_status plus related string-enum types.
Requests & Validation
src/Mailtrap.Abstractions/ContactExports/Requests/CreateContactExportRequest.cs, src/Mailtrap.Abstractions/ContactExports/Validators/*.cs
Adds CreateContactExportRequest with defensive copying and validators enforcing filter count bounds (1–50,000) and per-filter rules.
Resource Implementations
src/Mailtrap/ContactExports/ContactExportCollectionResource.cs, src/Mailtrap/ContactExports/ContactExportResource.cs
Implements collection and single-resource classes delegating to RestResource command factory (Create, GetDetails).
Contacts Collection Extensions
src/Mailtrap.Abstractions/Contacts/IContactCollectionResource.cs, src/Mailtrap/Contacts/ContactCollectionResource.cs
Adds Exports() and Export(long exportId) accessors and ExportsSegment constant usage.
Core Utilities & StringEnum
src/Mailtrap.Abstractions/Core/Extensions/InternalCollectionExtensions.cs, src/Mailtrap.Abstractions/Core/Models/StringEnum.cs
Adds Clone extension helpers for defensive copying and IsDefined(T?) helper for StringEnum validation.
Sealed Records & Defensive Copying elsewhere
src/Mailtrap.Abstractions/ContactImports/..., src/Mailtrap.Abstractions/ContactLists/..., src/Mailtrap.Abstractions/AccountAccesses/..., src/Mailtrap.Abstractions/ContactEvents/...
Converts several records to sealed and standardizes defensive copying to use Clone().
Global Usings
src/Mailtrap.Abstractions/GlobalUsings.cs, src/Mailtrap/GlobalUsings.cs, tests/*/GlobalUsings.cs
Adds global using directives for Mailtrap.ContactExports namespaces across projects and tests.
Tests: Integration & Unit
tests/Mailtrap.IntegrationTests/ContactExports/*, tests/Mailtrap.UnitTests/ContactExports/*, tests/Mailtrap.UnitTests/Contacts/ContactCollectionResourceTests.cs
Adds integration tests (Create/GetDetails and fixtures) and extensive unit tests for models, validators, and resource constructors; extends contact collection tests for Exports/Export.
Test Constants
tests/*/TestConstants/UrlSegmentsTestConstants.cs
Adds ExportsSegment constant for tests.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Client
    participant ContactsResource
    participant ExportCollectionResource
    participant ExportResource
    participant RestFactory
    participant API

    Client->>ContactsResource: Exports()
    ContactsResource->>ExportCollectionResource: new(factory, /contacts/.../exports)
    ContactsResource-->>Client: IContactExportCollectionResource

    Client->>ExportCollectionResource: Create(CreateContactExportRequest)
    ExportCollectionResource->>RestFactory: Create<CreateContactExportRequest, ContactExport>()
    RestFactory->>API: POST /contacts/.../exports
    API-->>RestFactory: 201 {ContactExport}
    RestFactory-->>ExportCollectionResource: Task<ContactExport>
    ExportCollectionResource-->>Client: ContactExport

    Client->>ContactsResource: Export(exportId)
    ContactsResource->>ExportResource: new(factory, /contacts/.../exports/{id})
    ContactsResource-->>Client: IContactExportResource

    Client->>ExportResource: GetDetails()
    ExportResource->>RestFactory: Get<ContactExport>()
    RestFactory->>API: GET /contacts/.../exports/{id}
    API-->>RestFactory: 200 {ContactExport}
    RestFactory-->>ExportResource: Task<ContactExport>
    ExportResource-->>Client: ContactExport
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Feature/123 contact fields #150 — Similar extension of IContactCollectionResource adding nested resource accessors (Fields/Field); overlaps in contact-collection surface changes.
  • Feature/124 contact lists #143 — Adds other nested contact resources (Imports/Lists); related patterns and potential merge conflicts.
  • Feature- Contacts API #153 — Touches Contacts collection surface and resource navigation; likely to intersect with Exports additions.

Suggested reviewers

  • zhaparoff
  • mklocek

Poem

🐰 In the warren the exporters hop with cheer,

Filters and statuses now appear,
Cloned lists keep data snug and tight,
Sealed records hold their bounds just right,
Hooray — the Mailtrap burrow hums tonight! 📬✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "Feature - Add support of Contact Exports API into .NET client" is directly related to the main changeset. It clearly and concisely identifies this as a feature addition and specifically mentions Contact Exports API support, which is the central focus of all changes across abstractions, implementation, tests, and the example project. The title accurately summarizes the primary objective without being vague or misleading.
Description Check ✅ Passed The PR description includes all required sections from the template: Motivation is present (references issue #155), Changes section provides six clear bullet points documenting what was added and modified, and How to test includes a checklist with three items providing references to test locations and the example project. While the format varies slightly from the template examples (offering more detailed explanations rather than generic placeholders), the content is complete, specific, and communicates the necessary information for reviewers to understand the scope and purpose of the changes.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/155-Contact-Exports

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b8335b6 and ebe1109.

📒 Files selected for processing (1)
  • tests/Mailtrap.UnitTests/ContactExports/Model/ContactExportSubscriptionStatusFilterTests.cs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
tests/Mailtrap.UnitTests/ContactExports/Model/ContactExportSubscriptionStatusFilterTests.cs (2)
tests/Mailtrap.IntegrationTests/ContactExports/ContactExportIntegrationTests.cs (4)
  • Test (33-77)
  • Test (121-159)
  • Test (161-202)
  • Test (204-243)
src/Mailtrap.Abstractions/ContactExports/Validators/ContactExportFilterValidator.cs (2)
  • ContactExportFilterValidator (9-51)
  • ContactExportFilterValidator (16-50)
🔇 Additional comments (1)
tests/Mailtrap.UnitTests/ContactExports/Model/ContactExportSubscriptionStatusFilterTests.cs (1)

1-111: LGTM! Comprehensive and well-structured test coverage.

The test suite thoroughly validates the ContactExportSubscriptionStatusFilter behavior:

  • Constructor null-safety and field initialization
  • Record copy semantics using with expressions
  • Validation rules for both Value and Operator properties across null, empty, and invalid scenarios

The tests follow NUnit and FluentAssertions best practices with clear Arrange-Act-Assert structure and descriptive naming.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@dr-3lo dr-3lo linked an issue Oct 20, 2025 that may be closed by this pull request
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (6)
src/Mailtrap.Abstractions/AccountAccesses/Requests/UpdatePermissionsRequest.cs (1)

33-56: Consider using .Clone() consistently in both constructors.

Both constructors perform defensive copying, but use different methods: the params constructor uses .ToList() (line 37) while the IEnumerable constructor uses .Clone() (line 55). For consistency, consider using .Clone() in both places since it's the standardized pattern introduced in this PR.

Apply this diff to align the params constructor:

-        Permissions = permissions.ToList(); // Defensive copy to prevent post-ctor mutation.
+        Permissions = permissions.Clone(); // Defensive copy to prevent post-ctor mutation.
src/Mailtrap.Abstractions/ContactExports/Models/ContactExportFilterBase.cs (1)

28-30: Consider making Operator init-only or removing the setter.

The public setter on Operator allows post-construction mutation, which can bypass validation and introduce invalid state (e.g., setting it back to Unknown after construction). Since this is a record type intended for immutability, consider using init instead of set:

-    public ContactExportFilterOperator Operator { get; set; } = ContactExportFilterOperator.Unknown;
+    public ContactExportFilterOperator Operator { get; init; } = ContactExportFilterOperator.Unknown;

This maintains the ability to use with-expressions while preventing arbitrary mutation.

src/Mailtrap.Abstractions/ContactExports/Models/ContactExportListIdFilter.cs (1)

29-31: Consider using IReadOnlyList<int> for Value property.

While the property has only a getter, IList<int> is mutable, allowing external code to modify the collection after construction:

var filter = new ContactExportListIdFilter(1, 2, 3);
filter.Value.Add(4); // This works!

This undermines the defensive copying and record immutability. Consider changing to IReadOnlyList<int>:

-    public IList<int> Value { get; } = [];
+    public IReadOnlyList<int> Value { get; } = [];

You'll also need to update the constructors to return a read-only wrapper:

-        Value = value.Clone(); // defensive copy to prevent post-ctor mutation
+        Value = value.Clone().AsReadOnly(); // defensive copy to prevent post-ctor mutation
-        Value = new List<int>(values);
+        Value = Array.AsReadOnly(values);

This ensures true immutability consistent with the record type design.

src/Mailtrap.Abstractions/ContactExports/Models/ContactExportSubscriptionStatusFilter.cs (1)

29-31: Consider making Value init-only instead of settable.

The public setter on Value allows post-construction mutation and can bypass validation. Since this is a record type, consider using init instead:

-    public ContactExportFilterSubscriptionStatus Value { get; set; } = ContactExportFilterSubscriptionStatus.Unknown;
+    public ContactExportFilterSubscriptionStatus Value { get; init; } = ContactExportFilterSubscriptionStatus.Unknown;

This maintains record semantics and with-expression support while preventing arbitrary mutation after construction.

tests/Mailtrap.IntegrationTests/ContactExports/ContactExportIntegrationTests.cs (1)

244-262: Extract duplicated RandomContactExportFilter to shared test utility.

This method is duplicated in tests/Mailtrap.UnitTests/ContactExports/Requests/CreateContactExportRequestTests.cs (lines 89-107) with identical implementation. Consider extracting it to a shared test utility class to reduce duplication:

// Create a new file: tests/Mailtrap.TestUtilities/ContactExports/ContactExportTestHelpers.cs
namespace Mailtrap.TestUtilities.ContactExports;

public static class ContactExportTestHelpers
{
    public static ContactExportFilterBase RandomContactExportFilter()
    {
        if (TestContext.CurrentContext.Random.NextBool())
        {
            return new ContactExportListIdFilter(
                TestContext.CurrentContext.Random.Next(),
                TestContext.CurrentContext.Random.Next()
            );
        }
        else
        {
            var status = TestContext.CurrentContext.Random.NextBool() switch
            {
                true => ContactExportFilterSubscriptionStatus.Subscribed,
                false => ContactExportFilterSubscriptionStatus.Unsubscribed,
            };
            return new ContactExportSubscriptionStatusFilter(status);
        }
    }
}

Then reference it from both test files.

tests/Mailtrap.UnitTests/ContactExports/Model/ContactExportSubscriptionStatusFilterTests.cs (1)

7-15: Fix misleading test name.

The test name references "Collection" but the parameter is a single value, not a collection. This is inconsistent with the actual test behavior:

-    public void Constructor_Should_ThrowArgumentNullException_WhenProvidedCollectionIsNull()
+    public void Constructor_Should_ThrowArgumentNullException_WhenProvidedValueIsNull()
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0cdc391 and b8335b6.

📒 Files selected for processing (47)
  • Mailtrap.sln (3 hunks)
  • examples/Mailtrap.Example.ContactExports/Mailtrap.Example.ContactExports.csproj (1 hunks)
  • examples/Mailtrap.Example.ContactExports/Program.cs (1 hunks)
  • examples/Mailtrap.Example.ContactExports/Properties/launchSettings.json (1 hunks)
  • examples/Mailtrap.Example.ContactExports/appsettings.json (1 hunks)
  • src/Mailtrap.Abstractions/AccountAccesses/Requests/UpdatePermissionsRequest.cs (1 hunks)
  • src/Mailtrap.Abstractions/ContactEvents/Requests/CreateContactEventRequest.cs (1 hunks)
  • src/Mailtrap.Abstractions/ContactExports/IContactExportCollectionResource.cs (1 hunks)
  • src/Mailtrap.Abstractions/ContactExports/IContactExportResource.cs (1 hunks)
  • src/Mailtrap.Abstractions/ContactExports/Models/ContactExport.cs (1 hunks)
  • src/Mailtrap.Abstractions/ContactExports/Models/ContactExportFilterBase.cs (1 hunks)
  • src/Mailtrap.Abstractions/ContactExports/Models/ContactExportFilterName.cs (1 hunks)
  • src/Mailtrap.Abstractions/ContactExports/Models/ContactExportFilterOperator.cs (1 hunks)
  • src/Mailtrap.Abstractions/ContactExports/Models/ContactExportFilterSubscriptionStatus.cs (1 hunks)
  • src/Mailtrap.Abstractions/ContactExports/Models/ContactExportListIdFilter.cs (1 hunks)
  • src/Mailtrap.Abstractions/ContactExports/Models/ContactExportStatus.cs (1 hunks)
  • src/Mailtrap.Abstractions/ContactExports/Models/ContactExportSubscriptionStatusFilter.cs (1 hunks)
  • src/Mailtrap.Abstractions/ContactExports/Requests/CreateContactExportRequest.cs (1 hunks)
  • src/Mailtrap.Abstractions/ContactExports/Validators/ContactExportFilterValidator.cs (1 hunks)
  • src/Mailtrap.Abstractions/ContactExports/Validators/CreateContactExportRequestValidator.cs (1 hunks)
  • src/Mailtrap.Abstractions/ContactImports/Models/ContactImport.cs (1 hunks)
  • src/Mailtrap.Abstractions/ContactImports/Requests/CreateContactImportRequest.cs (2 hunks)
  • src/Mailtrap.Abstractions/ContactLists/Requests/ContactListRequest.cs (1 hunks)
  • src/Mailtrap.Abstractions/Contacts/IContactCollectionResource.cs (1 hunks)
  • src/Mailtrap.Abstractions/Core/Extensions/InternalCollectionExtensions.cs (1 hunks)
  • src/Mailtrap.Abstractions/Core/Models/StringEnum.cs (3 hunks)
  • src/Mailtrap.Abstractions/GlobalUsings.cs (1 hunks)
  • src/Mailtrap/ContactExports/ContactExportCollectionResource.cs (1 hunks)
  • src/Mailtrap/ContactExports/ContactExportResource.cs (1 hunks)
  • src/Mailtrap/Contacts/ContactCollectionResource.cs (2 hunks)
  • src/Mailtrap/GlobalUsings.cs (1 hunks)
  • tests/Mailtrap.IntegrationTests/ContactExports/ContactExportIntegrationTests.cs (1 hunks)
  • tests/Mailtrap.IntegrationTests/ContactExports/Create_Success_Request.json (1 hunks)
  • tests/Mailtrap.IntegrationTests/ContactExports/Create_Success_Response.json (1 hunks)
  • tests/Mailtrap.IntegrationTests/ContactExports/GetDetails_ShouldCorrectlyHandleUri.json (1 hunks)
  • tests/Mailtrap.IntegrationTests/ContactExports/GetDetails_Success.json (1 hunks)
  • tests/Mailtrap.IntegrationTests/GlobalUsings.cs (1 hunks)
  • tests/Mailtrap.IntegrationTests/TestConstants/UrlSegmentsTestConstants.cs (1 hunks)
  • tests/Mailtrap.UnitTests/ContactExports/ContactExportCollectionResourceTests.cs (1 hunks)
  • tests/Mailtrap.UnitTests/ContactExports/ContactExportResourceTests.cs (1 hunks)
  • tests/Mailtrap.UnitTests/ContactExports/Model/ContactExportFilterBaseTests.cs (1 hunks)
  • tests/Mailtrap.UnitTests/ContactExports/Model/ContactExportListIdFilterTests.cs (1 hunks)
  • tests/Mailtrap.UnitTests/ContactExports/Model/ContactExportSubscriptionStatusFilterTests.cs (1 hunks)
  • tests/Mailtrap.UnitTests/ContactExports/Requests/CreateContactExportRequestTests.cs (1 hunks)
  • tests/Mailtrap.UnitTests/Contacts/ContactCollectionResourceTests.cs (1 hunks)
  • tests/Mailtrap.UnitTests/GlobalUsings.cs (1 hunks)
  • tests/Mailtrap.UnitTests/TestConstants/UrlSegmentsTestConstants.cs (1 hunks)
🧰 Additional context used
🧠 Learnings (14)
📚 Learning: 2025-09-22T08:20:57.431Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#150
File: src/Mailtrap.Abstractions/ContactFields/Validators/CreateContactsFieldRequestValidator.cs:8-8
Timestamp: 2025-09-22T08:20:57.431Z
Learning: In the Mailtrap.Abstractions project, global using statements in GlobalUsings.cs make types from Mailtrap.ContactFields.Requests (and other ContactFields namespaces) globally available, so explicit using statements are not needed in individual files like validators.

Applied to files:

  • tests/Mailtrap.IntegrationTests/GlobalUsings.cs
  • src/Mailtrap/GlobalUsings.cs
  • tests/Mailtrap.UnitTests/GlobalUsings.cs
  • src/Mailtrap.Abstractions/GlobalUsings.cs
📚 Learning: 2025-09-22T08:20:27.736Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#150
File: src/Mailtrap.Abstractions/ContactFields/Validators/CreateContactsFieldRequestValidator.cs:1-1
Timestamp: 2025-09-22T08:20:27.736Z
Learning: In the Mailtrap .NET project, FluentValidation is imported globally through GlobalUsings.cs files, making explicit using statements for FluentValidation unnecessary in individual validator files within the project.

Applied to files:

  • tests/Mailtrap.IntegrationTests/GlobalUsings.cs
  • src/Mailtrap/GlobalUsings.cs
  • tests/Mailtrap.UnitTests/GlobalUsings.cs
  • src/Mailtrap.Abstractions/GlobalUsings.cs
📚 Learning: 2025-09-25T10:10:41.714Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#153
File: examples/Mailtrap.Example.ContactFields/Mailtrap.Example.ContactFields.csproj:1-1
Timestamp: 2025-09-25T10:10:41.714Z
Learning: In the Mailtrap .NET client project, example projects automatically inherit configuration from mailtrap-example.props through examples/Directory.Build.props, which imports build/mailtrap-example.props. This means example .csproj files don't need explicit Import statements and can be simplified to just the SDK declaration.

Applied to files:

  • tests/Mailtrap.IntegrationTests/GlobalUsings.cs
  • Mailtrap.sln
  • examples/Mailtrap.Example.ContactExports/Mailtrap.Example.ContactExports.csproj
  • examples/Mailtrap.Example.ContactExports/Properties/launchSettings.json
  • examples/Mailtrap.Example.ContactExports/Program.cs
  • src/Mailtrap.Abstractions/GlobalUsings.cs
📚 Learning: 2025-09-25T10:10:38.229Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#153
File: examples/Mailtrap.Example.Email.Send/Mailtrap.Example.Email.Send.csproj:1-1
Timestamp: 2025-09-25T10:10:38.229Z
Learning: In the Mailtrap .NET client project, example projects automatically get their shared properties (TargetFramework, ProjectReference to Mailtrap.csproj, etc.) through the examples/Directory.Build.props file which imports mailtrap-example.props, so individual example .csproj files don't need explicit <Import> statements.

Applied to files:

  • tests/Mailtrap.IntegrationTests/GlobalUsings.cs
  • src/Mailtrap/GlobalUsings.cs
  • Mailtrap.sln
  • examples/Mailtrap.Example.ContactExports/Mailtrap.Example.ContactExports.csproj
  • examples/Mailtrap.Example.ContactExports/Properties/launchSettings.json
  • examples/Mailtrap.Example.ContactExports/Program.cs
  • src/Mailtrap.Abstractions/GlobalUsings.cs
📚 Learning: 2025-09-25T10:10:28.647Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#153
File: examples/Mailtrap.Example.Billing/Mailtrap.Example.Billing.csproj:1-1
Timestamp: 2025-09-25T10:10:28.647Z
Learning: In the Mailtrap .NET client project, example projects automatically inherit shared build configuration through Directory.Build.props mechanism - the examples/Directory.Build.props imports ../build/mailtrap-example.props, so individual .csproj files don't need explicit import statements and can remain minimal.

Applied to files:

  • tests/Mailtrap.IntegrationTests/GlobalUsings.cs
  • Mailtrap.sln
  • examples/Mailtrap.Example.ContactExports/Mailtrap.Example.ContactExports.csproj
  • examples/Mailtrap.Example.ContactExports/Properties/launchSettings.json
  • examples/Mailtrap.Example.ContactExports/Program.cs
  • src/Mailtrap.Abstractions/GlobalUsings.cs
📚 Learning: 2025-09-25T10:10:41.714Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#153
File: examples/Mailtrap.Example.ContactFields/Mailtrap.Example.ContactFields.csproj:1-1
Timestamp: 2025-09-25T10:10:41.714Z
Learning: In the Mailtrap .NET client project, example projects automatically inherit configuration from mailtrap-example.props through Directory.Build.props, which conditionally imports build/mailtrap-example.props for any project in the examples directory. This means example .csproj files don't need explicit Import statements.

Applied to files:

  • tests/Mailtrap.IntegrationTests/GlobalUsings.cs
  • Mailtrap.sln
  • examples/Mailtrap.Example.ContactExports/Mailtrap.Example.ContactExports.csproj
  • examples/Mailtrap.Example.ContactExports/Properties/launchSettings.json
  • examples/Mailtrap.Example.ContactExports/Program.cs
📚 Learning: 2025-09-10T17:01:49.270Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#142
File: src/Mailtrap.Abstractions/ContactImports/Validators/ContactsImportRequestValidator.cs:27-30
Timestamp: 2025-09-10T17:01:49.270Z
Learning: In ContactsImportRequestValidator, ContactRequestValidator.Instance is used to validate ContactImportRequest items because ContactImportRequest inherits from ContactRequest and doesn't introduce additional validation rules that would require a separate validator.

Applied to files:

  • src/Mailtrap.Abstractions/ContactExports/Validators/ContactExportFilterValidator.cs
  • src/Mailtrap.Abstractions/ContactImports/Requests/CreateContactImportRequest.cs
  • src/Mailtrap.Abstractions/ContactExports/Validators/CreateContactExportRequestValidator.cs
📚 Learning: 2025-09-25T13:46:15.548Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#153
File: tests/Mailtrap.IntegrationTests/ContactLists/ContactsListIntegrationTests.cs:86-87
Timestamp: 2025-09-25T13:46:15.548Z
Learning: The ContactListRequest class has both a parameterized constructor ContactListRequest(string name) and a parameterless constructor ContactListRequest(), so both instantiation patterns are valid.

Applied to files:

  • src/Mailtrap.Abstractions/ContactLists/Requests/ContactListRequest.cs
📚 Learning: 2025-09-10T14:37:39.872Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#142
File: src/Mailtrap/Contacts/ContactCollectionResource.cs:18-19
Timestamp: 2025-09-10T14:37:39.872Z
Learning: The Import method in ContactCollectionResource does not need explicit importId validation because this validation is already implemented in the URI model's Append method when handling long parameters.

Applied to files:

  • tests/Mailtrap.UnitTests/Contacts/ContactCollectionResourceTests.cs
  • src/Mailtrap/Contacts/ContactCollectionResource.cs
📚 Learning: 2025-09-25T10:10:41.714Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#153
File: examples/Mailtrap.Example.ContactFields/Mailtrap.Example.ContactFields.csproj:1-1
Timestamp: 2025-09-25T10:10:41.714Z
Learning: In the Mailtrap .NET client project, example projects automatically inherit configuration from build/mailtrap-example.props through examples/Directory.Build.props, which imports $(BuildConfigurationDirectory)mailtrap-example.props. This means example .csproj files don't need explicit Import statements and can be simplified to just the SDK declaration, as they get TargetFrameworks, OutputType, project references, and other shared settings automatically.

Applied to files:

  • Mailtrap.sln
  • examples/Mailtrap.Example.ContactExports/Mailtrap.Example.ContactExports.csproj
  • examples/Mailtrap.Example.ContactExports/Properties/launchSettings.json
  • examples/Mailtrap.Example.ContactExports/Program.cs
📚 Learning: 2025-09-25T10:10:41.519Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#153
File: examples/Mailtrap.Example.ContactLists/Mailtrap.Example.ContactLists.csproj:1-1
Timestamp: 2025-09-25T10:10:41.519Z
Learning: In the Mailtrap .NET client project, example projects inherit their dependencies through MSBuild's hierarchical property system via examples/Directory.Build.props and build/mailtrap-example.props, allowing individual .csproj files to be minimal (just <Project Sdk="Microsoft.NET.Sdk"/>) while still having access to all required project references, package dependencies, and build configuration.

Applied to files:

  • Mailtrap.sln
  • examples/Mailtrap.Example.ContactExports/Mailtrap.Example.ContactExports.csproj
  • examples/Mailtrap.Example.ContactExports/Program.cs
📚 Learning: 2025-09-22T09:52:44.054Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#150
File: examples/Mailtrap.Example.ContactFields/Mailtrap.Example.ContactFields.csproj:1-10
Timestamp: 2025-09-22T09:52:44.054Z
Learning: In the Mailtrap .NET client project, example projects use a centralized `mailtrap-example.props` file to define common MSBuild properties like TargetFramework, so individual .csproj files don't need to explicitly declare these properties.

Applied to files:

  • Mailtrap.sln
  • examples/Mailtrap.Example.ContactExports/Mailtrap.Example.ContactExports.csproj
  • examples/Mailtrap.Example.ContactExports/Properties/launchSettings.json
  • examples/Mailtrap.Example.ContactExports/Program.cs
📚 Learning: 2025-09-25T10:13:09.845Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#153
File: examples/Mailtrap.Example.Factory/Mailtrap.Example.Factory.csproj:5-7
Timestamp: 2025-09-25T10:13:09.845Z
Learning: The Mailtrap.Example.Factory project doesn't use host builder or configuration loading, so it doesn't require appsettings.json. It uses `<None Remove="appsettings.json"/>` to override the default inclusion rule from mailtrap-example.props.

Applied to files:

  • Mailtrap.sln
  • examples/Mailtrap.Example.ContactExports/appsettings.json
  • examples/Mailtrap.Example.ContactExports/Mailtrap.Example.ContactExports.csproj
  • examples/Mailtrap.Example.ContactExports/Properties/launchSettings.json
  • examples/Mailtrap.Example.ContactExports/Program.cs
📚 Learning: 2025-09-25T10:13:09.845Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#153
File: examples/Mailtrap.Example.Factory/Mailtrap.Example.Factory.csproj:5-7
Timestamp: 2025-09-25T10:13:09.845Z
Learning: The Mailtrap.Example.Factory project demonstrates standalone MailtrapClientFactory usage without configuration files or host builder. It uses `<None Remove="appsettings.json"/>` to override the default inclusion rule from mailtrap-example.props since it doesn't require appsettings.json.

Applied to files:

  • examples/Mailtrap.Example.ContactExports/appsettings.json
  • examples/Mailtrap.Example.ContactExports/Mailtrap.Example.ContactExports.csproj
  • examples/Mailtrap.Example.ContactExports/Program.cs
🧬 Code graph analysis (29)
src/Mailtrap.Abstractions/Contacts/IContactCollectionResource.cs (1)
src/Mailtrap/Contacts/ContactCollectionResource.cs (2)
  • IContactExportCollectionResource (17-18)
  • IContactExportResource (20-21)
src/Mailtrap/ContactExports/ContactExportResource.cs (5)
tests/Mailtrap.UnitTests/ContactExports/ContactExportResourceTests.cs (1)
  • ContactExportResource (51-51)
src/Mailtrap/Contacts/ContactCollectionResource.cs (3)
  • IContactExportResource (20-21)
  • Task (44-45)
  • Task (47-48)
src/Mailtrap.Abstractions/ContactExports/IContactExportResource.cs (1)
  • Task (19-19)
src/Mailtrap/ContactExports/ContactExportCollectionResource.cs (1)
  • Task (11-12)
src/Mailtrap/ContactImports/ContactImportResource.cs (1)
  • ContactImportResource (6-13)
src/Mailtrap.Abstractions/AccountAccesses/Requests/UpdatePermissionsRequest.cs (1)
src/Mailtrap.Abstractions/Core/Extensions/Ensure.cs (2)
  • Ensure (9-106)
  • NotNull (18-33)
src/Mailtrap.Abstractions/ContactExports/Models/ContactExportStatus.cs (1)
src/Mailtrap.Abstractions/Core/Models/StringEnum.cs (1)
  • StringEnum (41-49)
src/Mailtrap.Abstractions/ContactExports/Validators/ContactExportFilterValidator.cs (4)
tests/Mailtrap.IntegrationTests/ContactExports/ContactExportIntegrationTests.cs (1)
  • ContactExportFilterBase (244-262)
tests/Mailtrap.UnitTests/ContactExports/Requests/CreateContactExportRequestTests.cs (1)
  • ContactExportFilterBase (90-108)
src/Mailtrap.Abstractions/Core/Models/StringEnum.cs (1)
  • IsDefined (111-118)
src/Mailtrap.Abstractions/ContactExports/Models/ContactExportListIdFilter.cs (2)
  • ContactExportListIdFilter (63-69)
  • ContactExportListIdFilter (83-89)
src/Mailtrap.Abstractions/ContactExports/IContactExportResource.cs (5)
src/Mailtrap.Abstractions/Contacts/IContactCollectionResource.cs (3)
  • IContactExportResource (32-32)
  • Task (136-136)
  • Task (153-153)
src/Mailtrap/Contacts/ContactCollectionResource.cs (3)
  • IContactExportResource (20-21)
  • Task (44-45)
  • Task (47-48)
src/Mailtrap.Abstractions/ContactExports/IContactExportCollectionResource.cs (1)
  • Task (23-23)
src/Mailtrap/ContactExports/ContactExportCollectionResource.cs (1)
  • Task (11-12)
src/Mailtrap/ContactExports/ContactExportResource.cs (1)
  • Task (11-12)
src/Mailtrap.Abstractions/ContactExports/Models/ContactExportFilterName.cs (2)
src/Mailtrap.Abstractions/Core/Models/StringEnum.cs (1)
  • StringEnum (41-49)
src/Mailtrap.Abstractions/ContactExports/Models/ContactExportListIdFilter.cs (2)
  • ContactExportListIdFilter (63-69)
  • ContactExportListIdFilter (83-89)
src/Mailtrap/ContactExports/ContactExportCollectionResource.cs (6)
tests/Mailtrap.UnitTests/ContactExports/ContactExportCollectionResourceTests.cs (1)
  • ContactExportCollectionResource (51-51)
src/Mailtrap.Abstractions/Contacts/IContactCollectionResource.cs (3)
  • IContactExportCollectionResource (15-15)
  • Task (136-136)
  • Task (153-153)
src/Mailtrap/Contacts/ContactCollectionResource.cs (3)
  • IContactExportCollectionResource (17-18)
  • Task (44-45)
  • Task (47-48)
src/Mailtrap.Abstractions/ContactExports/IContactExportCollectionResource.cs (1)
  • Task (23-23)
src/Mailtrap/ContactExports/ContactExportResource.cs (1)
  • Task (11-12)
src/Mailtrap.Abstractions/ContactExports/Requests/CreateContactExportRequest.cs (1)
  • CreateContactExportRequest (38-44)
tests/Mailtrap.UnitTests/Contacts/ContactCollectionResourceTests.cs (6)
tests/Mailtrap.UnitTests/TestExtensions/ResourceValidator.cs (2)
  • ResourceValidator (4-16)
  • Validate (6-15)
src/Mailtrap.Abstractions/Contacts/IContactCollectionResource.cs (2)
  • IContactExportCollectionResource (15-15)
  • IContactExportResource (32-32)
src/Mailtrap/Contacts/ContactCollectionResource.cs (2)
  • IContactExportCollectionResource (17-18)
  • IContactExportResource (20-21)
src/Mailtrap/ContactExports/ContactExportCollectionResource.cs (2)
  • ContactExportCollectionResource (6-13)
  • ContactExportCollectionResource (8-9)
tests/Mailtrap.UnitTests/TestConstants/UrlSegmentsTestConstants.cs (1)
  • UrlSegmentsTestConstants (4-24)
src/Mailtrap/ContactExports/ContactExportResource.cs (2)
  • ContactExportResource (6-13)
  • ContactExportResource (8-9)
src/Mailtrap.Abstractions/Core/Extensions/InternalCollectionExtensions.cs (1)
src/Mailtrap.Abstractions/Core/Extensions/Ensure.cs (2)
  • Ensure (9-106)
  • NotNull (18-33)
src/Mailtrap.Abstractions/ContactExports/IContactExportCollectionResource.cs (4)
src/Mailtrap.Abstractions/Contacts/IContactCollectionResource.cs (3)
  • IContactExportCollectionResource (15-15)
  • Task (136-136)
  • Task (153-153)
src/Mailtrap/Contacts/ContactCollectionResource.cs (3)
  • IContactExportCollectionResource (17-18)
  • Task (44-45)
  • Task (47-48)
src/Mailtrap/ContactExports/ContactExportCollectionResource.cs (1)
  • Task (11-12)
src/Mailtrap.Abstractions/ContactExports/Requests/CreateContactExportRequest.cs (1)
  • CreateContactExportRequest (38-44)
src/Mailtrap.Abstractions/ContactExports/Models/ContactExportSubscriptionStatusFilter.cs (3)
tests/Mailtrap.IntegrationTests/ContactExports/ContactExportIntegrationTests.cs (1)
  • ContactExportFilterBase (244-262)
tests/Mailtrap.UnitTests/ContactExports/Requests/CreateContactExportRequestTests.cs (1)
  • ContactExportFilterBase (90-108)
src/Mailtrap.Abstractions/Core/Extensions/Ensure.cs (2)
  • Ensure (9-106)
  • NotNull (18-33)
src/Mailtrap.Abstractions/ContactExports/Models/ContactExport.cs (1)
src/Mailtrap.Abstractions/Contacts/Converters/DateTimeToUnixMsJsonConverter.cs (1)
  • DateTimeOffset (8-22)
src/Mailtrap/Contacts/ContactCollectionResource.cs (3)
src/Mailtrap.Abstractions/Contacts/IContactCollectionResource.cs (2)
  • IContactExportCollectionResource (15-15)
  • IContactExportResource (32-32)
src/Mailtrap/ContactExports/ContactExportCollectionResource.cs (2)
  • ContactExportCollectionResource (6-13)
  • ContactExportCollectionResource (8-9)
src/Mailtrap/ContactExports/ContactExportResource.cs (2)
  • ContactExportResource (6-13)
  • ContactExportResource (8-9)
tests/Mailtrap.UnitTests/ContactExports/Model/ContactExportFilterBaseTests.cs (4)
src/Mailtrap/Configuration/MailtrapClientOptions.cs (1)
  • JsonSerializerOptions (148-154)
src/Mailtrap/Configuration/MailtrapJsonSerializerOptions.cs (1)
  • MailtrapJsonSerializerOptions (4-19)
src/Mailtrap.Abstractions/ContactExports/Requests/CreateContactExportRequest.cs (1)
  • CreateContactExportRequest (38-44)
src/Mailtrap.Abstractions/ContactExports/Models/ContactExportListIdFilter.cs (2)
  • ContactExportListIdFilter (63-69)
  • ContactExportListIdFilter (83-89)
tests/Mailtrap.UnitTests/ContactExports/Model/ContactExportListIdFilterTests.cs (2)
src/Mailtrap.Abstractions/ContactExports/Models/ContactExportListIdFilter.cs (2)
  • ContactExportListIdFilter (63-69)
  • ContactExportListIdFilter (83-89)
src/Mailtrap.Abstractions/ContactExports/Validators/ContactExportFilterValidator.cs (2)
  • ContactExportFilterValidator (9-51)
  • ContactExportFilterValidator (16-50)
src/Mailtrap.Abstractions/ContactExports/Models/ContactExportFilterBase.cs (3)
src/Mailtrap.Abstractions/ContactExports/Models/ContactExportListIdFilter.cs (2)
  • ContactExportListIdFilter (63-69)
  • ContactExportListIdFilter (83-89)
tests/Mailtrap.IntegrationTests/ContactExports/ContactExportIntegrationTests.cs (1)
  • ContactExportFilterBase (244-262)
tests/Mailtrap.UnitTests/ContactExports/Requests/CreateContactExportRequestTests.cs (1)
  • ContactExportFilterBase (90-108)
src/Mailtrap.Abstractions/ContactExports/Models/ContactExportFilterSubscriptionStatus.cs (1)
src/Mailtrap.Abstractions/Core/Models/StringEnum.cs (1)
  • StringEnum (41-49)
tests/Mailtrap.IntegrationTests/ContactExports/ContactExportIntegrationTests.cs (11)
tests/Mailtrap.UnitTests/ContactExports/Requests/CreateContactExportRequestTests.cs (1)
  • ContactExportFilterBase (90-108)
src/Mailtrap/Configuration/MailtrapClientOptions.cs (1)
  • JsonSerializerOptions (148-154)
tests/Mailtrap.IntegrationTests/TestConstants/UrlSegmentsTestConstants.cs (1)
  • UrlSegmentsTestConstants (4-27)
src/Mailtrap.Abstractions/ContactExports/IContactExportCollectionResource.cs (1)
  • Task (23-23)
src/Mailtrap.Abstractions/ContactExports/IContactExportResource.cs (1)
  • Task (19-19)
src/Mailtrap/ContactExports/ContactExportCollectionResource.cs (1)
  • Task (11-12)
src/Mailtrap/ContactExports/ContactExportResource.cs (1)
  • Task (11-12)
src/Mailtrap.Abstractions/ContactExports/Requests/CreateContactExportRequest.cs (1)
  • CreateContactExportRequest (38-44)
src/Mailtrap/Core/Constants/MimeTypes.cs (2)
  • MimeTypes (4-19)
  • Application (6-11)
src/Mailtrap/Core/Constants/HeaderValues.cs (1)
  • HeaderValues (7-12)
src/Mailtrap.Abstractions/ContactExports/Models/ContactExportListIdFilter.cs (2)
  • ContactExportListIdFilter (63-69)
  • ContactExportListIdFilter (83-89)
src/Mailtrap.Abstractions/ContactExports/Models/ContactExportFilterOperator.cs (1)
src/Mailtrap.Abstractions/Core/Models/StringEnum.cs (1)
  • StringEnum (41-49)
tests/Mailtrap.UnitTests/ContactExports/ContactExportCollectionResourceTests.cs (3)
tests/Mailtrap.UnitTests/ContactExports/ContactExportResourceTests.cs (1)
  • TestFixture (4-52)
tests/Mailtrap.UnitTests/TestConstants/UrlSegmentsTestConstants.cs (1)
  • UrlSegmentsTestConstants (4-24)
src/Mailtrap/ContactExports/ContactExportCollectionResource.cs (2)
  • ContactExportCollectionResource (6-13)
  • ContactExportCollectionResource (8-9)
src/Mailtrap.Abstractions/ContactExports/Requests/CreateContactExportRequest.cs (3)
src/Mailtrap.Abstractions/Core/Extensions/InternalCollectionExtensions.cs (1)
  • IList (23-31)
src/Mailtrap.Abstractions/Core/Extensions/Ensure.cs (1)
  • Ensure (9-106)
src/Mailtrap.Abstractions/ContactExports/Validators/CreateContactExportRequestValidator.cs (2)
  • CreateContactExportRequestValidator (8-33)
  • CreateContactExportRequestValidator (21-32)
src/Mailtrap.Abstractions/Core/Models/StringEnum.cs (1)
src/Mailtrap/Core/Converters/StringEnumJsonConverter.cs (1)
  • T (11-23)
examples/Mailtrap.Example.ContactExports/Program.cs (1)
src/Mailtrap.Abstractions/ContactExports/Requests/CreateContactExportRequest.cs (1)
  • CreateContactExportRequest (38-44)
src/Mailtrap.Abstractions/ContactExports/Validators/CreateContactExportRequestValidator.cs (2)
src/Mailtrap.Abstractions/ContactExports/Requests/CreateContactExportRequest.cs (1)
  • CreateContactExportRequest (38-44)
src/Mailtrap.Abstractions/ContactExports/Validators/ContactExportFilterValidator.cs (2)
  • ContactExportFilterValidator (9-51)
  • ContactExportFilterValidator (16-50)
tests/Mailtrap.UnitTests/ContactExports/ContactExportResourceTests.cs (4)
tests/Mailtrap.UnitTests/ContactExports/ContactExportCollectionResourceTests.cs (1)
  • TestFixture (4-52)
tests/Mailtrap.UnitTests/Contacts/ContactCollectionResourceTests.cs (1)
  • TestFixture (4-254)
tests/Mailtrap.UnitTests/TestConstants/UrlSegmentsTestConstants.cs (1)
  • UrlSegmentsTestConstants (4-24)
src/Mailtrap/ContactExports/ContactExportResource.cs (2)
  • ContactExportResource (6-13)
  • ContactExportResource (8-9)
tests/Mailtrap.UnitTests/ContactExports/Requests/CreateContactExportRequestTests.cs (3)
src/Mailtrap.Abstractions/ContactExports/Requests/CreateContactExportRequest.cs (1)
  • CreateContactExportRequest (38-44)
src/Mailtrap.Abstractions/ContactExports/Validators/CreateContactExportRequestValidator.cs (2)
  • CreateContactExportRequestValidator (8-33)
  • CreateContactExportRequestValidator (21-32)
src/Mailtrap.Abstractions/ContactExports/Models/ContactExportListIdFilter.cs (2)
  • ContactExportListIdFilter (63-69)
  • ContactExportListIdFilter (83-89)
src/Mailtrap.Abstractions/ContactExports/Models/ContactExportListIdFilter.cs (5)
tests/Mailtrap.IntegrationTests/ContactExports/ContactExportIntegrationTests.cs (1)
  • ContactExportFilterBase (244-262)
tests/Mailtrap.UnitTests/ContactExports/Requests/CreateContactExportRequestTests.cs (1)
  • ContactExportFilterBase (90-108)
src/Mailtrap.Abstractions/Core/Extensions/InternalCollectionExtensions.cs (1)
  • IList (23-31)
src/Mailtrap.Abstractions/ContactExports/Models/ContactExportSubscriptionStatusFilter.cs (1)
  • JsonConstructor (45-52)
src/Mailtrap.Abstractions/Core/Extensions/Ensure.cs (1)
  • Ensure (9-106)
tests/Mailtrap.UnitTests/ContactExports/Model/ContactExportSubscriptionStatusFilterTests.cs (1)
src/Mailtrap.Abstractions/ContactExports/Validators/ContactExportFilterValidator.cs (2)
  • ContactExportFilterValidator (9-51)
  • ContactExportFilterValidator (16-50)
🔇 Additional comments (50)
tests/Mailtrap.IntegrationTests/GlobalUsings.cs (1)

18-19: LGTM!

The new global using directives for ContactExports follow the established project pattern and are correctly placed near the related Contacts namespaces. This change is necessary to support the new ContactExports integration tests added in this PR.

src/Mailtrap/GlobalUsings.cs (1)

36-38: LGTM – No changes needed.

The global using directives are correct as written. While validators exist for ContactExports (they're internal sealed classes in Abstractions), the pattern in the main project is intentionally selective: only Contacts, EmailTemplates, and Projects expose Validators globally. ContactExports correctly follows the same pattern as ContactImports, ContactLists, ContactFields, and ContactEvents—omitting the Validators namespace.

src/Mailtrap.Abstractions/ContactImports/Models/ContactImport.cs (1)

6-6: LGTM! Sealing the record is appropriate.

Sealing this data model prevents unintended inheritance and is consistent with best practices for DTOs.

src/Mailtrap.Abstractions/ContactExports/IContactExportResource.cs (1)

1-20: LGTM! Interface follows established patterns.

The interface design is consistent with existing REST resource interfaces in the codebase, with proper async/await support and cancellation token handling.

src/Mailtrap.Abstractions/Core/Extensions/InternalCollectionExtensions.cs (1)

1-65: LGTM! Defensive copying implementation is correct and efficient.

The Clone extension methods properly prevent post-constructor mutation while optimizing for common collection types. The null checks and documentation are thorough.

src/Mailtrap.Abstractions/ContactImports/Requests/CreateContactImportRequest.cs (2)

6-6: LGTM! Sealing the request is appropriate.

Sealing this request model prevents unintended inheritance and is consistent with the PR's objective to seal classes from the Contacts API.


39-45: LGTM! Simplified defensive copying using the new Clone extension.

The uniform Clone() call replaces conditional branching logic while maintaining the defensive copy behavior, improving code clarity and consistency.

examples/Mailtrap.Example.ContactExports/Mailtrap.Example.ContactExports.csproj (1)

1-1: LGTM! Project file follows established conventions.

The minimal project file is correct, as example projects automatically inherit shared configuration through the Directory.Build.props mechanism.

Based on learnings

examples/Mailtrap.Example.ContactExports/Properties/launchSettings.json (1)

1-10: LGTM! Standard launch settings configuration.

The launch settings properly configure the Development environment for the example project, consistent with .NET conventions.

tests/Mailtrap.IntegrationTests/ContactExports/Create_Success_Response.json (1)

1-7: LGTM! Test fixture correctly models initial export state.

The fixture appropriately shows status "started" for a newly created export, with url as null until the export completes.

tests/Mailtrap.IntegrationTests/ContactExports/GetDetails_Success.json (1)

1-7: LGTM! Test fixture correctly models export details state.

The fixture appropriately shows status "created" for a completed export, representing progression from the "started" state in the create response.

tests/Mailtrap.UnitTests/TestConstants/UrlSegmentsTestConstants.cs (1)

19-19: LGTM!

The new ExportsSegment constant follows the established pattern and naming conventions in this file.

examples/Mailtrap.Example.ContactExports/appsettings.json (1)

1-17: LGTM!

The configuration structure follows standard .NET conventions with appropriate logging levels and a placeholder for the API token.

tests/Mailtrap.IntegrationTests/ContactExports/GetDetails_ShouldCorrectlyHandleUri.json (1)

1-6: LGTM!

The test fixture structure is appropriate for testing URI handling with query parameters.

src/Mailtrap.Abstractions/ContactEvents/Requests/CreateContactEventRequest.cs (1)

55-59: LGTM!

The defensive copy using .Clone() prevents post-constructor mutation of the Params dictionary, which is a solid improvement for immutability.

tests/Mailtrap.IntegrationTests/TestConstants/UrlSegmentsTestConstants.cs (1)

22-22: LGTM!

The ExportsSegment constant mirrors the unit test constants file and follows the established pattern.

tests/Mailtrap.UnitTests/GlobalUsings.cs (1)

28-31: LGTM!

The global using directives for ContactExports namespaces follow the established pattern and make the new types conveniently available throughout the unit tests. Based on learnings.

tests/Mailtrap.IntegrationTests/ContactExports/Create_Success_Request.json (1)

1-17: LGTM!

The test fixture appropriately represents a contact export creation request with multiple filter types (array-valued and string-valued).

src/Mailtrap.Abstractions/GlobalUsings.cs (1)

34-37: LGTM!

The global using directives for ContactExports namespaces follow the established pattern and are properly ordered alphabetically between ContactImports and ContactLists.

src/Mailtrap.Abstractions/ContactLists/Requests/ContactListRequest.cs (1)

6-6: LGTM - Sealing the record.

Sealing the record prevents further inheritance, which is a sound design choice for request DTOs. Note that this is a breaking change if any external code was inheriting from this class, but it aligns with best practices for sealed abstractions.

src/Mailtrap.Abstractions/ContactExports/IContactExportCollectionResource.cs (1)

1-24: LGTM!

The interface follows the established REST resource pattern with clear documentation and a well-defined Create operation. The method signature is consistent with other collection resources in the codebase.

tests/Mailtrap.UnitTests/ContactExports/ContactExportCollectionResourceTests.cs (1)

1-52: LGTM!

Comprehensive constructor tests covering null checks for both dependencies and correct initialization of the ResourceUri property. The test structure follows the established pattern used in other resource tests.

tests/Mailtrap.UnitTests/ContactExports/Model/ContactExportListIdFilterTests.cs (1)

1-130: LGTM!

Comprehensive test coverage for ContactExportListIdFilter including constructor validation, initialization from different collection types, copy behavior with with expressions, and thorough validator testing for various edge cases.

src/Mailtrap.Abstractions/Core/Models/StringEnum.cs (1)

99-118: LGTM!

The IsDefined method provides essential validation capability for StringEnum-based types. The implementation correctly validates singleton identity by checking null/None/Unknown, dictionary presence via ToString(), and reference equality. This supports the validation logic used in ContactExports filters and validators.

tests/Mailtrap.UnitTests/ContactExports/Requests/CreateContactExportRequestTests.cs (1)

1-109: LGTM!

Excellent test coverage for CreateContactExportRequest including constructor validation, comprehensive boundary testing for collection size limits (0, 1, 200, 50000, 50001), null element detection, and a well-designed helper method for generating random filter variants.

src/Mailtrap.Abstractions/ContactExports/Models/ContactExportStatus.cs (1)

1-35: LGTM!

The ContactExportStatus enum follows the StringEnum pattern correctly with three well-defined lifecycle states (Created, Started, Finished). The sealed record design and comprehensive documentation align with best practices.

src/Mailtrap.Abstractions/ContactExports/Models/ContactExportFilterOperator.cs (1)

1-17: LGTM! Clean StringEnum implementation.

The implementation correctly follows the StringEnum pattern and provides the required filter operator. The single "equal" operator aligns with the Contact Exports API requirements.

src/Mailtrap.Abstractions/Contacts/IContactCollectionResource.cs (1)

8-32: LGTM! Consistent API extension.

The new Exports() and Export(long exportId) methods are well-documented and follow the established pattern for nested resources (Imports, Lists, Fields). The exception documentation is appropriate.

src/Mailtrap.Abstractions/ContactExports/Validators/ContactExportFilterValidator.cs (1)

1-51: LGTM! Well-structured validator implementation.

The validator correctly implements:

  • Singleton pattern for reuse (consistent with existing validators)
  • Common validation rules for all filter types
  • Type-specific conditional validation using When() guards
  • Appropriate use of CascadeMode.Stop to short-circuit validation

The null-forgiving operators in the conditional blocks are safe since they're guarded by type checks.

src/Mailtrap/Contacts/ContactCollectionResource.cs (1)

8-21: LGTM! Consistent resource implementation.

The new export methods correctly follow the established pattern for nested resources (Imports, Lists, Fields). The implementation is clean and consistent with the existing codebase.

src/Mailtrap/ContactExports/ContactExportResource.cs (1)

1-13: LGTM! Clean resource implementation.

The implementation correctly follows the RestResource pattern and is consistent with similar resources like ContactImportResource. The use of ConfigureAwait(false) is appropriate for library code.

src/Mailtrap.Abstractions/ContactExports/Models/ContactExport.cs (2)

39-52: Verify DateTimeOffset serialization format.

The CreatedAt and UpdatedAt properties use DateTimeOffset? without a custom JSON converter. The codebase includes a DateTimeToUnixMsJsonConverter for handling Unix milliseconds (seen in src/Mailtrap.Abstractions/Contacts/Converters/DateTimeToUnixMsJsonConverter.cs).

Please confirm that the Contact Exports API returns timestamps in ISO8601 format (which .NET handles by default) rather than Unix milliseconds. If the API returns Unix milliseconds, these properties will need the [JsonConverter(typeof(DateTimeToUnixMsJsonConverter))] attribute.


1-67: Well-structured model with comprehensive documentation.

The ContactExport model is well-designed with:

  • Appropriate property types and nullability
  • Clear JSON serialization attributes with proper naming and ordering
  • Comprehensive XML documentation
  • Sensible default values (Status = Unknown)
src/Mailtrap.Abstractions/ContactExports/Models/ContactExportFilterSubscriptionStatus.cs (1)

1-26: LGTM! Clean StringEnum implementation.

The implementation correctly follows the StringEnum pattern and provides the two expected subscription status values. Documentation is clear and comprehensive.

src/Mailtrap/ContactExports/ContactExportCollectionResource.cs (1)

1-13: LGTM! Clean collection resource implementation.

The implementation correctly follows the RestResource pattern and is consistent with other collection resources in the codebase. The Create method properly forwards to the base implementation with ConfigureAwait(false).

tests/Mailtrap.UnitTests/ContactExports/Model/ContactExportFilterBaseTests.cs (3)

9-42: LGTM! Solid serialization test.

The test properly normalizes both expected and actual JSON using the same serializer options, which prevents false negatives from formatting differences.


44-72: LGTM! Thorough deserialization test.

The test validates polymorphic deserialization correctly, checking both type discrimination and nested values.


74-93: LGTM! Effective round-trip test.

The test ensures data integrity is preserved through serialization/deserialization cycles.

examples/Mailtrap.Example.ContactExports/Program.cs (3)

14-23: LGTM! Standard example setup.

The host builder configuration and dependency injection setup follows the established patterns from other example projects in the codebase.


25-65: LGTM! Clear API usage demonstration.

The example effectively demonstrates the Contact Exports API workflow: creating filters, creating an export, and retrieving export details. The hardcoded values are appropriate for example code.


67-71: Note: Unreachable throw statement.

Line 71's throw is unreachable since Environment.FailFast terminates the process. However, this pattern appears consistently across example projects, likely to satisfy compiler or static analysis requirements.

src/Mailtrap.Abstractions/ContactExports/Models/ContactExportFilterName.cs (1)

1-26: LGTM! Clean string enum implementation.

The implementation follows the established StringEnum pattern and properly references the discriminators from the filter classes.

tests/Mailtrap.UnitTests/ContactExports/ContactExportResourceTests.cs (1)

1-52: LGTM! Standard resource constructor tests.

The tests follow the established pattern for validating resource constructors and URI initialization. The URI construction correctly includes both the exports segment and the export ID.

src/Mailtrap.Abstractions/ContactExports/Requests/CreateContactExportRequest.cs (3)

8-17: LGTM! Proper immutable collection property.

The property correctly uses JsonObjectCreationHandling.Populate to work with the parameterless constructor pattern, and the get-only property with collection initialization provides appropriate immutability.


19-44: LGTM! Proper defensive copying.

The constructor correctly creates a defensive copy of the filters collection to prevent post-construction mutation, and the parameterless constructor supports JSON deserialization.


46-52: LGTM! Standard validation implementation.

The validation method follows the established pattern of delegating to a singleton validator instance and converting the result to the Mailtrap ValidationResult type.

Mailtrap.sln (1)

102-103: LGTM! Correct solution configuration.

The new Mailtrap.Example.ContactExports project is properly configured with Debug/Release builds and correctly nested under the examples folder.

Also applies to: 202-205, 234-234

src/Mailtrap.Abstractions/ContactExports/Validators/CreateContactExportRequestValidator.cs (2)

10-27: Verify the maximum filters limit.

The MaxFiltersPerRequest = 50_000 seems exceptionally high for an export request. Please confirm this limit aligns with:

  • API performance capabilities
  • Backend resource constraints
  • Realistic use cases

Consider whether a lower limit (e.g., 100-1000) would be more appropriate for most practical scenarios.


29-31: LGTM! Proper per-item validation.

The per-item validation correctly delegates to the ContactExportFilterValidator.Instance, following the established pattern of reusing validators for collection elements.

tests/Mailtrap.UnitTests/Contacts/ContactCollectionResourceTests.cs (1)

50-94: LGTM! Consistent test coverage for exports endpoints.

The new test methods follow the established patterns for testing nested resource access, covering both the collection resource and individual resource methods, including proper validation of invalid IDs.

@yanchuk yanchuk requested review from yanchuk and removed request for leonid-shevtsov and mklocek October 28, 2025 12:15
@dr-3lo dr-3lo merged commit 2b862ea into main Oct 28, 2025
3 checks passed
@dr-3lo dr-3lo deleted the feature/155-Contact-Exports branch October 28, 2025 13:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Contacts Export

4 participants