Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Disallow search filter with CreatedAfter greater than CreatedBefore #2019

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

oskogstad
Copy link
Collaborator

@oskogstad oskogstad commented Mar 6, 2025

Description

This PR disallows search filtering with {dateProperty}After > {dateProperty}Before
for all available date filter types,

  • CreatedAt
  • DueAt
  • UpdatedAt
  • VisibleFrom (ServiceOwner only)

Also adding tests to verify these filters work with normal use, and that validation errors are produced when the rule above is broken.

Related Issue(s)

Verification

  • Your code builds clean without any errors or warnings
  • Manual testing done (required)
  • Relevant automated test added (if you find this hard, leave it and we'll help out)

Documentation

  • Documentation is updated (either in docs-directory, Altinnpedia or a separate linked PR in altinn-studio-docs., if applicable)

Copy link
Contributor

coderabbitai bot commented Mar 6, 2025

📝 Walkthrough

Walkthrough

This pull request introduces a new internal static class ValidationErrorStrings containing a constant error message for property comparisons. The validation logic in two SearchDialogQueryValidator classes has been extended to enforce that date-related properties (e.g., CreatedAfter, DueAfter, UpdatedAfter, VisibleAfter) are less than or equal to their corresponding comparison properties. Method signatures in dialog fake data generation have been updated to accept an optional visibility date. Additionally, several integration test classes have been added for filtering dialogs based on created, due, updated, and visible dates, while an obsolete test file has been removed.

Changes

Files Change Summary
src/Digdir.../Features/V1/Common/ValidationErrorStrings.cs Added a new internal static class ValidationErrorStrings with the constant PropertyNameMustBeLessThanOrEqualToComparisonProperty.
src/Digdir.../Features/V1/{EndUser,ServiceOwner}/Dialogs/Queries/Search/SearchDialogQueryValidator.cs Enhanced validation rules in both EndUser and ServiceOwner validators to ensure that "After" date properties are less than or equal to their "Before" counterparts using the new error message constant.
src/Digdir.Tool.../DialogGenerator.cs Updated method signatures for GenerateFakeCreateDialogCommand, GenerateFakeDialog, and GenerateFakeDialogs to include an optional DateTimeOffset? visibleFrom parameter and integrate it into the dialog generation logic.
tests/Digdir.../Common/Common.cs Introduced new testing utilities including DateFilterTestData, common date constants, and extension methods to support dialog command generation based on year-specific dates.
tests/Digdir.../EndUser/Dialogs/Queries/Search/{CreatedAt,DueAt,UpdatedAt}FilterTests.cs Added integration tests to validate filtering logic based on created, due, and updated dates for EndUser dialogs.
tests/Digdir.../ServiceOwner/Dialogs/Queries/Search/{CreatedAt,DueAt,UpdatedAt,VisibleFrom}FilterTests.cs
tests/Digdir.../SearchDialogTests.cs
Added integration tests for filtering on created, due, updated, and visible dates for ServiceOwner dialogs and removed the obsolete SearchDialogTests file.

Possibly related PRs

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@oskogstad oskogstad marked this pull request as ready for review March 6, 2025 19:35
@oskogstad oskogstad requested a review from a team as a code owner March 6, 2025 19:35
Copy link
Contributor

@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 (4)
tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/Search/DueAtFilterTests.cs (1)

57-70: Avoid using hardcoded years in tests

The test uses absolute years (2021, 2022) which could make the test brittle over time since these years are already in the past. Consider using relative years based on the current date, similar to how you're doing in the DueAtTestData method.

- var response = await Application.Send(new SearchDialogQuery
- {
-     DueAfter = CreateDateFromYear(2022),
-     DueBefore = CreateDateFromYear(2021)
- });
+ var currentYear = DateTimeOffset.UtcNow.Year;
+ var response = await Application.Send(new SearchDialogQuery
+ {
+     DueAfter = CreateDateFromYear(currentYear + 1),
+     DueBefore = CreateDateFromYear(currentYear)
+ });
tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/Search/VisibleFromFilterTests.cs (2)

14-27: Avoid using hardcoded years in tests

Similar to the DueAtFilterTests, this test uses absolute years (2021, 2022) which could make the test brittle over time. Consider using relative years based on the current date.

- var response = await Application.Send(new SearchDialogQuery
- {
-     VisibleAfter = CreateDateFromYear(2022),
-     VisibleBefore = CreateDateFromYear(2021)
- });
+ var currentYear = DateTimeOffset.UtcNow.Year;
+ var response = await Application.Send(new SearchDialogQuery
+ {
+     VisibleAfter = CreateDateFromYear(currentYear + 1),
+     VisibleBefore = CreateDateFromYear(currentYear)
+ });

14-16: Inconsistent method naming

The method name has an underscore between "VisibleFrom" and "After" which is inconsistent with the property name in the query (VisibleAfter). This could lead to confusion.

- public async Task Cannot_Filter_On_VisibleFrom_After_With_Value_Greater_Than_VisibleFrom_Before()
+ public async Task Cannot_Filter_On_VisibleAfter_With_Value_Greater_Than_VisibleBefore()
tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Common/Common.cs (1)

30-52: Consider extracting date constraint logic

The method has embedded knowledge about date constraints (e.g., "Requires CreatedAt to be earlier than UpdatedAt"). If these constraints change, you'll need to update the method. Consider extracting these constraints to make them more explicit and maintainable.

internal static async Task<Guid> CreateDialogWithDateInYear(this DialogApplication application, int year, string dateType)
{
    var date = CreateDateFromYear(year);
+   var createDialogCommand = CreateDialogCommandWithDate(date, dateType, year);
-   var createDialogCommand = dateType switch
-   {
-       UpdatedAt => DialogGenerator.GenerateFakeCreateDialogCommand(
-           // Requires CreatedAt to be earlier than UpdatedAt
-           createdAt: CreateDateFromYear(year - 1), updatedAt: date),
-
-       VisibleFrom => DialogGenerator.GenerateFakeCreateDialogCommand(
-           // Requires DueAt to be later than VisibleFrom
-           dueAt: CreateDateFromYear(year + 1), visibleFrom: date),
-
-       DueAt => DialogGenerator.GenerateFakeCreateDialogCommand(dueAt: date),
-       CreatedAt => DialogGenerator.GenerateFakeCreateDialogCommand(createdAt: date),
-       _ => throw new ArgumentException("Invalid date type", nameof(dateType))
-   };

    createDialogCommand.Dto.Party = Party;

    var createCommandResponse = await application.Send(createDialogCommand);
    return createCommandResponse.AsT0.DialogId;
}

+ private static DialogGenerator.CreateDialogCommand CreateDialogCommandWithDate(DateTimeOffset date, string dateType, int year)
+ {
+     return dateType switch
+     {
+         UpdatedAt => DialogGenerator.GenerateFakeCreateDialogCommand(
+             // Requires CreatedAt to be earlier than UpdatedAt
+             createdAt: CreateDateFromYear(year - 1), updatedAt: date),
+
+         VisibleFrom => DialogGenerator.GenerateFakeCreateDialogCommand(
+             // Requires DueAt to be later than VisibleFrom
+             dueAt: CreateDateFromYear(year + 1), visibleFrom: date),
+
+         DueAt => DialogGenerator.GenerateFakeCreateDialogCommand(dueAt: date),
+         CreatedAt => DialogGenerator.GenerateFakeCreateDialogCommand(createdAt: date),
+         _ => throw new ArgumentException("Invalid date type", nameof(dateType))
+     };
+ }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 584b71c and 906a420.

📒 Files selected for processing (13)
  • src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/ValidationErrorStrings.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogQueryValidator.cs (2 hunks)
  • src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogQueryValidator.cs (2 hunks)
  • src/Digdir.Tool.Dialogporten.GenerateFakeData/DialogGenerator.cs (6 hunks)
  • tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Common/Common.cs (1 hunks)
  • tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/EndUser/Dialogs/Queries/Search/CreatedAtFilterTests.cs (1 hunks)
  • tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/EndUser/Dialogs/Queries/Search/DueAtFilterTests.cs (1 hunks)
  • tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/EndUser/Dialogs/Queries/Search/UpdatedAtFilterTests.cs (1 hunks)
  • tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/Search/CreatedAtFilterTests.cs (1 hunks)
  • tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/Search/DueAtFilterTests.cs (1 hunks)
  • tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/Search/UpdatedAtFilterTests.cs (1 hunks)
  • tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/Search/VisibleFromFilterTests.cs (1 hunks)
  • tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/SearchDialogTests.cs (0 hunks)
💤 Files with no reviewable changes (1)
  • tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/SearchDialogTests.cs
✅ Files skipped from review due to trivial changes (1)
  • src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/ValidationErrorStrings.cs
🔇 Additional comments (26)
src/Digdir.Domain.Dialogporten.Application/Features/V1/ServiceOwner/Dialogs/Queries/Search/SearchDialogQueryValidator.cs (3)

10-10: Good addition of the static import.

Using the static import provides cleaner code access to the validation error strings constant.


63-67: Well-implemented validation rule for CreatedAfter/CreatedBefore dates.

The validation correctly ensures that CreatedAfter is less than or equal to CreatedBefore, and only applies when both dates are provided. The error message is appropriately set using the constant from ValidationErrorStrings.


68-81: Consistent implementation of date range validations.

The validation rules for DueAfter, UpdatedAfter, and VisibleAfter follow the same pattern as CreatedAfter, ensuring consistency across all date filters. This is a good practice that will make the code easier to maintain.

src/Digdir.Domain.Dialogporten.Application/Features/V1/EndUser/Dialogs/Queries/Search/SearchDialogQueryValidator.cs (2)

8-8: Good addition of the static import.

Using the static import provides cleaner code access to the validation error strings constant.


57-70: Well-implemented date range validations for EndUser queries.

The validation rules for CreatedAfter, DueAfter, and UpdatedAfter follow the same pattern as in the ServiceOwner validator, maintaining consistency across the application. Note that VisibleAfter validation is not included here as it's only applicable for ServiceOwner, which is correct based on the PR objectives.

tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/Search/UpdatedAtFilterTests.cs (2)

14-51: Well-structured parameterized test for UpdatedAt filtering.

The test covers multiple scenarios with different date combinations using InlineData, which is a good approach for testing various filtering conditions. The test correctly verifies both the count of returned items and their specific IDs.


53-66: Good validation test for invalid date ranges.

The test correctly verifies that providing an UpdatedAfter date that is greater than UpdatedBefore results in a validation error. This ensures the validation rule works as expected.

tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/Search/CreatedAtFilterTests.cs (2)

14-51: Well-structured parameterized test for CreatedAt filtering.

Similar to the UpdatedAt tests, this test effectively covers multiple scenarios using InlineData and verifies both the count and content of the results. The structure is consistent with other filter tests, which is good for maintainability.


53-66: Good validation test for invalid date ranges.

The test properly verifies that providing a CreatedAfter date that is greater than CreatedBefore results in a validation error, ensuring the validation rule works as expected.

tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/EndUser/Dialogs/Queries/Search/CreatedAtFilterTests.cs (1)

1-68: Well-structured test implementation.

The test class is well organized and thoroughly tests the filtering functionality based on created dates. You've implemented both positive tests (using parameterized data) and negative tests to verify validation constraints. The test cases cover essential scenarios: filtering after a date, before a date, and within a date range.

tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/EndUser/Dialogs/Queries/Search/UpdatedAtFilterTests.cs (1)

1-68: LGTM - Clear and consistent test implementation.

This test class follows the same pattern as CreatedAtFilterTests, providing good coverage for filtering based on updated dates. The consistent structure across test files makes the code easier to understand and maintain.

tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/EndUser/Dialogs/Queries/Search/DueAtFilterTests.cs (3)

13-55: Good approach using relative future dates.

Using current year-based offsets for due dates ensures that the tests remain valid regardless of when they're run. This is particularly appropriate for due dates which are typically in the future.


57-71: Validation test for DueAfter > DueBefore looks good.

This test effectively verifies that validation prevents setting DueAfter to a date greater than DueBefore, which aligns well with the PR objective.


73-113: Well-documented test data provider.

The comments explaining the test data generation are helpful for future maintenance. The test data covers the essential scenarios: filtering after a specific year, before a specific year, and within a year range.

src/Digdir.Tool.Dialogporten.GenerateFakeData/DialogGenerator.cs (6)

38-38: Good enhancement to support visibility date testing.

Adding the visibleFrom parameter to the method signature allows for more comprehensive testing of the visibility date filtering functionality.


66-66: Parameter correctly passed through to inner method.

The visibleFrom parameter is correctly passed through to the GenerateFakeDialogs method.


91-91: Consistent parameter addition.

The visibleFrom parameter is consistently added to all relevant method signatures.


117-117: Parameter correctly passed through.

The visibleFrom parameter is correctly passed through from GenerateFakeDialog to GenerateFakeDialogs.


144-144: Parameter added to base method signature.

The visibleFrom parameter has been added to the main generating method.


167-167: Property correctly assigned in the rule.

The visibleFrom parameter is correctly assigned to the VisibleFrom property using the RuleFor method.

tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/Search/DueAtFilterTests.cs (2)

14-55: Test implementation looks good

The parameterized test is well-structured with clear arrange, act, and assert sections. Good use of data-driven testing to cover multiple scenarios.


72-112: Well-structured test data method

The test data implementation with clear comments explaining the year calculations is excellent for maintainability. The approach of using relative years ensures tests remain valid regardless of when they run.

tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/Search/VisibleFromFilterTests.cs (2)

29-70: Well-structured parameterized test

The test is well-implemented with clear arrange, act, and assert sections. Good use of the theory attribute with data provider method.


72-112: Good test data implementation

Clear test data method with good explanatory comments. The approach of using relative years ensures the tests remain valid regardless of when they run.

tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Common/Common.cs (2)

7-13: Well-designed test data class

The DateFilterTestData class is well-structured with clear properties and appropriate use of nullable types for optional values. The required modifier on ExpectedYears ensures this important property is always provided.


15-26: Good use of constants for string values

Using constants for string values like UpdatedAt, VisibleFrom, etc. helps prevent typos and makes refactoring easier.

@oskogstad oskogstad changed the title fix: Disallow filter with CreatedAfter greater than CreatedBefore fix: Disallow search filter with CreatedAfter greater than CreatedBefore Mar 6, 2025
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.

1 participant