Skip to content

Conversation

ilko-dev
Copy link
Contributor

@ilko-dev ilko-dev commented Mar 13, 2025

Summary of issue

Need to create an "Events" entity for the new "Calendar" module

Summary of change

  1. Created new table "Event" in the db. Implemented TPH approach: Two entities Historical events and Custom events are in the one table and inherit base class (Event).
  2. Created DTOs for Events.
  3. Created controller for CRUD endpoints.
  4. Implemented Repository and MediatR patterns.
  5. Implemented validation for Events.
  6. Implemented Unit and Integration tests.

Summary by CodeRabbit

  • New Features
    • Introduced a comprehensive event management system for browsing, creating, updating, and deleting events.
    • Expanded support for both historical and custom events, enhancing the variety of event data available.
    • Added refined input validations and localized, user-friendly error messaging to improve overall experience.
    • Implemented pagination and filtering options for retrieving event lists.
    • Added new data transfer objects (DTOs) for better data handling in event management.
    • Introduced a new controller for managing event-related HTTP requests.

This update delivers an improved, seamless interaction with event data, ensuring smoother and more reliable event management for users.

Copy link

coderabbitai bot commented Mar 13, 2025

Walkthrough

This pull request introduces comprehensive event management features. New DTOs, MediatR commands/handlers, and validators have been added to facilitate event creation, updates, retrieval, and deletion. The changes also include new Entity Framework Core configurations, repository interfaces/implementations, and an EventsController with REST endpoints. Additionally, localized resource entries, unit tests, and integration test clients have been extended to support event-specific operations and error handling.

Changes

Files/Components Change Summary
DTOs & Records
Streetcode/.../DTO/Event/CreateUpdate/CreateUpdateEventDTO.cs
Streetcode/.../DTO/Event/CustomEventDTO.cs
Streetcode/.../DTO/Event/EventDTO.cs
Streetcode/.../DTO/Event/EventShortDTO.cs
Streetcode/.../DTO/Event/GetAllEventsResponseDTO.cs
Streetcode/.../DTO/Event/HistoricalEventDTO.cs
Streetcode/.../DTO/Event/UpdateEventDTO.cs
Added new DTO classes and record types to encapsulate data for event creation, updates, and responses.
Factory & Mapping
Streetcode/.../Factories/Event/EventFactory.cs
Streetcode/.../Mapping/Event/EventProfile.cs
Introduced an event factory for instantiation based on type and an AutoMapper profile to map entities and DTOs.
MediatR Commands & Handlers
Streetcode/.../MediatR/Event/Create/*.cs
Streetcode/.../MediatR/Event/Delete/*.cs
Streetcode/.../MediatR/Event/GetAll/*.cs
Streetcode/.../MediatR/Event/GetAllShort/*.cs
Streetcode/.../MediatR/Event/GetById/*.cs
Streetcode/.../MediatR/Event/Update/*.cs
Added commands, queries, and handlers using MediatR for CRUD operations on events with proper error handling and transactional support.
Resource Files / Localization
Streetcode/.../Resources/SharedResource.*.resx
Added new resource entries for error messages and field names related to events in both English and Ukrainian.
Validators
Streetcode/.../Validators/Event/BaseEventValidator.cs
Streetcode/.../Validators/Event/CreateEventValidator.cs
Streetcode/.../Validators/Event/UpdateEventValidator.cs
Introduced validators to ensure that event DTOs meet business rules and format requirements.
Entity Configurations
Streetcode/.../DAL/Configurations/EventMap.cs
Streetcode/.../DAL/Configurations/EventStreetcodesMap.cs
Streetcode/.../DAL/Configurations/HistoricalEventMap.cs
Added EF Core configuration classes to define entity mappings, relationships, and discriminator settings for event entities.
Entity Classes & Enums
Streetcode/.../DAL/Entities/Event/*.cs
Streetcode/.../DAL/Entities/Streetcode/StreetcodeContent.cs (added property)
Streetcode/.../DAL/Enums/EventType.cs
Streetcode/.../DAL/Enums/EventTypeDiscriminators.cs
Introduced new event classes (including CustomEvent and HistoricalEvent), enriched the StreetcodeContent entity, and defined enums for event categorization.
DbContext Update
Streetcode/.../DAL/Persistence/StreetcodeDbContext.cs
Updated DbContext to include a new DbSet for managing Event entities.
Repositories
Streetcode/.../Repositories/Interfaces/Base/IRepositoryWrapper.cs (updated)
Streetcode/.../Repositories/Interfaces/Event/*.cs
Streetcode/.../Repositories/Realizations/Base/RepositoryWrapper.cs (updated)
Streetcode/.../Repositories/Realizations/Event/*.cs
Added new repository interfaces and their implementations to support event data operations.
Web API & Client
Streetcode/.../WebApi/Controllers/Event/EventsController.cs
Streetcode/.../WebApi/Extensions/SeedingLocalExtension.cs
Streetcode/.../XIntegrationTest/ControllerTests/Event/EventControllerTests.cs
Streetcode/.../XIntegrationTest/ControllerTests/Utils/Client/Event/EventClient.cs
Introduced an EventsController with complete REST endpoints and seeding logic, alongside integration test clients to validate API behavior.
Unit & Integration Tests
Streetcode/.../XUnitTest/Fuilds/Event/EventFactoryTests.cs
Streetcode/.../XUnitTest/MediatRTests/Event/*.cs
Streetcode/.../XUnitTest/Mocks/*.cs
Added extensive unit tests for factories, MediatR handlers, and mock localizers to ensure robustness of event operations and error handling.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Controller as EventsController
    participant Mediator
    participant Handler as CreateEventHandler
    participant Factory as EventFactory
    participant Repo as Repository

    Client->>Controller: POST /api/events\nwith CreateUpdateEventDTO
    Controller->>Mediator: Send(CreateEventCommand)
    Mediator->>Handler: Invoke Handle()
    Handler->>Factory: CreateEvent(eventType)
    Factory-->>Handler: Event instance
    Handler->>Repo: Save event and streetcodes
    Repo-->>Handler: Persisted result
    Handler-->>Mediator: Return Result(event ID)
    Mediator-->>Controller: Return event ID
    Controller-->>Client: HTTP 200 OK\nwith event ID
Loading

Poem

In code we trust, new features align,
Events take shape, both crisp and fine.
Factories and handlers now elegantly play,
Validations guide the data’s way.
Controllers listen to each command with cheer,
Tests and resources make our vision clear.
Cheers to progress – our system shines here!

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 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 plan to trigger planning for file edits and PR creation.
  • @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.

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: 7

🔭 Outside diff range comments (1)
Streetcode/Streetcode.BLL/MediatR/Event/GetAllShort/GetAllEventsShortHandler.cs (1)

1-46: 💡 Verification agent

🧩 Analysis chain

Verify namespace consistency with file location

I notice that the file appears to be in the GetAllShort directory based on the import on line 8, but the namespace is Streetcode.BLL.MediatR.Event.GetAll. This inconsistency might cause confusion when navigating the codebase. Consider ensuring the namespace matches the file's location.


🏁 Script executed:

#!/bin/bash
# Check the actual file location to verify if there's a namespace/directory mismatch
find . -name "GetAllEventsShortHandler.cs" | grep -i streetcode

# Check related query class location
find . -name "*GetAllEventsShort*.cs" | grep -v GetAllEventsShortHandler.cs | grep -i streetcode

Length of output: 324


Namespace Inconsistency: Update Required

The GetAllEventsShortHandler.cs file is located in the Streetcode/Streetcode.BLL/MediatR/Event/GetAllShort/ directory, yet its namespace is declared as Streetcode.BLL.MediatR.Event.GetAll. This mismatch could cause confusion during navigation and maintenance.

Suggestions:

  • Option 1: Update the namespace in the file (and any related files, such as GetAllEventsShortQuery.cs) to Streetcode.BLL.MediatR.Event.GetAllShort so it aligns with the directory structure.
  • Option 2: If the intended design is for the namespace to remain as GetAll, consider moving the file and related classes to a directory that reflects this, for example, Streetcode/Streetcode.BLL/MediatR/Event/GetAll.

Please review the overall organization of the project to decide the best approach. Collaboration on this change will help ensure consistency across the codebase.

🧹 Nitpick comments (55)
Streetcode/Streetcode.BLL/MediatR/Event/GetById/GetEventByIdQuery.cs (1)

1-9: Well-structured query class using MediatR pattern

The implementation of GetEventByIdQuery follows the CQRS pattern appropriately, using MediatR and FluentResults for a clean separation of concerns. This approach will provide a good foundation for implementing event retrieval functionality.

I notice that the handler class mentioned in the summary (GetEventByIdHandler) isn't included in this file. While it's perfectly valid to separate the query and handler into different files, for simpler queries like this, it's sometimes more maintainable to keep related components together.

Consider whether you want to follow a consistent organization pattern across your codebase - either keeping handlers with their queries in the same file, or maintaining separate files for each.

Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToValidateSharedResource.en-US.resx (1)

213-215: Minor formatting issue in the English message.

There should be a space between the single quote and the word "characters" in the English version to ensure proper formatting when displayed to users.

-    <value>The field must be between '{0}' and '{1}'characters.</value>
+    <value>The field must be between '{0}' and '{1}' characters.</value>
Streetcode/Streetcode.BLL/Resources/SharedResource.CannotFindSharedResource.en-US.resx (1)

330-335: Consider pluralization consistency in error message.

The error message entries have been added correctly with proper XML structure and following the existing pattern. However, there's a minor inconsistency: the key "CannotFindAnyEvents" (plural) has a message "Cannot find any event" (singular). While this won't affect functionality, consistent pluralization would improve code clarity.

Consider changing either:

  1. The message to "Cannot find any events" (plural to match the key), or
  2. The key to "CannotFindAnyEvent" (singular to match the message)
Streetcode/Streetcode.BLL/Validators/Event/UpdateEventValidator.cs (1)

1-11: Well-structured validator implementation with clean dependency injection.

The UpdateEventValidator class follows good practices for FluentValidation by using dependency injection to receive the BaseEventValidator and delegating validation of the Event property to it. This promotes code reuse and follows the Single Responsibility Principle.

A few enhancement suggestions:

  1. Consider adding XML documentation to describe the purpose of this validator and its relationship with BaseEventValidator.

  2. Depending on the requirements for updating events, you might want to add specific validation rules for update operations beyond just validating the Event property (e.g., ensuring the ID exists).

  3. If there are different validation requirements between creating and updating events, you could add conditional validation rules here.

 using FluentValidation;
 using Streetcode.BLL.MediatR.Event.Update;
 
 namespace Streetcode.BLL.Validators.Event;
+/// <summary>
+/// Validator for the UpdateEventCommand that handles validation 
+/// of event update operations.
+/// </summary>
 public class UpdateEventValidator : AbstractValidator<UpdateEventCommand>
 {
+    /// <summary>
+    /// Initializes a new instance of the UpdateEventValidator.
+    /// </summary>
+    /// <param name="baseEventValidator">The base validator for common event validation rules.</param>
     public UpdateEventValidator(BaseEventValidator baseEventValidator)
     {
         RuleFor(e => e.Event).SetValidator(baseEventValidator);
+        
+        // Consider additional update-specific validation if needed
+        // Example: RuleFor(e => e.Event.Id).GreaterThan(0).WithMessage("Event ID must be provided for updates");
     }
 }
Streetcode/Streetcode.DAL/Repositories/Realizations/Event/EventRepository.cs (1)

10-19: Consider enhancing the repository with documentation and specialized methods

The repository implementation follows good practices with proper inheritance and dependency injection. However, I recommend a few improvements:

  1. Add XML documentation to describe the purpose and responsibilities of this repository
  2. Consider adding event-specific query methods based on your application requirements (e.g., filtering events by date range, type, or searching by title)
  3. The fully qualified type name DAL.Entities.Event.Event creates verbosity - consider using a namespace alias directive at the top of the file:
    using EventEntity = Streetcode.DAL.Entities.Event.Event;
    // Then use: public class EventRepository : RepositoryBase<EventEntity>, IEventRepository

These enhancements would improve code readability and provide more specialized functionality for event-related operations beyond the basic CRUD methods inherited from the base repository.

Streetcode/Streetcode.BLL/MediatR/Event/GetAllShort/GetAllEventsShortHandler.cs (2)

1-13: Consider removing unused import

The import for Streetcode.BLL.DTO.Partners on line 7 appears to be unused in this handler. Removing unnecessary imports helps keep the code cleaner and avoids potential confusion.

- using Streetcode.BLL.DTO.Partners;

31-43: Consider enhancing error handling and adding pagination

The implementation works well for retrieving all events, but there are a few considerations:

  1. The method handles null results but doesn't address empty collections. While an empty collection is a valid result rather than an error, it might be worth considering whether your application needs to distinguish between "no events exist" and "error retrieving events".

  2. As the application grows, retrieving all events without pagination could lead to performance issues. Consider adding pagination support.

public async Task<Result<IEnumerable<EventShortDTO>>> Handle(GetAllEventsShortQuery request, CancellationToken cancellationToken)
{
-    var events = await _repositoryWrapper.EventRepository.GetAllAsync();
+    var events = await _repositoryWrapper.EventRepository.GetAllAsync(cancellationToken);
+    
+    // If pagination is needed in the future:
+    // var pagedEvents = await _repositoryWrapper.EventRepository.GetPagedAsync(
+    //    request.PageNumber, 
+    //    request.PageSize,
+    //    cancellationToken);

    if (events is null)
    {
        string errorMsg = _stringLocalizeCannotFind["CannotFindAnyEvents"].Value;
        _logger.LogError(request, errorMsg);
        return Result.Fail(new Error(errorMsg));
    }

    return Result.Ok(_mapper.Map<IEnumerable<EventShortDTO>>(events));
}
Streetcode/Streetcode.DAL/Repositories/Realizations/Event/EventStreetcodesRepository.cs (1)

8-14: Consider adding XML documentation for better code maintainability.

While the implementation is straightforward, adding XML documentation to describe the purpose of this repository and how it relates to the Event entity would improve long-term maintainability, especially for new developers who might work on this codebase.

+/// <summary>
+/// Repository for managing associations between events and streetcodes.
+/// Implements the base repository pattern for CRUD operations.
+/// </summary>
 internal class EventStreetcodesRepository : RepositoryBase<EventStreetcodes>, IEventStreetcodesRepository
 {
+    /// <summary>
+    /// Initializes a new instance of the <see cref="EventStreetcodesRepository"/> class.
+    /// </summary>
+    /// <param name="context">Database context for event streetcodes operations.</param>
     public EventStreetcodesRepository(StreetcodeDbContext context)
         : base(context)
     {
     }
 }
Streetcode/Streetcode.DAL/Entities/Event/CustomEvent.cs (2)

10-18: Good implementation of CustomEvent entity

The CustomEvent class properly inherits from the base Event class and includes appropriate MaxLength constraints for its string properties. This implementation aligns with the Table Per Hierarchy (TPH) approach mentioned in the PR objectives.

Consider whether any of these nullable properties should be required for a valid CustomEvent. If so, validation logic should be implemented in the corresponding validators.


1-7: Consider using more specific imports

Several of the imported namespaces don't appear to be used in this class. Consider removing unused imports to improve code clarity.

-using System;
-using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using System.ComponentModel.DataAnnotations;
Streetcode/Streetcode.BLL/DTO/Event/EventDTO.cs (1)

6-14: Consider using enum for EventType

The EventDTO is well-structured with appropriate properties for representing events. However, using a string for EventType might be less type-safe than using an enum.

-public string EventType { get; set; }
+public EventTypeEnum EventType { get; set; }

This would provide compile-time checking and prevent invalid event types from being assigned. If you need string representation for serialization purposes, you can still convert between the enum and string when needed.

Streetcode/Streetcode.DAL/Configurations/HistoricalEventMap.cs (2)

1-9: Consider removing unused using directives

Several of the imported namespaces (System, System.Collections.Generic, System.Linq, System.Text, System.Threading.Tasks) aren't being used in this file.

-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore;
using Streetcode.DAL.Entities.Event;

16-19: Consider using property expressions instead of string literals for foreign keys

Using string literals for foreign key names is prone to errors and makes refactoring more difficult. Consider using a property expression instead:

-            builder.HasOne(e => e.TimelineItem)
-                .WithMany()
-                .HasForeignKey("TimelineItemId")
-                .OnDelete(DeleteBehavior.SetNull);
+            builder.HasOne(e => e.TimelineItem)
+                .WithMany()
+                .HasForeignKey(e => e.TimelineItemId)
+                .OnDelete(DeleteBehavior.SetNull);

Also, if the TimelineItem entity has a corresponding navigation property for HistoricalEvents, consider specifying it in the WithMany() call for better clarity and complete relationship mapping.

Streetcode/Streetcode.BLL/DTO/Event/EventShortDTO.cs (2)

1-6: Consider removing unused namespaces

This code imports several namespaces (System.Collections.Generic, System.Linq, System.Text, System.Threading.Tasks) that aren't being used in this simple DTO. Clean code practices suggest removing unused imports to improve code clarity and reduce unnecessary dependencies.

- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;

9-14: Well-structured DTO with appropriate nullable property

The EventShortDTO class is well-designed with appropriate property types and a correctly marked nullable Title property. Consider adding XML documentation comments to provide more context about the purpose of each property, especially for API documentation purposes.

public class EventShortDTO
{
+    /// <summary>
+    /// Unique identifier for the event
+    /// </summary>
    public int Id { get; set; }
+    /// <summary>
+    /// Date when the event occurred
+    /// </summary>
    public DateTime Date { get; set; }
+    /// <summary>
+    /// Optional title of the event
+    /// </summary>
    public string? Title { get; set; }
}
Streetcode/Streetcode.BLL/MediatR/Event/GetAllShort/GetAllEventsShortQuery.cs (1)

1-8: Clean implementation of MediatR query

This query record follows best practices for the MediatR and CQRS patterns. It's concise, uses modern C# features (record type), and properly implements the IRequest interface with a Result wrapper for the return type.

Consider adding a brief XML documentation comment to describe the query's purpose and expected behavior:

+/// <summary>
+/// Query to retrieve all events in a shortened format.
+/// </summary>
public record GetAllEventsShortQuery : IRequest<Result<IEnumerable<EventShortDTO>>>;
Streetcode/Streetcode.BLL/Validators/Event/BaseEventValidator.cs (1)

23-24: Consider additional date validation

Currently, you're only validating that the Date field is not empty. Depending on your business requirements, you might want to add validation for future/past dates or specific date formats.

        RuleFor(e => e.Date)
            .NotEmpty().WithMessage(localizer["CannotBeEmpty", fieldLocalizer["Date"]]);
+           // .Must(date => date > DateTime.Now).WithMessage(localizer["DateMustBeInFuture"])
+           // Or other date-specific validation as needed
Streetcode/Streetcode.BLL/MediatR/Event/Delete/DeleteEventHandler.cs (1)

39-41: Add explicit exception handling for SaveChangesAsync

The current implementation checks if the result is > 0 but doesn't handle potential exceptions that might be thrown during the save operation.

            _repositoryWrapper.EventRepository.Delete(eventToDelete);
-           var resultIsSuccess = await _repositoryWrapper.SaveChangesAsync() > 0;
+           bool resultIsSuccess;
+           try 
+           {
+               resultIsSuccess = await _repositoryWrapper.SaveChangesAsync() > 0;
+           }
+           catch (Exception ex)
+           {
+               var errorMessage = _stringLocalizerFailedToDelete["FailedToDeleteEvent"].Value;
+               _logger.LogError(request, $"{errorMessage}. Exception: {ex.Message}");
+               return Result.Fail(new Error(errorMessage));
+           }
Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Event/EventClient.cs (1)

1-27: Add UpdateAsync method for complete CRUD operations

The client implements Get, Create, and Delete operations but is missing an Update method. For complete test coverage, consider adding an UpdateAsync method.

        public async Task<RestResponse> DeleteAsync(int id, string authToken = "")
        {
            var dto = new { Id = id };
            return await this.SendCommand($"/Delete/{id}", Method.Delete, dto, authToken);
        }
+
+       public async Task<RestResponse> UpdateAsync(UpdateEventDTO eventDto, string authToken = "")
+           => await this.SendCommand($"/Update", Method.Put, eventDto, authToken);
Streetcode/Streetcode.BLL/DTO/Event/CustomEventDTO.cs (1)

7-14: Consider adding XML documentation comments.

Adding XML documentation comments would improve code readability and provide better IntelliSense support for developers using this DTO.

namespace Streetcode.BLL.DTO.Event
{
+    /// <summary>
+    /// Data Transfer Object for custom events with additional location and organizer information.
+    /// </summary>
    public class CustomEventDTO : EventDTO
    {
+        /// <summary>
+        /// Gets or sets the location where the custom event takes place.
+        /// </summary>
        public string? Location { get; set; }
+        /// <summary>
+        /// Gets or sets the name of the person or organization responsible for the event.
+        /// </summary>
        public string? Organizer { get; set; }
    }
}
Streetcode/Streetcode.BLL/DTO/Event/GetAllEventsResponseDTO.cs (1)

3-7: Add XML documentation comments for better API documentation.

Including XML documentation would improve the usability of this DTO and provide better context for developers.

+/// <summary>
+/// Response DTO for retrieving all events with pagination information.
+/// </summary>
public class GetAllEventsResponseDTO
{
+    /// <summary>
+    /// Gets or sets the total number of events available.
+    /// </summary>
    public int TotalAmount { get; set; }
+    /// <summary>
+    /// Gets or sets the collection of events for the current page.
+    /// </summary>
    public IEnumerable<object> Events { get; set; } = new List<object>();
}
Streetcode/Streetcode.BLL/MediatR/Event/Delete/DeleteEventCommand.cs (1)

1-8: Remove unused namespaces to keep the code clean

There are several unused namespaces imported in this file. Consider removing the ones that aren't being used (System.Collections.Generic, System.Linq, System.Text, etc.) to maintain clean code.

using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
using System.Threading.Tasks;
using FluentResults;
using MediatR;
Streetcode/Streetcode.XUnitTest/Factories/Event/EventFactoryTests.cs (1)

23-23: Fix typo in test method name

There's a typo in the test method name:

-public void CreateEvent_CustomlEventType_ReturnCustomEvent()
+public void CreateEvent_CustomEventType_ReturnCustomEvent()
Streetcode/Streetcode.BLL/MediatR/Event/GetAll/GetAllEventsQuery.cs (1)

8-9: Consider using enum instead of string for EventType

Using a string parameter for EventType could lead to runtime errors if invalid values are provided. Consider using an enum type from Streetcode.DAL.Enums since you're already importing this namespace. This would provide compile-time safety and better IntelliSense support.

- public record GetAllEventsQuery(string? EventType, ushort? page = null, ushort? pageSize = null)
+ public record GetAllEventsQuery(EventType? EventType, ushort? page = null, ushort? pageSize = null)

If you need string values for API compatibility, consider performing the conversion in the handler instead.

Streetcode/Streetcode.WebApi/Extensions/SeedingLocalExtension.cs (1)

3-3: Unused import detected

The Mono.TextTemplating namespace is imported but doesn't appear to be used in this file.

Consider removing this unused import:

-using Mono.TextTemplating;
Streetcode/Streetcode.BLL/Mapping/Event/EventProfile.cs (1)

18-20: Remove redundant ReverseMap call

There's a redundant call to .ReverseMap() on line 19 after an initial ReverseMap.

Apply this fix:

-            CreateMap<CustomEvent, CustomEventDTO>().ReverseMap()
-                .ReverseMap();
+            CreateMap<CustomEvent, CustomEventDTO>().ReverseMap();
Streetcode/Streetcode.XUnitTest/MediatRTests/Event/GetEventByIdTests.cs (3)

39-64: Expand verification within the positive scenario test
While this test confirms basic properties (such as Id and EventType) are mapped correctly, consider verifying additional mapped fields (e.g., descriptions, timestamps, or related references) if available. This ensures deeper coverage and prevents regressions.


66-87: Consider adding more edge case tests
The negative scenario is well covered here. However, you could add a test that ensures correct behavior for an unrecognized event type (e.g., neither "Historical" nor "Custom"), which may trigger the default branch in the handler.


89-95: Refine the naming of the mock setup for clarity
SetupRepositoryMock is descriptive, but if you plan to include more services, consider naming it more generically (e.g., ArrangeRepositoryDependency) to make it clear this is a setup method for all repository interactions. This is a minor detail but can aid readability at scale.

Streetcode/Streetcode.BLL/MediatR/Event/GetById/GetEventByIdHandler.cs (1)

48-61: Good use of switch expressions for event differentiation
Switching on eventEntity.EventType ensures maintainable extension for future event types. Consider referencing a dedicated enum or constants (already in use with EventTypeDiscriminators) if you want to avoid string-based checks.

Streetcode/Streetcode.DAL/Enums/EventTypeDiscriminators.cs (1)

16-24: Suggest verifying future extensibility
The GetEventType method works well now. If you plan to add more event types, consider using an enum-based look-up or dictionary to manage expansions cleanly. This will keep the class maintainable over time.

Streetcode/Streetcode.BLL/MediatR/Event/GetAll/GetAllEventsHandler.cs (3)

35-54: Robust pagination handling
Retrieving paginated data helps scalability. Ensure request.page and request.pageSize are validated or sanitized to avoid unexpected paging results (e.g., negative values).


58-85: Dynamic mapping by event type is a nice touch
Using the pattern-based approach for HistoricalEvent vs. CustomEvent ensures the correct DTO. If more event types are introduced, confirm you have coverage for them. Optionally, consider delegating this mapping logic to your AutoMapper profiles to reduce complexity here.


87-93: Comprehensive response structure
The TotalAmount and Events fields provide essential info. If you need more pagination data returned (e.g., total pages, current page), consider extending the response for better front-end integration.

Streetcode/Streetcode.XUnitTest/MediatRTests/Event/GetAllEventsTests.cs (4)

46-47: Consider parameterizing the test data.

The hardcoded values for page and pageSize (1 and 10) would be better as test parameters, allowing you to test different pagination scenarios with minimal code duplication.


90-101: Consider making repository mock setup more explicit.

The current setup passes null for multiple parameters. For improved test clarity, consider specifying meaningful values for these parameters to more accurately reflect how the repository would be used in production code.

private void SetupRepositoryMock(PaginationResponse<EventEntity>? paginationResponse)
{
    _mockRepository.Setup(r => r.EventRepository.GetAllPaginated(
        It.IsAny<ushort?>(),
        It.IsAny<ushort?>(),
-       null,
-       null,
+       It.IsAny<Expression<Func<EventEntity, bool>>>(),
+       It.IsAny<Func<IQueryable<EventEntity>, IOrderedQueryable<EventEntity>>>(),
        It.IsAny<Func<IQueryable<EventEntity>, IIncludableQueryable<EventEntity, object>>?>(),
-       null,
+       It.IsAny<bool>(),
        It.IsAny<Expression<Func<EventEntity, object>>?>()))
    .Returns(paginationResponse);
}

137-138: Avoid using null-forgiving operator in test code.

The null! pattern is using the null-forgiving operator, which could mask potential null reference issues. Consider a safer approach to handle this case:

else
{
-   return null!;
+   return new EventDTO(); // Return empty object or handle more explicitly
}

142-151: Improve test helper method organization.

The MapStreetcodes method contains business logic that makes the test harder to maintain. Consider:

  1. Simplifying this test-only mapper implementation
  2. Or moving it to a shared test utility class if it's reused across multiple test files
Streetcode/Streetcode.XUnitTest/MediatRTests/Event/DeleteEventTests.cs (1)

107-108: Make repository mock setup more specific.

The current setup uses a generic pattern for GetFirstOrDefaultAsync. Consider making it more specific by verifying the actual query expression:

_mockRepository
-   .Setup(repo => repo.EventRepository.GetFirstOrDefaultAsync(It.IsAny<Expression<Func<EventEntity, bool>>>(), null))
+   .Setup(repo => repo.EventRepository.GetFirstOrDefaultAsync(
+       It.Is<Expression<Func<EventEntity, bool>>>(expr => 
+           // Verify that we're querying for the correct event ID
+           ExpressionMatchesEventId(expr, eventEntity?.Id ?? 0)), 
+       null))
    .ReturnsAsync(eventEntity);

// Add a helper method to verify the expression
private bool ExpressionMatchesEventId(Expression<Func<EventEntity, bool>> expr, int eventId)
{
    // Simple implementation - in real tests you might want a more robust solution
    var eventToTest = new EventEntity { Id = eventId };
    var func = expr.Compile();
    return func(eventToTest);
}
Streetcode/Streetcode.XUnitTest/MediatRTests/Event/CreateEventTests.cs (3)

59-60: Be consistent with verification method call counts.

You're using Times.Once() for the Create method but Times.AtLeastOnce() for SaveChangesAsync. For better test precision, be consistent with your expectations:

_mockRepository.Verify(r => r.EventRepository.Create(It.IsAny<HistoricalEvent>()), Times.Once);
-_mockRepository.Verify(r => r.SaveChangesAsync(), Times.AtLeastOnce);
+_mockRepository.Verify(r => r.SaveChangesAsync(), Times.Once);

103-104: Remove console output from the test.

The Console.WriteLine(result) statement appears to be a debugging artifact and should be removed from the final test code.

Assert.Multiple(() =>
{
    Assert.NotNull(result);
-   Console.WriteLine(result);
    Assert.False(result.IsSuccess);
    Assert.Contains(expectedErrorValue, result.Errors.First().Message);
});

111-112: Mock the transaction instead of using a real TransactionScope.

In unit tests, it's generally better to mock all external dependencies rather than using real implementations:

-_mockRepository.Setup(r => r.BeginTransaction()).Returns(new TransactionScope(TransactionScopeAsyncFlowOption.Enabled));
+var mockTransaction = new Mock<IDbContextTransaction>();
+_mockRepository.Setup(r => r.BeginTransaction()).Returns(mockTransaction.Object);

This would require adding a mock implementation of IDbContextTransaction or whatever transaction interface your repository uses.

Streetcode/Streetcode.XIntegrationTest/ControllerTests/Event/EventControllerTests.cs (3)

39-40: Remove empty line in Assert.Multiple block.

There's an unnecessary empty line in the Assert.Multiple block that should be removed:

Assert.Multiple(() =>
{
-
    Assert.True(response.IsSuccessStatusCode, $"Expected success status code, but got {response.StatusCode}. Response: {response.Content}");
    Assert.NotNull(returnedValue);
});

57-65: Extract duplicated ID parsing logic to a helper method.

The same code for parsing and validating the created event ID appears in two test methods. Consider extracting this to a helper method:

+private int ParseCreatedEventId(string createContent)
+{
+    if (string.IsNullOrEmpty(createContent))
+    {
+        Assert.Fail("Create response content is empty.");
+    }
+
+    if (!int.TryParse(createContent, out int createdEventId))
+    {
+        Assert.Fail($"Failed to parse created event ID from response. Content: {createContent}");
+    }
+
+    return createdEventId;
+}

// Then use it in both test methods:
-var createContent = createResponse.Content;
-if (string.IsNullOrEmpty(createContent))
-{
-    Assert.Fail("Create response content is empty.");
-}
-
-if (!int.TryParse(createContent, out int createdEventId))
-{
-    Assert.Fail($"Failed to parse created event ID from response. Content: {createContent}");
-}
+int createdEventId = ParseCreatedEventId(createResponse.Content);

Also applies to: 117-125


127-130: Move admin token validation earlier in the test.

The admin token null check occurs quite late in the test flow. For better "fail fast" behavior, validate this prerequisite earlier:

[Fact]
public async Task Delete_ReturnsSuccess_WithAdminToken()
{
+    if (_tokenStorage.AdminAccessToken == null)
+    {
+        Assert.Fail("Admin token is null");
+        return;
+    }
+
    var createResponse = await this.Client.CreateAsync(new CreateUpdateEventDTO
    {
        Title = _testEvent.Title,
        EventType = _testEvent.EventType
    }, _tokenStorage.AdminAccessToken);
    
    // Rest of the test...
    
-    if (_tokenStorage.AdminAccessToken == null)
-    {
-        Assert.Fail("Admin token is null");
-    }
    
    var response = await this.Client.DeleteAsync(createdEventId, _tokenStorage.AdminAccessToken);
    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
Streetcode/Streetcode.XUnitTest/MediatRTests/Event/UpdateEventTests.cs (2)

59-63: Use of Assert.Multiple in xUnit tests.

Assert.Multiple is typically not part of the core xUnit framework. Ensure the entire team is aligned on using the related extension library or consider individual assertions if sticking closely to xUnit’s standard practices.


141-152: Consider verifying transaction rollback behavior.

When mocking transaction scopes, it can be beneficial to confirm that an exception triggers a rollback, preserving data integrity. You can include an additional test or assertion to validate that the transaction scope is properly reversed on errors.

Streetcode/Streetcode.BLL/MediatR/Event/Create/CreateEventHandler.cs (2)

43-44: Avoid calling _mapper.Map twice for the same object.

The method invokes _mapper.Map(request.Event, eventEntity) in the main flow and again in SetSpecialEventFields. If the second call isn’t necessary, removing it can reduce redundant operations and improve maintainability.

 // Example removal of redundant mapping in SetSpecialEventFields (lines 75-76)
-private void SetSpecialEventFields(EventEntity eventToCreate, CreateEventCommand request)
-{
-    _mapper.Map(request.Event, eventToCreate); 
-    // ...
+private void SetSpecialEventFields(EventEntity eventToCreate, CreateEventCommand request)
+{
+    // ...

Also applies to: 75-76


73-86: Ensure handling of additional or future event types.

Currently, SetSpecialEventFields checks only for HistoricalEvent or CustomEvent. If other types are planned, consider making this logic more generic or extensible to accommodate future needs.

Streetcode/Streetcode.BLL/MediatR/Event/Update/UpdateEventHandler.cs (2)

64-66: Eliminate redundant _mapper.Map calls.

_mapper.Map(request.Event, eventToUpdate); is invoked in both the primary update logic and UpdateSpecialEventFields, potentially duplicating entity mapping. Consolidate them to simplify the code and avoid accidental overwrites.

Also applies to: 119-120


134-139: Clarify in-memory vs. DB removal in UpdateEventStreetcodes.

Clearing the EventStreetcodes collection (line 134) and later removing them from the database (line 158) can be redundant. Confirm if both are needed or if one approach is sufficient to maintain data consistency and clarity.

Also applies to: 149-159

Streetcode/Streetcode.WebApi/Controllers/Event/EventsController.cs (4)

24-29: Evaluate whether these endpoints can be combined or if separate “short” data is truly necessary.
The GetAllShort endpoint is useful, but there might be potential duplication with the GetAll endpoint. You could consider an optional query parameter in a single GET method that toggles between full results and short results.


38-46: Adopt HTTP 201 Created for new resource creation.
Currently, the Create endpoint returns 200 OK. For REST best practices, returning 201 (Created) and including the new resource’s URI in the Location header is common.

Here’s a possible diff for the attribute if you want to adopt 201 Created:

[HttpPost]
[Authorize(Roles = nameof(UserRole.Admin))]
- [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(int))]
+ [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(int))]

48-56: Consider placing the event ID in the route for consistency with usual REST patterns.
In many REST conventions, an update uses a PUT endpoint such as [HttpPut("{id:int}")], with id passed separately. This helps keep the resource path consistent and unambiguous. Using the body to pass the Id is still valid but might deviate from standard patterns.


58-66: Check if returning the entire deleted event is necessary.
Some APIs simply return a 204 (No Content) in response to a DELETE, or they return minimal information. If returning the entire EventDTO is essential for the UI or logging, that’s fine; otherwise, consider returning a simpler response or 204 to avoid overhead.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4820041 and 20e0fbc.

⛔ Files ignored due to path filters (3)
  • Streetcode/Streetcode.DAL/Persistence/Migrations/20250213203537_AddEventTable.Designer.cs is excluded by !**/Migrations/**, !**/*.Designer.cs
  • Streetcode/Streetcode.DAL/Persistence/Migrations/20250213203537_AddEventTable.cs is excluded by !**/Migrations/**
  • Streetcode/Streetcode.DAL/Persistence/Migrations/StreetcodeDbContextModelSnapshot.cs is excluded by !**/Migrations/**
📒 Files selected for processing (70)
  • Streetcode/Streetcode.BLL/DTO/Event/CreateUpdate/CreateUpdateEventDTO.cs (1 hunks)
  • Streetcode/Streetcode.BLL/DTO/Event/CustomEventDTO.cs (1 hunks)
  • Streetcode/Streetcode.BLL/DTO/Event/EventDTO.cs (1 hunks)
  • Streetcode/Streetcode.BLL/DTO/Event/EventShortDTO.cs (1 hunks)
  • Streetcode/Streetcode.BLL/DTO/Event/GetAllEventsResponseDTO.cs (1 hunks)
  • Streetcode/Streetcode.BLL/DTO/Event/HistoricalEventDTO.cs (1 hunks)
  • Streetcode/Streetcode.BLL/DTO/Event/UpdateEventDTO.cs (1 hunks)
  • Streetcode/Streetcode.BLL/Factories/Event/EventFactory.cs (1 hunks)
  • Streetcode/Streetcode.BLL/Mapping/Event/EventProfile.cs (1 hunks)
  • Streetcode/Streetcode.BLL/MediatR/Event/Create/CreateEventCommand.cs (1 hunks)
  • Streetcode/Streetcode.BLL/MediatR/Event/Create/CreateEventHandler.cs (1 hunks)
  • Streetcode/Streetcode.BLL/MediatR/Event/Delete/DeleteEventCommand.cs (1 hunks)
  • Streetcode/Streetcode.BLL/MediatR/Event/Delete/DeleteEventHandler.cs (1 hunks)
  • Streetcode/Streetcode.BLL/MediatR/Event/GetAll/GetAllEventsHandler.cs (1 hunks)
  • Streetcode/Streetcode.BLL/MediatR/Event/GetAll/GetAllEventsQuery.cs (1 hunks)
  • Streetcode/Streetcode.BLL/MediatR/Event/GetAllShort/GetAllEventsShortHandler.cs (1 hunks)
  • Streetcode/Streetcode.BLL/MediatR/Event/GetAllShort/GetAllEventsShortQuery.cs (1 hunks)
  • Streetcode/Streetcode.BLL/MediatR/Event/GetById/GetEventByIdHandler.cs (1 hunks)
  • Streetcode/Streetcode.BLL/MediatR/Event/GetById/GetEventByIdQuery.cs (1 hunks)
  • Streetcode/Streetcode.BLL/MediatR/Event/Update/UpdateEventCommand.cs (1 hunks)
  • Streetcode/Streetcode.BLL/MediatR/Event/Update/UpdateEventHandler.cs (1 hunks)
  • Streetcode/Streetcode.BLL/Resources/SharedResource.AnErrorOccurredSharedResource.en-US.resx (1 hunks)
  • Streetcode/Streetcode.BLL/Resources/SharedResource.AnErrorOccurredSharedResource.uk-UA.resx (1 hunks)
  • Streetcode/Streetcode.BLL/Resources/SharedResource.CannotFindSharedResource.en-US.resx (1 hunks)
  • Streetcode/Streetcode.BLL/Resources/SharedResource.CannotFindSharedResource.uk-UA.resx (1 hunks)
  • Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToCreateSharedResource.en-US.resx (1 hunks)
  • Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToCreateSharedResource.uk-UA.resx (1 hunks)
  • Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToDeleteSharedResource.en-US.resx (1 hunks)
  • Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToDeleteSharedResource.uk-UA.resx (1 hunks)
  • Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToUpdateSharedResource.en-US.resx (1 hunks)
  • Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToUpdateSharedResource.uk-UA.resx (1 hunks)
  • Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToValidateSharedResource.en-US.resx (1 hunks)
  • Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToValidateSharedResource.uk-UA.resx (1 hunks)
  • Streetcode/Streetcode.BLL/Resources/SharedResource.FieldNamesSharedResource.en-US.resx (1 hunks)
  • Streetcode/Streetcode.BLL/Resources/SharedResource.FieldNamesSharedResource.uk-UA.resx (1 hunks)
  • Streetcode/Streetcode.BLL/Validators/Event/BaseEventValidator.cs (1 hunks)
  • Streetcode/Streetcode.BLL/Validators/Event/CreateEventValidator.cs (1 hunks)
  • Streetcode/Streetcode.BLL/Validators/Event/UpdateEventValidator.cs (1 hunks)
  • Streetcode/Streetcode.DAL/Configurations/EventMap.cs (1 hunks)
  • Streetcode/Streetcode.DAL/Configurations/EventStreetcodesMap.cs (1 hunks)
  • Streetcode/Streetcode.DAL/Configurations/HistoricalEventMap.cs (1 hunks)
  • Streetcode/Streetcode.DAL/Entities/Event/CustomEvent.cs (1 hunks)
  • Streetcode/Streetcode.DAL/Entities/Event/Event.cs (1 hunks)
  • Streetcode/Streetcode.DAL/Entities/Event/EventStreetcodes.cs (1 hunks)
  • Streetcode/Streetcode.DAL/Entities/Event/HistoricalEvent.cs (1 hunks)
  • Streetcode/Streetcode.DAL/Entities/Streetcode/StreetcodeContent.cs (3 hunks)
  • Streetcode/Streetcode.DAL/Enums/EventType.cs (1 hunks)
  • Streetcode/Streetcode.DAL/Enums/EventTypeDiscriminators.cs (1 hunks)
  • Streetcode/Streetcode.DAL/Persistence/StreetcodeDbContext.cs (2 hunks)
  • Streetcode/Streetcode.DAL/Repositories/Interfaces/Base/IRepositoryWrapper.cs (2 hunks)
  • Streetcode/Streetcode.DAL/Repositories/Interfaces/Event/IEventRepository.cs (1 hunks)
  • Streetcode/Streetcode.DAL/Repositories/Interfaces/Event/IEventStreetcodesRepository.cs (1 hunks)
  • Streetcode/Streetcode.DAL/Repositories/Realizations/Base/RepositoryWrapper.cs (4 hunks)
  • Streetcode/Streetcode.DAL/Repositories/Realizations/Event/EventRepository.cs (1 hunks)
  • Streetcode/Streetcode.DAL/Repositories/Realizations/Event/EventStreetcodesRepository.cs (1 hunks)
  • Streetcode/Streetcode.WebApi/Controllers/Event/EventsController.cs (1 hunks)
  • Streetcode/Streetcode.WebApi/Extensions/SeedingLocalExtension.cs (2 hunks)
  • Streetcode/Streetcode.XIntegrationTest/ControllerTests/Event/EventControllerTests.cs (1 hunks)
  • Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Event/EventClient.cs (1 hunks)
  • Streetcode/Streetcode.XUnitTest/Factories/Event/EventFactoryTests.cs (1 hunks)
  • Streetcode/Streetcode.XUnitTest/MediatRTests/Event/CreateEventTests.cs (1 hunks)
  • Streetcode/Streetcode.XUnitTest/MediatRTests/Event/DeleteEventTests.cs (1 hunks)
  • Streetcode/Streetcode.XUnitTest/MediatRTests/Event/GetAllEventsTests.cs (1 hunks)
  • Streetcode/Streetcode.XUnitTest/MediatRTests/Event/GetEventByIdTests.cs (1 hunks)
  • Streetcode/Streetcode.XUnitTest/MediatRTests/Event/UpdateEventTests.cs (1 hunks)
  • Streetcode/Streetcode.XUnitTest/Mocks/MockAnErrorOccurredLocalizer.cs (1 hunks)
  • Streetcode/Streetcode.XUnitTest/Mocks/MockCannotFindLocalizer.cs (2 hunks)
  • Streetcode/Streetcode.XUnitTest/Mocks/MockFailedToCreateLocalizer.cs (1 hunks)
  • Streetcode/Streetcode.XUnitTest/Mocks/MockFailedToDeleteLocalizer.cs (1 hunks)
  • Streetcode/Streetcode.XUnitTest/Mocks/MockFailedToUpdateLocalizer.cs (1 hunks)
🔇 Additional comments (66)
Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToValidateSharedResource.en-US.resx (1)

213-218: Good addition of validation resources.

These new validation messages align well with the PR objectives for implementing Events validation. The messages are clear and provide appropriate guidance to users about length constraints and title formatting requirements.

Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToValidateSharedResource.uk-UA.resx (1)

213-218: Proper localization consistency.

The Ukrainian translations are well-crafted and maintain consistent meaning with the English versions. This ensures a good user experience across both language options.

Streetcode/Streetcode.XUnitTest/Mocks/MockCannotFindLocalizer.cs (1)

21-21: Well-integrated error messages for the new Events functionality.

The new error message keys "CannotFindAnyEvents" and "CannotFindEventWithCorrespondingId" are properly integrated into their respective error groups, maintaining consistency with the existing pattern. This ensures that the mock localizer can handle the new event-related error scenarios in unit tests.

Also applies to: 35-35

Streetcode/Streetcode.BLL/Resources/SharedResource.CannotFindSharedResource.uk-UA.resx (1)

327-332: Well-localized event error messages.

The Ukrainian translations for the event-related error messages are properly structured and follow the established patterns in the resource file. The translated content correctly conveys the meaning of the original English messages.

Streetcode/Streetcode.BLL/MediatR/Event/GetAllShort/GetAllEventsShortHandler.cs (1)

14-29: Code structure and dependency injection look good

The handler is well-structured with proper dependency injection through the constructor. All dependencies are correctly initialized and their purposes are clear. The use of interfaces rather than concrete implementations follows good dependency inversion principles.

Streetcode/Streetcode.DAL/Repositories/Realizations/Event/EventStreetcodesRepository.cs (2)

1-15: Well-structured repository implementation following established patterns.

The repository follows a clean implementation of the repository pattern and properly inherits from the base repository class, which is consistent with the architecture described in the PR objectives. This implementation will seamlessly integrate with the MediatR pattern mentioned in the PR.


8-8:

✅ Verification successful

Ensure IEventStreetcodesRepository is properly defined.

The repository implements IEventStreetcodesRepository, which should define any specific operations needed for EventStreetcodes beyond the standard CRUD operations provided by the base repository. While this implementation is correct, verify that the interface contains all necessary methods for your business requirements.


🏁 Script executed:

#!/bin/bash
# Check the definition of IEventStreetcodesRepository
find . -name "IEventStreetcodesRepository.cs" -type f -exec cat {} \;

Length of output: 318


Interface Verification for IEventStreetcodesRepository

  • Verified via the script output that the interface is defined correctly, inheriting from IRepositoryBase<EventStreetcodes>.
  • Currently, no additional methods are declared, which is acceptable if your business logic relies solely on the generic CRUD operations provided by the base repository.
  • If future requirements call for custom operations specific to EventStreetcodes, consider extending this interface accordingly.
Streetcode/Streetcode.DAL/Repositories/Interfaces/Event/IEventRepository.cs (1)

1-13: Repository interface follows the established pattern

The IEventRepository interface follows the repository pattern structure used throughout the project and extends the generic IRepositoryBase with the Event entity type. This ensures consistency with the rest of the data access layer.

As the project grows, consider whether you'll need to add any custom query methods specific to Event retrieval that go beyond the base repository functionality.

Streetcode/Streetcode.DAL/Enums/EventType.cs (1)

7-14: Clean enum implementation for event categorization

The EventType enum provides a clear categorization mechanism for the two types of events mentioned in the PR (Historical and Custom). This will work well with the Table Per Hierarchy approach you're implementing.

If you anticipate adding more event types in the future, you might want to consider adding XML documentation comments to describe each enum value's purpose and use cases.

Streetcode/Streetcode.DAL/Entities/Event/HistoricalEvent.cs (1)

8-15: Entity inheritance structure is appropriate, but consider nullability design

The HistoricalEvent class properly inherits from the Event base class as part of your TPH implementation. This provides a clean way to handle different event types.

I notice that both TimelineItemId and TimelineItem are nullable. Is this intentional? Consider whether a HistoricalEvent should always be associated with a TimelineItem. If so, these properties should potentially be non-nullable to enforce that relationship at the data model level.

Streetcode/Streetcode.DAL/Repositories/Interfaces/Event/IEventStreetcodesRepository.cs (1)

4-9: Repository interface for junction entity follows established pattern

The IEventStreetcodesRepository interface properly extends the base repository interface for the EventStreetcodes entity, which appears to be a junction entity connecting Events to Streetcodes.

As the implementation progresses, you might need to add specific methods for retrieving events by streetcode or vice versa. Consider whether specialized query methods would be beneficial for common access patterns.

Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToCreateSharedResource.en-US.resx (1)

129-131: Well-structured resource addition

The new error message for event creation failure has been properly added following the consistent pattern of other resource entries. This aligns well with the implementation of the new Events functionality described in the PR objectives.

Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToUpdateSharedResource.uk-UA.resx (1)

129-131: Appropriate localization for event update failure

The Ukrainian translation for the event update failure message has been added correctly, maintaining consistency with other resource entries in the file.

Streetcode/Streetcode.DAL/Entities/Event/EventStreetcodes.cs (1)

4-14: Good implementation of the mapping entity

The EventStreetcodes class correctly defines the relationship between events and streetcodes. The usage of [Required] attributes on ID properties and nullable navigation properties follows good practices for Entity Framework Core.

One suggestion to consider for future refactoring:

  • The composite primary key configuration is likely defined in the corresponding mapping class. Consider using Fluent API exclusively for all configurations to maintain consistency.
Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToCreateSharedResource.uk-UA.resx (1)

159-161: Resource entry properly added

The new localized error message for event creation follows the established pattern in the resource file and maintains consistency with other entity error messages.

Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToDeleteSharedResource.uk-UA.resx (1)

126-128: Resource entry properly added

The error message for event deletion has been correctly added, following the same pattern as other entity error messages in the resource file.

Streetcode/Streetcode.DAL/Configurations/HistoricalEventMap.cs (1)

19-19: Verify that TimelineItemId is nullable

The DeleteBehavior.SetNull implies that the TimelineItemId property in HistoricalEvent is nullable. Ensure that this property is properly defined as nullable in the entity class to avoid runtime exceptions.

Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToDeleteSharedResource.en-US.resx (1)

126-128: Consistent error message formatting

The added error message follows the established pattern and maintains consistency with other error messages in the resource file. The message is clear and concise, which is excellent for user experience.

Streetcode/Streetcode.DAL/Repositories/Interfaces/Base/IRepositoryWrapper.cs (2)

5-5: Appropriate namespace import

The added import statement correctly references the Event namespace that contains the new repository interfaces.


64-65: Well-integrated repository properties

The new event-related repository properties follow the established pattern in the codebase and are properly positioned within the interface. This addition maintains the consistency of the repository wrapper design while extending its functionality to support event management.

Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToUpdateSharedResource.en-US.resx (1)

129-131: Resource addition looks good

The new error message for event updates follows the established naming pattern and message format used throughout the resource file.

Streetcode/Streetcode.DAL/Entities/Streetcode/StreetcodeContent.cs (2)

17-17: Adding Event namespace reference is appropriate

The new using directive correctly imports the Event namespace needed for the relationship.


115-115: Navigation property correctly implements many-to-many relationship

The EventStreetcodes property is properly implemented as a nullable collection with initialization. This establishes the appropriate relationship between StreetcodeContent and Event entities.

Streetcode/Streetcode.BLL/Resources/SharedResource.AnErrorOccurredSharedResource.uk-UA.resx (2)

123-125: Event creation error resource looks good

The Ukrainian localization for event creation errors follows the established pattern and includes the placeholder for detailed error messages.


129-131: Event update error resource looks good

The Ukrainian localization for event update errors follows the established pattern and includes the placeholder for detailed error messages.

Streetcode/Streetcode.DAL/Configurations/EventStreetcodesMap.cs (1)

7-26: Well-structured configuration class

The EventStreetcodesMap follows Entity Framework Core best practices with a properly configured composite key and clearly defined relationships. The cascade delete behavior is appropriate for this join entity.

Streetcode/Streetcode.BLL/Resources/SharedResource.FieldNamesSharedResource.uk-UA.resx (1)

327-335: Appropriate localization additions

The new Ukrainian translations for "Date", "Location", and "Organizer" are properly formatted and maintain consistency with the existing resource entries. These strings will support the UI elements for the new Event functionality.

Streetcode/Streetcode.DAL/Repositories/Realizations/Base/RepositoryWrapper.cs (3)

7-7: Appropriate imports for new event functionality

The added using directives correctly reference the new event-related interfaces and implementations.

Also applies to: 24-24


126-129: Well-structured repository field declarations

The private fields for event repositories follow the established nullable pattern used throughout the class.


644-668: Consistent repository property implementation

The EventRepository and EventStreetcodesRepository properties follow the same lazy initialization pattern used throughout the class, maintaining consistency with the existing architecture.

Streetcode/Streetcode.BLL/Resources/SharedResource.FieldNamesSharedResource.en-US.resx (1)

327-335: Appropriate English localization entries

The English localization entries for "Date", "Location", and "Organizer" are properly formatted and align with the Ukrainian translations. These strings support internationalization for the new Event functionality.

Streetcode/Streetcode.BLL/Validators/Event/BaseEventValidator.cs (1)

8-35: Well-structured validator implementation

The validator follows best practices with FluentValidation:

  • Constants for length constraints
  • Localized error messages
  • Separate validation rules for each property
  • Clear, maintainable structure
Streetcode/Streetcode.BLL/MediatR/Event/Delete/DeleteEventHandler.cs (1)

28-52: Well-implemented command handler with proper error handling

The handler follows the mediator pattern correctly and includes appropriate error handling for event not found and unsuccessful deletion scenarios. Good use of localization for error messages and proper logging.

Streetcode/Streetcode.BLL/DTO/Event/UpdateEventDTO.cs (1)

5-8: Clean and well-designed DTO implementation

The DTO properly extends the base CreateUpdateEventDTO by adding the necessary Id property for update operations. This approach maintains code reuse while adding the specific property needed for updates.

Streetcode/Streetcode.BLL/DTO/Event/CustomEventDTO.cs (1)

9-13: Clean implementation of the CustomEventDTO class.

The class properly inherits from EventDTO and includes nullable string properties for Location and Organizer, which aligns with the requirements for custom event functionality.

Streetcode/Streetcode.XUnitTest/Mocks/MockFailedToUpdateLocalizer.cs (1)

18-18: Well-integrated error message for event updates.

The new error message "FailedToUpdateEvent" follows the established pattern and integrates seamlessly with the existing error messages in the mock localizer.

Streetcode/Streetcode.XUnitTest/Mocks/MockFailedToDeleteLocalizer.cs (1)

20-20: Well-integrated error message for event deletions.

The new error message "FailedToDeleteEvent" aligns with the existing pattern and complements the event management functionality being added to the system.

Streetcode/Streetcode.BLL/DTO/Event/HistoricalEventDTO.cs (1)

1-13: Well-designed DTO class that follows inheritance pattern

The HistoricalEventDTO is properly implemented as a subclass of EventDTO, which aligns with the TPH (Table Per Hierarchy) approach mentioned in the PR objectives. The class includes a specific TimelineItemId property that allows historical events to be associated with timeline items.

This implementation supports the separation of different event types while maintaining a common base structure, which is a good design practice for extensibility.

Streetcode/Streetcode.XUnitTest/Mocks/MockFailedToCreateLocalizer.cs (1)

21-21: Error message addition aligns with new event functionality

The addition of the "FailedToCreateEvent" error message to the mock localizer is consistent with the new event functionality being implemented. This ensures proper error handling and localization for event creation failures in tests.

The message follows the naming pattern of existing entries, which maintains consistency in the codebase.

Streetcode/Streetcode.XUnitTest/Mocks/MockAnErrorOccurredLocalizer.cs (1)

15-16: Consistent error message additions for event operations

The addition of "AnErrorOccurredWhileCreatingEvent" and "AnErrorOccurredWhileUpdatingEvent" error messages properly extends the error handling capabilities for the new event functionality. These messages follow the established naming pattern and provide specific feedback for different event operations.

These additions ensure comprehensive test coverage for error scenarios related to event management.

Streetcode/Streetcode.DAL/Persistence/StreetcodeDbContext.cs (2)

7-7: Appropriate import for new entity namespace

The addition of the Streetcode.DAL.Entities.Event namespace import is necessary to support the new Event entity being introduced. This import follows the existing pattern for entity namespace imports.


78-78: DbSet property added for Events entity

The addition of the Events DbSet property is essential for Entity Framework Core to manage the new Event entities. The property follows the naming conventions used throughout the class (plural form for collections) and is positioned appropriately among the other entity DbSet declarations.

This change enables the data access layer to perform CRUD operations on Event entities, supporting the new functionality described in the PR objectives.

Streetcode/Streetcode.BLL/MediatR/Event/Delete/DeleteEventCommand.cs (1)

9-13: Command definition looks well-structured

Good implementation of the MediatR command pattern. The record syntax is concise and appropriate for this use case, implementing the IRequest interface with FluentResults for proper error handling.

Streetcode/Streetcode.BLL/MediatR/Event/Create/CreateEventCommand.cs (1)

1-9: Well-structured command implementation

The command is correctly implemented using the MediatR pattern with FluentResults for proper error handling. The record syntax provides a clean, concise way to define the command.

Streetcode/Streetcode.BLL/DTO/Event/CreateUpdate/CreateUpdateEventDTO.cs (1)

7-10: Well-defined properties with appropriate nullability

Good job defining the required properties with null forgiving operator and marking optional properties as nullable. This makes the contract clear for consumers of this DTO.

Streetcode/Streetcode.XUnitTest/Factories/Event/EventFactoryTests.cs (2)

9-20: Test follows good Arrange-Act-Assert pattern

The test is well-structured following the standard Arrange-Act-Assert pattern, making it clear and easy to understand.


22-33: Test follows good Arrange-Act-Assert pattern

The test is well-structured following the standard Arrange-Act-Assert pattern, making it clear and easy to understand.

Streetcode/Streetcode.BLL/Validators/Event/CreateEventValidator.cs (1)

6-12: Well-structured validator implementation

The validator implementation follows good practices by:

  • Using dependency injection for the BaseEventValidator
  • Applying composition to reuse validation logic
  • Following the FluentValidation pattern with clear rule definition

This approach promotes code reuse and maintainability.

Streetcode/Streetcode.BLL/MediatR/Event/Update/UpdateEventCommand.cs (1)

7-8: Command structure looks good

The command structure follows the MediatR pattern correctly and returns an appropriate result type. The design indicates that a successful update will return the ID of the updated entity.

Streetcode/Streetcode.DAL/Configurations/EventMap.cs (1)

14-23: Good implementation of TPH pattern for Event entity

The Entity Framework Core configuration correctly sets up the Table Per Hierarchy inheritance pattern for the Event entity. This approach allows storing different event types (HistoricalEvent and CustomEvent) in a single table with a discriminator column, which is an efficient design choice.

Streetcode/Streetcode.BLL/Resources/SharedResource.AnErrorOccurredSharedResource.en-US.resx (2)

123-125: Good addition of localized error message

The new resource entry for event creation errors follows the established pattern for error messages in the application. This will help with consistent error reporting and localization.


129-131: Good addition of localized error message

The new resource entry for event updating errors follows the established pattern for error messages in the application. This will help with consistent error reporting and localization.

Streetcode/Streetcode.WebApi/Extensions/SeedingLocalExtension.cs (1)

1140-1172: Good implementation of Event data seeding

The code properly checks for existing events before adding sample data, which prevents duplicate records during multiple application starts. The samples include both CustomEvent and HistoricalEvent types with various properties, providing good test data for development and testing.

I particularly like how the HistoricalEvent "Підрозділ Протасового" links to a TimelineItem, which shows the relationship between events and timeline items.

Streetcode/Streetcode.BLL/Mapping/Event/EventProfile.cs (1)

23-34: Good implementation of inheritance mapping

The mapping configuration correctly handles inheritance for the UpdateEventDTO to different event types. The specific property mappings for CustomEvent and HistoricalEvent ensure that the appropriate properties are mapped to each derived type.

Streetcode/Streetcode.XUnitTest/MediatRTests/Event/GetEventByIdTests.cs (1)

18-22: Solid use of mock fields for the test class
These mocks clearly separate concerns and help with isolating dependencies, making your tests more robust. Keep it up!

Streetcode/Streetcode.BLL/MediatR/Event/GetById/GetEventByIdHandler.cs (3)

21-31: Thumbs up for clear constructor-based DI
This approach makes dependencies explicit and fosters good testing practices. Keep ensuring that only relevant services are injected for single-responsibility.


33-46: Well-handled not-found logic
Returning a fail result with an informative, localized message is a great pattern for clarity and user feedback. Ensure the resource key remains consistent across different error states.


63-79: Defensive consideration for null references
Using the null check on EventStreetcodes is solid. Continue verifying the entire object graph for potential null references (for instance, StreetcodeContent usage) to minimize runtime surprises in future expansions.

Streetcode/Streetcode.DAL/Enums/EventTypeDiscriminators.cs (1)

11-14: Clear definition of event type properties
These static properties serve as a reliable reference for TPH (Table Per Hierarchy) discrimination. Ensure they remain in sync with the rest of the system to avoid mismatches.

Streetcode/Streetcode.BLL/MediatR/Event/GetAll/GetAllEventsHandler.cs (1)

23-33: Constructor DI pattern is consistent
Your injection of mapper, repository, logger, and localizer keeps the class cohesive. This consistency benefits unit testing and maintainability.

Streetcode/Streetcode.XUnitTest/MediatRTests/Event/DeleteEventTests.cs (1)

35-56: LGTM! Well-structured test for successful event deletion.

The test follows good practices for unit testing:

  • Clear AAA (Arrange-Act-Assert) structure
  • Specific expectations for repository method calls
  • Comprehensive assertions to validate the result
Streetcode/Streetcode.BLL/MediatR/Event/Create/CreateEventHandler.cs (1)

36-71: Overall logic looks consistent.

The transactional flow, error handling, and logging appear correct. This design should work well for event creation.

Streetcode/Streetcode.BLL/MediatR/Event/Update/UpdateEventHandler.cs (2)

59-62: Review EF tracking when changing event type.

Creating a new entity with the same ID and discarding the old reference could cause EF to track multiple objects with the same key. Verify that entity state transitions are handled properly to avoid conflicts or unexpected behavior.


41-93: Good use of transaction handling and error reporting.

The update flow is well-organized: retrieving, mapping, validating, and saving changes with robust error handling. This should help ensure reliable event updates.

Streetcode/Streetcode.WebApi/Controllers/Event/EventsController.cs (2)

17-22: Consider adding explicit handling for empty results or invalid pagination.
The GetAll method allows page and pageSize to be null, but the current code does not explicitly validate them or handle invalid values (e.g., zero). If a query returns no events, does the Mediator return an empty list or a 404? Make sure to confirm or document the behavior for clarity.

Would you like to verify how GetAllEventsQuery handles these scenarios? I can generate a script to inspect the query logic and search for potential edge cases.


31-36: Verify not found behavior for the requested ID.
GetById handles the retrieval of a single event, but the code currently does not advertise any 404 response. Confirm that HandleResult or GetEventByIdQuery properly returns a 404 or a suitable response when the ID is invalid or not found.

Comment on lines +1 to +3
using Streetcode.DAL.Enums;
using Streetcode.BLL.DTO.Streetcode;

Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Check namespace import

The import for Streetcode.DAL.Enums suggests that there might be an enum type that could be used for EventType instead of a string.


🏁 Script executed:

#!/bin/bash
# Check if there's an enum type that could be used for EventType
rg -A 5 "namespace.*Enums" --glob "*.cs"

Length of output: 4886


Action Required: Consider Using the EventType Enum in EventDTO

After confirming the available enum types, we found that there is an EventType enum defined in Streetcode.DAL/Enums/EventType.cs with the values Historical and Custom. This suggests that instead of exposing event types as strings in your DTO, you might benefit from using the type-safe enum.

  • Verify if a property in EventDTO intended for event type is currently a string.
  • If so, consider switching its type to the EventType enum to leverage compile-time checks and reduce potential errors.
  • If you intentionally prefer using a string (e.g., for legacy compatibility or specific serialization concerns), please add a clarifying comment explaining the choice.

Comment on lines 11 to 35
namespace Streetcode.DAL.Entities.Event
{
[Table("event", Schema = "events")]
public class Event
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }

[Required]
[DataType(DataType.Date)]
public DateTime Date { get; set; }

[Required]
[MaxLength(100)]
public string? Title { get; set; }

[MaxLength(600)]
public string? Description { get; set; }

[Required]
public string EventType { get; set; }
public List<EventStreetcodes> EventStreetcodes { get; set; } = new();
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Event entity implementation looks good, but has some inconsistencies with nullable properties

The Event entity is well-structured with appropriate database annotations and relationships. However, there's a contradiction between nullability annotations and validation attributes:

  1. On lines 26 and 29, the Title and Description properties are marked as nullable with string?, but Title also has a [Required] attribute. This creates a mixed message - either the property should be required (and not nullable) or optional.

  2. The EventType property on line 32 is required but doesn't have constraints on valid values. Consider using an enum or adding validation to ensure only valid event types are accepted.

- [Required]
- [MaxLength(100)]
- public string? Title { get; set; }
+ [Required]
+ [MaxLength(100)]
+ public string Title { get; set; }

- [MaxLength(600)]
- public string? Description { get; set; }
+ [MaxLength(600)]
+ public string? Description { get; set; }

RuleFor(e => e.Title)
.NotEmpty().WithMessage(localizer["CannotBeEmpty", fieldLocalizer["Title"]])
.Length(TitleMinLength, TitleMaxLength).WithMessage(localizer["LengthBetween", TitleMinLength, TitleMaxLength])
.Matches(@"^[A-Za-zА-Яа-яІіЇїЄєҐґ0-9{L}\d\s\-'-]+$").WithMessage(localizer["TitleFormat"]);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix regex pattern for title validation

The regex pattern contains an error: {L} is not a valid regex construct. If you intended to match any Unicode letter character, you should use \p{L} instead.

-            .Matches(@"^[A-Za-zА-Яа-яІіЇїЄєҐґ0-9{L}\d\s\-'-]+$").WithMessage(localizer["TitleFormat"]);
+            .Matches(@"^[A-Za-zА-Яа-яІіЇїЄєҐґ0-9\p{L}\d\s\-'-]+$").WithMessage(localizer["TitleFormat"]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.Matches(@"^[A-Za-zА-Яа-яІіЇїЄєҐґ0-9{L}\d\s\-'-]+$").WithMessage(localizer["TitleFormat"]);
.Matches(@"^[A-Za-zА-Яа-яІіЇїЄєҐґ0-9\p{L}\d\s\-'-]+$").WithMessage(localizer["TitleFormat"]);

Comment on lines +21 to +25
public async Task<RestResponse> DeleteAsync(int id, string authToken = "")
{
var dto = new { Id = id };
return await this.SendCommand($"/Delete/{id}", Method.Delete, dto, authToken);
}
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Consider revising the DeleteAsync method implementation

There appears to be redundancy in how the ID is passed. You're including it in both the URL path ($"/Delete/{id}") and in the request body as an anonymous object. Check your API endpoint implementation to ensure this is the expected format.


🏁 Script executed:

#!/bin/bash
# Find the endpoint implementation for Delete in the EventsController
rg -A 10 "Delete.*Event.*" --type cs

Length of output: 14466


Action Required: Eliminate redundant ID passing in DeleteAsync
It appears that the method currently sends the event ID both in the URL (via /Delete/{id}) and in the request body as an anonymous object. The API endpoint—and its corresponding DeleteEventCommand and handler—only expect the ID from the URL. To avoid confusion and potential mismatches with the API contract, please consider one of the following adjustments:

  • Remove the redundant request body:
    Update the method to simply pass the ID in the URL. For example:

    public async Task<RestResponse> DeleteAsync(int id, string authToken = "")
    {
        return await this.SendCommand($"/Delete/{id}", Method.Delete, null, authToken);
    }
  • Alternatively, if the API is intended to accept additional data from the body:
    Confirm the endpoint’s expected payload, and modify the API contract to process both the URL and body values consistently.

Please verify the API’s design requirements and update accordingly.

Comment on lines 3 to 7
public class GetAllEventsResponseDTO
{
public int TotalAmount { get; set; }
public IEnumerable<object> Events { get; set; } = new List<object>();
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Reconsider using generic object type for the Events collection.

Using IEnumerable<object> for the Events property is not type-safe and could lead to runtime errors during serialization/deserialization or when accessing properties. Consider using a specific event type or interface instead.

public class GetAllEventsResponseDTO
{
    public int TotalAmount { get; set; }
-    public IEnumerable<object> Events { get; set; } = new List<object>();
+    public IEnumerable<EventDTO> Events { get; set; } = new List<EventDTO>();
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public class GetAllEventsResponseDTO
{
public int TotalAmount { get; set; }
public IEnumerable<object> Events { get; set; } = new List<object>();
}
public class GetAllEventsResponseDTO
{
public int TotalAmount { get; set; }
public IEnumerable<EventDTO> Events { get; set; } = new List<EventDTO>();
}

Comment on lines 1 to 15
using Streetcode.DAL.Enums;

namespace Streetcode.BLL.DTO.Event.CreateUpdate
{
public class CreateUpdateEventDTO
{
public string Title { get; set; } = null!;
public DateTime Date { get; set; }
public string? Description { get; set; }
public List<int>? StreetcodeIds { get; set; }
public string EventType { get; set; }
public string? Location { get; set; }
public string? Organizer { get; set; }
public int? TimelineItemId { get; set; }
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider using an enum instead of string for EventType

The EventType property is defined as a string, but since it appears to have specific discriminators (as seen in the test file with EventTypeDiscriminators enum), consider using an enum type instead. This would provide type safety and prevent errors from invalid string values.

public string Title { get; set; } = null!;
public DateTime Date { get; set; }
public string? Description { get; set; }
public List<int>? StreetcodeIds { get; set; }
-public string EventType { get; set; }
+public EventTypeDiscriminators EventType { get; set; }
public string? Location { get; set; }
public string? Organizer { get; set; }
public int? TimelineItemId { get; set; }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
using Streetcode.DAL.Enums;
namespace Streetcode.BLL.DTO.Event.CreateUpdate
{
public class CreateUpdateEventDTO
{
public string Title { get; set; } = null!;
public DateTime Date { get; set; }
public string? Description { get; set; }
public List<int>? StreetcodeIds { get; set; }
public string EventType { get; set; }
public string? Location { get; set; }
public string? Organizer { get; set; }
public int? TimelineItemId { get; set; }
}
using Streetcode.DAL.Enums;
namespace Streetcode.BLL.DTO.Event.CreateUpdate
{
public class CreateUpdateEventDTO
{
public string Title { get; set; } = null!;
public DateTime Date { get; set; }
public string? Description { get; set; }
public List<int>? StreetcodeIds { get; set; }
public EventTypeDiscriminators EventType { get; set; }
public string? Location { get; set; }
public string? Organizer { get; set; }
public int? TimelineItemId { get; set; }
}
}

Comment on lines +8 to +19
public static DAL.Entities.Event.Event CreateEvent(string eventType)
{
switch(eventType)
{
case "Custom":
return new CustomEvent();
case "Historical":
return new HistoricalEvent();
default:
throw new ArgumentException($"Unsupported streetcode type: {eventType}", nameof(eventType));
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Recommend using enum for event types instead of string literals

Using string literals for event types is error-prone and doesn't leverage compile-time checking. Consider:

  1. Using an enum from Streetcode.DAL.Enums since you're already importing this namespace
  2. Fixing the error message which incorrectly references "streetcode type" instead of "event type"
  3. Adding a null check for the eventType parameter
- public static DAL.Entities.Event.Event CreateEvent(string eventType)
+ public static DAL.Entities.Event.Event CreateEvent(string eventType)
{
+    if (string.IsNullOrEmpty(eventType))
+    {
+        throw new ArgumentException("Event type cannot be null or empty", nameof(eventType));
+    }
+
    switch(eventType)
    {
        case "Custom":
            return new CustomEvent();
        case "Historical":
            return new HistoricalEvent();
        default:
-            throw new ArgumentException($"Unsupported streetcode type: {eventType}", nameof(eventType));
+            throw new ArgumentException($"Unsupported event type: {eventType}", nameof(eventType));
    }
}

// Even better approach with enum:
+ public static DAL.Entities.Event.Event CreateEvent(EventType eventType)
+ {
+     switch(eventType)
+     {
+         case EventType.Custom:
+             return new CustomEvent();
+         case EventType.Historical:
+             return new HistoricalEvent();
+         default:
+             throw new ArgumentException($"Unsupported event type: {eventType}", nameof(eventType));
+     }
+ }

This would make the code more robust and maintainable.

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: 2

🧹 Nitpick comments (8)
Streetcode/Streetcode.BLL/MediatR/Event/Create/CreateEventHandler.cs (4)

38-39: Consider using explicit braces for the using statement

While this code works perfectly, adding explicit braces for the using statement would enhance readability and help prevent potential future errors if additional code is added later.

- using(var transactionScope = _repositoryWrapper.BeginTransaction())
- {
+ using (var transactionScope = _repositoryWrapper.BeginTransaction())
+ {

Also, consider adding a space after using for consistent code style.


89-102: Consider combining save operations and validating StreetcodeIds

The current implementation performs a separate save operation for the event streetcodes. Consider combining this with the previous save operation for better efficiency. Additionally, there's no validation that the provided streetcode IDs actually exist.

- private async Task SetEventStreetcodes(EventEntity eventEntity, CreateEventCommand request)
+ private async Task SetEventStreetcodes(EventEntity eventEntity, IEnumerable<int> streetcodeIds)
  {
-     if (request.Event.StreetcodeIds == null)
+     if (streetcodeIds == null || !streetcodeIds.Any())
      {
          return;
      }

+     // Optional: Validate that all streetcodeIds exist
+     var existingStreetcodeIds = await _repositoryWrapper.StreetcodeRepository
+         .GetAllAsync(s => streetcodeIds.Contains(s.Id))
+         .Select(s => s.Id)
+         .ToListAsync();
+
+     if (existingStreetcodeIds.Count != streetcodeIds.Count())
+     {
+         var nonExistentIds = streetcodeIds.Except(existingStreetcodeIds);
+         _logger.LogWarning($"Some streetcodes were not found: {string.Join(", ", nonExistentIds)}");
+     }

-     var eventStreetcodes = request.Event.StreetcodeIds
+     var eventStreetcodes = existingStreetcodeIds
                          .Select(id => new EventStreetcodes { EventId = eventEntity.Id, StreetcodeId = id })
                          .ToList();

      await _repositoryWrapper.EventStreetcodesRepository.CreateRangeAsync(eventStreetcodes);
-     await _repositoryWrapper.SaveChangesAsync();
  }

Then update the call in the Handle method:

- await SetEventStreetcodes(eventEntity, request);
+ await SetEventStreetcodes(eventEntity, request.Event.StreetcodeIds);
+ await _repositoryWrapper.SaveChangesAsync();

This changes would:

  1. Make the method more focused by accepting only what it needs
  2. Add validation for streetcode IDs existence
  3. Combine save operations for better efficiency

36-71: Consider implementing optimistic concurrency for event creation

The current implementation doesn't handle potential concurrency issues, which could arise if multiple users attempt to create similar events simultaneously.

Consider implementing optimistic concurrency control either through EF Core's built-in mechanisms or through business-level validation to prevent duplicate events.

// Example validation in the Handle method
var existingEvent = await _repositoryWrapper.EventRepository
    .GetFirstOrDefaultAsync(e => 
        e.Title == request.Event.Title && 
        e.EventType == request.Event.EventType);

if (existingEvent != null)
{
    string errorMsg = _stringLocalizerFailedToCreate["EventAlreadyExists"].Value;
    _logger.LogWarning(request, errorMsg);
    return Result.Fail(new Error(errorMsg));
}

36-71: Enhance error messages with more context for better troubleshooting

While the current error messages use localization (which is excellent), they could be enhanced with more specific context about what failed during event creation.

Consider adding more detailed context to error messages:

- string errorMsg = _stringLocalizerAnErrorOccurred["AnErrorOccurredWhileCreatingEvent", ex.Message].Value;
+ string errorMsg = _stringLocalizerAnErrorOccurred["AnErrorOccurredWhileCreatingEvent", 
+     $"Event type: {request.Event.EventType}, Error: {ex.Message}"].Value;

This additional context would make troubleshooting easier by providing more specific information about what failed.

Streetcode/Streetcode.BLL/MediatR/Event/Update/UpdateEventHandler.cs (4)

41-44: Add concurrency checks for robust transaction handling
The approach of wrapping the update in a transaction is excellent. However, consider handling concurrency issues explicitly (e.g., using row versioning or concurrency tokens) to avoid overwriting changes made concurrently.


64-64: Avoid redundant AutoMapper calls
_mapper.Map(request.Event, eventToUpdate) is called at lines 64 and 120, which could lead to confusion or potential overwriting of data. Consolidating the calls or removing duplicates could simplify logic.

Also applies to: 120-120


100-111: Plan for extending new event types
Currently, only "HistoricalEvent" and "CustomEvent" are handled. Future additions will require updating this switch. Consider using polymorphic resolution or an extensible pattern for new event types.


70-72: Evaluate multiple database saves
The code saves changes twice: once for streetcodes (line 163) and once for event updates (line 71). This pattern can create partial updates if the first save succeeds and the second fails. Consider a single commit for consistency and performance.

Also applies to: 163-164

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 3711993 and df5a4f9.

⛔ Files ignored due to path filters (2)
  • Streetcode/Streetcode.DAL/Persistence/Migrations/20250213203537_AddEventTable.cs is excluded by !**/Migrations/**
  • Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/AddEventTable.sql is excluded by !**/ScriptsMigration/**, !**/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/**
📒 Files selected for processing (4)
  • Streetcode/Streetcode.BLL/DTO/Event/CreateUpdate/CreateUpdateEventDTO.cs (1 hunks)
  • Streetcode/Streetcode.BLL/DTO/Event/CustomEventDTO.cs (1 hunks)
  • Streetcode/Streetcode.BLL/MediatR/Event/Create/CreateEventHandler.cs (1 hunks)
  • Streetcode/Streetcode.BLL/MediatR/Event/Update/UpdateEventHandler.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • Streetcode/Streetcode.BLL/DTO/Event/CustomEventDTO.cs
  • Streetcode/Streetcode.BLL/DTO/Event/CreateUpdate/CreateUpdateEventDTO.cs
🧰 Additional context used
🧬 Code Definitions (1)
Streetcode/Streetcode.BLL/MediatR/Event/Update/UpdateEventHandler.cs (2)
Streetcode/Streetcode.BLL/Factories/Event/EventFactory.cs (2) (2)
  • DAL (8-19)
  • EventFactory (6-20)
Streetcode/Streetcode.DAL/Repositories/Realizations/Event/EventRepository.cs (2) (2)
  • EventRepository (12-18)
  • EventRepository (14-17)
🔇 Additional comments (4)
Streetcode/Streetcode.BLL/MediatR/Event/Create/CreateEventHandler.cs (2)

1-14: The imports and namespace structure look appropriate

The imports cover all necessary dependencies for the functionality being implemented, and the namespace follows the project's convention correctly.


15-34: Good use of dependency injection and immutable fields

The class properly implements the IRequestHandler interface and follows good practices for dependency injection. All injected dependencies are stored in private readonly fields, which helps ensure they're not accidentally modified.

Streetcode/Streetcode.BLL/MediatR/Event/Update/UpdateEventHandler.cs (2)

59-63: Good approach to handle event type changes
The check for changed event type before updating is clear and helps ensure the correct entity subtype is used.


136-141: Confirm intended behavior when StreetcodeIds is null
Clearing EventStreetcodes before early returning might inadvertently remove all associations if it's not the intended outcome for a null or missing StreetcodeIds array.

Do you intend to remove all streetcode links when StreetcodeIds is null? If not, you may want to skip clearing the collection in this scenario.

Comment on lines +42 to +46
var eventEntity = EventFactory.CreateEvent(request.Event.EventType);
_mapper.Map(request.Event, eventEntity);

SetSpecialEventFields(eventEntity, request);

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid duplicate mapping in SetSpecialEventFields

The code maps properties from the request to the entity twice - once here and again in the SetSpecialEventFields method (line 75). This redundancy could lead to inconsistencies if mappings are modified in one place but not the other.

  var eventEntity = EventFactory.CreateEvent(request.Event.EventType);
  _mapper.Map(request.Event, eventEntity);

- SetSpecialEventFields(eventEntity, request);
+ SetSpecialEventFields(eventEntity, request.Event);

Then update the SetSpecialEventFields method signature and implementation to remove the duplicate mapping.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var eventEntity = EventFactory.CreateEvent(request.Event.EventType);
_mapper.Map(request.Event, eventEntity);
SetSpecialEventFields(eventEntity, request);
var eventEntity = EventFactory.CreateEvent(request.Event.EventType);
_mapper.Map(request.Event, eventEntity);
SetSpecialEventFields(eventEntity, request.Event);

Comment on lines +73 to +87
private void SetSpecialEventFields(EventEntity eventToCreate, CreateEventCommand request)
{
_mapper.Map(request.Event, eventToCreate);

if (eventToCreate is HistoricalEvent historicalEvent)
{
historicalEvent.TimelineItemId = request.Event.TimelineItemId;
}
else if (eventToCreate is CustomEvent customEvent)
{
customEvent.DateString = request.Event.DateString;
customEvent.Location = request.Event.Location;
customEvent.Organizer = request.Event.Organizer;
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refactor SetSpecialEventFields to avoid duplicate mapping

This method currently duplicates the mapping that's already done in the Handle method. Consider refactoring to avoid redundant mapping and explicitly focus on setting type-specific fields.

- private void SetSpecialEventFields(EventEntity eventToCreate, CreateEventCommand request)
+ private void SetSpecialEventFields(EventEntity eventToCreate, CreateUpdateEventDTO eventDto)
  {
-     _mapper.Map(request.Event, eventToCreate);
      
      if (eventToCreate is HistoricalEvent historicalEvent)
      {
-         historicalEvent.TimelineItemId = request.Event.TimelineItemId;
+         historicalEvent.TimelineItemId = eventDto.TimelineItemId;
      }
      else if (eventToCreate is CustomEvent customEvent)
      {
-         customEvent.DateString = request.Event.DateString;
-         customEvent.Location = request.Event.Location;
-         customEvent.Organizer = request.Event.Organizer;
+         customEvent.DateString = eventDto.DateString;
+         customEvent.Location = eventDto.Location;
+         customEvent.Organizer = eventDto.Organizer;
      }
  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private void SetSpecialEventFields(EventEntity eventToCreate, CreateEventCommand request)
{
_mapper.Map(request.Event, eventToCreate);
if (eventToCreate is HistoricalEvent historicalEvent)
{
historicalEvent.TimelineItemId = request.Event.TimelineItemId;
}
else if (eventToCreate is CustomEvent customEvent)
{
customEvent.DateString = request.Event.DateString;
customEvent.Location = request.Event.Location;
customEvent.Organizer = request.Event.Organizer;
}
}
private void SetSpecialEventFields(EventEntity eventToCreate, CreateUpdateEventDTO eventDto)
{
if (eventToCreate is HistoricalEvent historicalEvent)
{
historicalEvent.TimelineItemId = eventDto.TimelineItemId;
}
else if (eventToCreate is CustomEvent customEvent)
{
customEvent.DateString = eventDto.DateString;
customEvent.Location = eventDto.Location;
customEvent.Organizer = eventDto.Organizer;
}
}

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: 7

🧹 Nitpick comments (23)
Streetcode/Streetcode.BLL/MediatR/Event/GetAllShort/GetAllEventsShortHandler.cs (2)

14-17: Ensure namespace alignment with file location
The namespace is Streetcode.BLL.MediatR.Event.GetAll, but the file path includes GetAllShort. Consider adjusting the namespace or file path naming to maintain consistency and improve discoverability.


31-33: Consider handling large result sets
This code retrieves all events in one go. If the database grows, this might result in performance issues. Implement pagination or filtering strategies to optimize retrieval of a potentially large dataset.

Streetcode/Streetcode.BLL/Validators/Event/BaseEventValidator.cs (2)

22-23: Consider additional date validation.

The current validation only checks if the date is not empty. Consider adding validation for:

  1. Date format validation
  2. Reasonable date range validation (e.g., not too far in the past or future)
RuleFor(e => e.Date)
    .NotEmpty().WithMessage(localizer["CannotBeEmpty", fieldLocalizer["Date"]])
+   .Must(date => date > DateTime.MinValue && date < DateTime.MaxValue)
+   .WithMessage(localizer["InvalidDateRange"]);

1-35: Consider validation for remaining DTO properties.

The DTO includes additional properties that aren't validated in this class:

  • StreetcodeIds (List of integers)
  • TimelineItemId (Nullable integer)
  • DateString (Nullable string)

If these properties have specific validation requirements, consider adding appropriate rules for them.

Streetcode/Streetcode.BLL/DTO/Event/EventShortDTO.cs (1)

9-15: Consider introducing an enum or validation for EventType.
While the current string approach is flexible, using an enum (or a validated string) can help ensure only supported event types are allowed.

Streetcode/Streetcode.XIntegrationTest/ControllerTests/Event/EventControllerTests.cs (5)

13-30: Potential enhancement for test initialization.
Consider adding a default date to _testEvent if a date is mandatory or relevant to test coverage. Providing a complete set of event properties can help detect issues earlier.


32-44: Enhance verification in GetAll_ReturnsSuccess.
The test checks for a successful response but could include additional assertions. For example, verify that returnedValue.TotalAmount or the contents of returnedValue.Events meet expectations.


46-86: Expand validation in GetById_ReturnsSuccess.
Currently, the test ensures a successful status and matches IDs. You could also verify whether other fields (e.g., Title, EventType) match what was created.


96-104: Consider verifying response details in Create_ReturnsUnauthorized_WithoutToken.
The current check ensures the status is Unauthorized. You might also validate any relevant response body or error message to confirm the response is as expected.


105-135: Confirm completeness of the delete operation in Delete_ReturnsSuccess_WithAdminToken.
After deleting, you could optionally attempt to retrieve the event to ensure it's truly gone, increasing confidence in end-to-end correctness.

Streetcode/Streetcode.WebApi/Controllers/Event/EventsController.cs (4)

17-22: Check default parameter handling in GetAll.
If page or pageSize are null, consider whether you want to apply defaults. Handling them gracefully can prevent unexpected query failures or 500 errors.


24-29: Optionally enhance GetAllShort with filters or pagination.
Filtering or basic pagination might be beneficial if the short list can grow large. This would help clients retrieve only relevant subsets.


38-46: Consider returning 201 for resource creation.
Using HTTP 201 (Created) is a more conventional approach for newly created resources instead of 200 (OK).

-[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(int))]
+[ProducesResponseType(StatusCodes.Status201Created, Type = typeof(int))]

48-56: Ensure consistent status codes for updates.
Returning 200 is valid, but if there's an application convention for updated resources (e.g., 200 vs. 204), maintain consistency across all CRUD endpoints.

Streetcode/Streetcode.XUnitTest/MediatRTests/Event/GetEventByIdTests.cs (3)

39-64: Verify Streetcodes collection mapping

The test verifies basic properties like Id and EventType, but doesn't verify that the Streetcodes collection is properly populated. Consider adding assertions for this important part of the handler's functionality.

 // Assert
 Assert.Multiple(() =>
 {
     Assert.NotNull(result);
     Assert.True(result.IsSuccess);
     Assert.Equal(testEventDto.Id, result.Value.Id);
     Assert.Equal(testEventDto.EventType, result.Value.EventType);
+    Assert.NotNull(result.Value.Streetcodes);
+    Assert.Empty(result.Value.Streetcodes); // or Assert.Equal(expectedCount, result.Value.Streetcodes.Count)
 });

44-45: Initialize EventStreetcodes property

The test creates a HistoricalEvent but doesn't initialize the EventStreetcodes collection. Since the handler accesses this property (as seen in the relevant code snippets), consider initializing it to avoid potential null reference issues in your tests.

-var testEvent = new HistoricalEvent { Id = 1, EventType = "Historical" };
+var testEvent = new HistoricalEvent 
+{ 
+    Id = 1, 
+    EventType = "Historical",
+    EventStreetcodes = new List<EventStreetcodes>() 
+};

66-87: Add verification for logger calls

The test correctly verifies the error result, but doesn't verify that the logger is called with the error message when the event is not found. Consider adding verification for logger interactions.

 // Assert
 Assert.Multiple(() =>
 {
     Assert.NotNull(result);
     Assert.False(result.IsSuccess);
     Assert.Contains(expectedErrorValue, result.Errors.Single().Message);
+    _mockLogger.Verify(logger => logger.LogError(
+        It.IsAny<GetEventByIdQuery>(),
+        It.Is<string>(s => s.Contains(expectedErrorValue))), 
+        Times.Once);
 });
Streetcode/Streetcode.XUnitTest/MediatRTests/Event/UpdateEventTests.cs (3)

47-64: Add mapper verification in successful update test

The test verifies successful update but doesn't check that the mapper is called to update the entity properties. Adding this verification would ensure the mapping logic is tested.

 // Assert
 Assert.Multiple(() =>
 {
     Assert.True(result.IsSuccess);
     Assert.Equal(1, result.Value);
+    _mockMapper.Verify(m => m.Map(It.IsAny<UpdateEventDto>(), It.IsAny<EventEntity>()), Times.Once);
 });

115-139: Verify transaction rollback on exception

When testing exceptions during streetcode updates, verify that the transaction is properly disposed to ensure changes are rolled back.

 // Act
 var result = await _handler.Handle(request, CancellationToken.None);

 // Assert
 Assert.Multiple(() =>
 {
     Assert.False(result.IsSuccess);
     Assert.Contains(expectedErrorValue, result.Errors.Single().Message);
+    _mockRepository.Verify(repo => repo.DisposeTransaction(), Times.Once);
 });

141-152: Consider adding transaction disposal in repository mock setup

The setup for transaction handling doesn't include mocking the disposal of the transaction. Consider adding this to ensure complete transaction handling is tested.

 private void SetupRepositoryMock(EventEntity? eventEntity, bool saveSuccess)
 {
     _mockRepository.Setup(r => r.BeginTransaction()).Returns(new TransactionScope(TransactionScopeAsyncFlowOption.Enabled));
+    _mockRepository.Setup(r => r.DisposeTransaction());

     _mockRepository.Setup(repo => repo.EventRepository.Update(It.IsAny<EventEntity>()));
     // Rest of the method...
Streetcode/Streetcode.XUnitTest/MediatRTests/Event/CreateEventTests.cs (3)

45-46: Remove unused variable

The historicalEvent variable is declared but never used. Consider removing it to improve code clarity.

 // Arrange
 var request = new CreateEventCommand(new CreateUpdateEventDto { EventType = "Historical", TimelineItemId = 1 });
-var historicalEvent = new HistoricalEvent();

71-71: Add descriptive comment for the false parameter

The meaning of false parameter might not be immediately clear. Consider using a named variable or adding a comment.

-        SetupRepositoryMock(false);
+        // Set saveSuccess to false to simulate event creation failure
+        SetupRepositoryMock(saveSuccess: false);

103-104: Remove debug Console.WriteLine statement

Debug statements should be removed before committing code.

 Assert.Multiple(() =>
 {
     Assert.NotNull(result);
-    Console.WriteLine(result);
     Assert.False(result.IsSuccess);
     Assert.Contains(expectedErrorValue, result.Errors.First().Message);
 });
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between df5a4f9 and 5be2827.

📒 Files selected for processing (24)
  • Streetcode/Streetcode.BLL/DTO/Event/CreateUpdate/CreateUpdateEventDTO.cs (1 hunks)
  • Streetcode/Streetcode.BLL/DTO/Event/CustomEventDTO.cs (1 hunks)
  • Streetcode/Streetcode.BLL/DTO/Event/EventDTO.cs (1 hunks)
  • Streetcode/Streetcode.BLL/DTO/Event/EventShortDTO.cs (1 hunks)
  • Streetcode/Streetcode.BLL/DTO/Event/GetAllEventsResponseDTO.cs (1 hunks)
  • Streetcode/Streetcode.BLL/DTO/Event/HistoricalEventDTO.cs (1 hunks)
  • Streetcode/Streetcode.BLL/DTO/Event/UpdateEventDTO.cs (1 hunks)
  • Streetcode/Streetcode.BLL/Mapping/Event/EventProfile.cs (1 hunks)
  • Streetcode/Streetcode.BLL/MediatR/Event/Create/CreateEventCommand.cs (1 hunks)
  • Streetcode/Streetcode.BLL/MediatR/Event/GetAll/GetAllEventsHandler.cs (1 hunks)
  • Streetcode/Streetcode.BLL/MediatR/Event/GetAll/GetAllEventsQuery.cs (1 hunks)
  • Streetcode/Streetcode.BLL/MediatR/Event/GetAllShort/GetAllEventsShortHandler.cs (1 hunks)
  • Streetcode/Streetcode.BLL/MediatR/Event/GetAllShort/GetAllEventsShortQuery.cs (1 hunks)
  • Streetcode/Streetcode.BLL/MediatR/Event/GetById/GetEventByIdHandler.cs (1 hunks)
  • Streetcode/Streetcode.BLL/MediatR/Event/GetById/GetEventByIdQuery.cs (1 hunks)
  • Streetcode/Streetcode.BLL/MediatR/Event/Update/UpdateEventCommand.cs (1 hunks)
  • Streetcode/Streetcode.BLL/Validators/Event/BaseEventValidator.cs (1 hunks)
  • Streetcode/Streetcode.WebApi/Controllers/Event/EventsController.cs (1 hunks)
  • Streetcode/Streetcode.XIntegrationTest/ControllerTests/Event/EventControllerTests.cs (1 hunks)
  • Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Event/EventClient.cs (1 hunks)
  • Streetcode/Streetcode.XUnitTest/MediatRTests/Event/CreateEventTests.cs (1 hunks)
  • Streetcode/Streetcode.XUnitTest/MediatRTests/Event/GetAllEventsTests.cs (1 hunks)
  • Streetcode/Streetcode.XUnitTest/MediatRTests/Event/GetEventByIdTests.cs (1 hunks)
  • Streetcode/Streetcode.XUnitTest/MediatRTests/Event/UpdateEventTests.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (14)
  • Streetcode/Streetcode.BLL/DTO/Event/GetAllEventsResponseDTO.cs
  • Streetcode/Streetcode.BLL/DTO/Event/UpdateEventDTO.cs
  • Streetcode/Streetcode.BLL/DTO/Event/CustomEventDTO.cs
  • Streetcode/Streetcode.BLL/DTO/Event/HistoricalEventDTO.cs
  • Streetcode/Streetcode.BLL/DTO/Event/EventDTO.cs
  • Streetcode/Streetcode.BLL/MediatR/Event/Create/CreateEventCommand.cs
  • Streetcode/Streetcode.BLL/MediatR/Event/GetById/GetEventByIdQuery.cs
  • Streetcode/Streetcode.BLL/DTO/Event/CreateUpdate/CreateUpdateEventDTO.cs
  • Streetcode/Streetcode.BLL/MediatR/Event/GetAllShort/GetAllEventsShortQuery.cs
  • Streetcode/Streetcode.BLL/MediatR/Event/GetAll/GetAllEventsQuery.cs
  • Streetcode/Streetcode.BLL/MediatR/Event/Update/UpdateEventCommand.cs
  • Streetcode/Streetcode.BLL/Mapping/Event/EventProfile.cs
  • Streetcode/Streetcode.BLL/MediatR/Event/GetAll/GetAllEventsHandler.cs
  • Streetcode/Streetcode.XUnitTest/MediatRTests/Event/GetAllEventsTests.cs
🧰 Additional context used
🧬 Code Definitions (6)
Streetcode/Streetcode.BLL/MediatR/Event/GetById/GetEventByIdHandler.cs (7)
Streetcode/Streetcode.BLL/DTO/Event/EventDTO.cs (1)
  • EventDto (6-14)
Streetcode/Streetcode.DAL/Repositories/Interfaces/Base/IRepositoryWrapper.cs (1)
  • Task (68-68)
Streetcode/Streetcode.DAL/Repositories/Realizations/Base/RepositoryWrapper.cs (1)
  • Task (675-678)
Streetcode/Streetcode.DAL/Repositories/Realizations/Event/EventRepository.cs (2)
  • EventRepository (12-18)
  • EventRepository (14-17)
Streetcode/Streetcode.BLL/DTO/Event/HistoricalEventDTO.cs (1)
  • HistoricalEventDto (9-12)
Streetcode/Streetcode.BLL/DTO/Event/CustomEventDTO.cs (1)
  • CustomEventDto (9-14)
Streetcode/Streetcode.XUnitTest/MediatRTests/Event/GetAllEventsTests.cs (2)
  • List (142-151)
  • List (153-190)
Streetcode/Streetcode.BLL/Validators/Event/BaseEventValidator.cs (1)
Streetcode/Streetcode.BLL/DTO/Event/CreateUpdate/CreateUpdateEventDTO.cs (1)
  • CreateUpdateEventDto (5-16)
Streetcode/Streetcode.XIntegrationTest/ControllerTests/Event/EventControllerTests.cs (4)
Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Event/EventClient.cs (6)
  • EventClient (7-26)
  • EventClient (9-12)
  • Task (14-14)
  • Task (16-16)
  • Task (18-19)
  • Task (21-25)
Streetcode/Streetcode.BLL/DTO/Event/EventDTO.cs (1)
  • EventDto (6-14)
Streetcode/Streetcode.BLL/DTO/Event/GetAllEventsResponseDTO.cs (1)
  • GetAllEventsResponseDto (3-7)
Streetcode/Streetcode.BLL/DTO/Event/CreateUpdate/CreateUpdateEventDTO.cs (1)
  • CreateUpdateEventDto (5-16)
Streetcode/Streetcode.XUnitTest/MediatRTests/Event/GetEventByIdTests.cs (2)
Streetcode/Streetcode.BLL/MediatR/Event/GetById/GetEventByIdHandler.cs (3)
  • GetEventByIdHandler (14-81)
  • GetEventByIdHandler (21-31)
  • Task (33-80)
Streetcode/Streetcode.BLL/DTO/Event/HistoricalEventDTO.cs (1)
  • HistoricalEventDto (9-12)
Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Event/EventClient.cs (4)
Streetcode/Streetcode.BLL/MediatR/Event/GetAllShort/GetAllEventsShortHandler.cs (1)
  • Task (31-43)
Streetcode/Streetcode.BLL/MediatR/Event/GetAll/GetAllEventsHandler.cs (1)
  • Task (35-94)
Streetcode/Streetcode.BLL/MediatR/Event/GetById/GetEventByIdHandler.cs (1)
  • Task (33-80)
Streetcode/Streetcode.BLL/DTO/Event/CreateUpdate/CreateUpdateEventDTO.cs (1)
  • CreateUpdateEventDto (5-16)
Streetcode/Streetcode.WebApi/Controllers/Event/EventsController.cs (8)
Streetcode/Streetcode.BLL/DTO/Event/GetAllEventsResponseDTO.cs (1)
  • GetAllEventsResponseDto (3-7)
Streetcode/Streetcode.BLL/MediatR/Event/GetAll/GetAllEventsHandler.cs (1)
  • Task (35-94)
Streetcode/Streetcode.BLL/MediatR/Event/Create/CreateEventHandler.cs (2)
  • Task (36-71)
  • Task (89-102)
Streetcode/Streetcode.BLL/MediatR/Event/Update/UpdateEventHandler.cs (2)
  • Task (41-93)
  • Task (134-164)
Streetcode/Streetcode.BLL/MediatR/Event/Delete/DeleteEventHandler.cs (1)
  • Task (28-52)
Streetcode/Streetcode.BLL/DTO/Event/EventDTO.cs (1)
  • EventDto (6-14)
Streetcode/Streetcode.BLL/DTO/Event/CreateUpdate/CreateUpdateEventDTO.cs (1)
  • CreateUpdateEventDto (5-16)
Streetcode/Streetcode.BLL/DTO/Event/UpdateEventDTO.cs (1)
  • UpdateEventDto (5-8)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Jenkins
🔇 Additional comments (27)
Streetcode/Streetcode.BLL/MediatR/Event/GetAllShort/GetAllEventsShortHandler.cs (2)

35-40: Clarify the null check on repository results
It's unusual for a repository's GetAllAsync() method to return null instead of an empty collection. Confirm if it can actually return null, or consider adjusting the repository so it never returns null. This ensures consistent error handling and reduces confusion.


42-42: Mapping to DTO looks correct
Returning a mapped result is a clean approach that maintains separation of concerns and ensures well-structured data transfer.

Streetcode/Streetcode.BLL/Validators/Event/BaseEventValidator.cs (2)

8-15: Well-structured constants for validation constraints.

The class defines clear, reasonable length constraints for various fields. This approach promotes maintainability by centralizing these values as constants rather than embedding them directly in validation rules.


18-20: Missing regex pattern for title validation.

The title validation should include a regex pattern to validate the format of the input. This was previously mentioned in a review comment and has not been implemented.

RuleFor(e => e.Title)
    .NotEmpty().WithMessage(localizer["CannotBeEmpty", fieldLocalizer["Title"]])
    .Length(TitleMinLength, TitleMaxLength).WithMessage(localizer["LengthBetween", TitleMinLength, TitleMaxLength])
+   .Matches(@"^[A-Za-zА-Яа-яІіЇїЄєҐґ0-9\p{L}\d\s\-'-]+$").WithMessage(localizer["TitleFormat"]);
Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Event/EventClient.cs (7)

1-4: Imports look good.

No issues found with the namespaces or references here.


5-8: Namespace and class declaration are consistent.

The structure aligns well with the folder hierarchy and naming conventions.


9-12: Constructor is clear and straightforward.

Passing secondPartUrl to the base class is a clean approach; no concerns found.


14-15: GetAllAsync method is suitably aligned with the intended endpoint.

No issues with the route or usage of SendQuery.


16-17: GetByIdAsync method is correctly referencing the query path.

Matches the API route conventions for fetching by ID.


18-19: CreateAsync method aligns with the route and uses the correct HTTP verb.

The DTO usage is consistent with the existing create operation pattern.


21-25: Eliminate redundant ID passing in DeleteAsync.

This was flagged before, so marking it as a repeated comment. Currently, the method includes the ID in both the path (/Delete/{id}) and the request body. Remove the redundant body parameter to avoid confusion and ensure consistency with typical REST conventions.

- var dto = new { Id = id };
- return await this.SendCommand($"/Delete/{id}", Method.Delete, dto, authToken);
+ return await this.SendCommand($"/Delete/{id}", Method.Delete, null, authToken);
Streetcode/Streetcode.BLL/DTO/Event/EventShortDTO.cs (1)

1-6: All imports look appropriate.
No issues spotted; the namespaces and using directives are minimal and relevant.

Streetcode/Streetcode.XIntegrationTest/ControllerTests/Event/EventControllerTests.cs (1)

88-95: The Create_ReturnsSuccess_WithAdminToken test is effective.
This straightforward test covers the primary scenario. The coverage looks good; no further issues identified.

Streetcode/Streetcode.WebApi/Controllers/Event/EventsController.cs (3)

1-12: No immediate issues in the controller imports.
All namespaces appear consistent and relevant to the controller logic.


58-66:

❓ Verification inconclusive

Confirm behavior when deleting non-existent resources.
Currently, a missing event likely triggers a failure in the Mediator handler, but consider verifying that the controller translates it to a 404 status.


🏁 Script executed:

#!/bin/bash
# Check if a non-existent ID returns 404 in the DeleteEventCommand handler or is handled differently
rg -A 5 'DeleteEventCommand'

Length of output: 4200


Action Required: Verify HTTP 404 Response for Non-existent Events

The DeleteEventCommand tests correctly capture the error scenario—returning an error (with the key "CannotFindEventWithCorrespondingId") when an event isn’t found. However, it’s not clear from the controller code if the HandleResult method translates this error into a proper 404 HTTP response for the client. Please verify (or add an integration test) that when a DELETE request is made for a non-existent event, the controller responds with a 404 status instead of, for example, a 200 or 500 status.

  • Confirm that HandleResult maps the mediator’s error result to a 404 Not Found.
  • If this mapping is not already implemented, consider updating the logic and adding tests to enforce the correct HTTP response for missing resources.

31-36:

❓ Verification inconclusive

Verify the not-found case in GetById.
Ensure the mediator returns an appropriate error status (like 404) if the event is nonexistent.


🏁 Script executed:

#!/bin/bash
# Check where not-found logic is handled in the GetEventByIdQuery handler or controller pipeline
rg -A 5 'return.*Result\.Fail'

Length of output: 106680


Clarify Not-Found Handling in GetById Endpoint

Please verify that the mediator’s GetEventByIdQuery handler properly checks for a missing event and returns a failure (for example, via Result.Fail) that the controller’s HandleResult method then maps to a 404 response. While the codebase consistently uses Result.Fail in various handlers, the shell output did not reveal evidence for this specific event scenario. It would be helpful to ensure that:

  • The GetEventByIdQuery handler performs a null check and returns a failure result when the event does not exist.
  • The controller’s HandleResult method correctly interprets such a failure as a 404 Not Found response.
  • Appropriate test cases are in place to validate this behavior.
Streetcode/Streetcode.BLL/MediatR/Event/GetById/GetEventByIdHandler.cs (6)

1-5: Imports appear correct and comprehensive.

The imported namespaces correctly reflect the dependencies needed for MediatR, AutoMapper, localization, logging, and repository wrapping. No issues spotted here.


12-31: Constructor injection is clear and follows best practices.

The constructor neatly injects required services (IMapper, IRepositoryWrapper, ILoggerService, IStringLocalizer), promoting testability and maintainability.


33-39: Good repository usage with Include chaining for related data.

Fetching EventStreetcodes and StreetcodeContent via Include is efficient and ensures related data is readily available.


41-46: Effective error handling for missing entities.

Returning a failure result with both localized error messaging and logger integration offers clarity for debugging. This adheres to good exception-handling practices.


63-77: Streetcodes mapping logic is straightforward and efficient.

Your filter and projection of StreetcodeContent to StreetcodeShortDTO is appropriate. The fallback to an empty list prevents null references. Nicely handled.


79-80: Returning a success result is appropriate.

The successful result containing the mapped DTO concludes the handler properly. No issues found.

Streetcode/Streetcode.XUnitTest/MediatRTests/Event/GetEventByIdTests.cs (4)

1-13: Good organization of imports

The imports are well-structured and properly organized, making it clear what dependencies this test class requires.


16-22: Test class setup looks good

The class declaration and field setup follows best practices for unit testing. Fields are clearly named and properly scoped as private.


24-37: Constructor initialization is well-structured

Good job initializing all the required dependencies in the constructor. The handler is properly created with all the necessary mock objects.


89-95: SetupRepositoryMock method is well-implemented

The helper method effectively configures the mock repository for both test methods, reducing code duplication.

Streetcode/Streetcode.XUnitTest/MediatRTests/Event/CreateEventTests.cs (1)

109-125: Well-structured repository mock setup

The helper method effectively handles different test scenarios, including exception cases, with a clean conditional structure.

Comment on lines +16 to +33
public BaseEventValidator(IStringLocalizer<FailedToValidateSharedResource> localizer, IStringLocalizer<FieldNamesSharedResource> fieldLocalizer)
{
RuleFor(e => e.Title)
.NotEmpty().WithMessage(localizer["CannotBeEmpty", fieldLocalizer["Title"]])
.Length(TitleMinLength, TitleMaxLength).WithMessage(localizer["LengthBetween", TitleMinLength, TitleMaxLength]);

RuleFor(e => e.Date)
.NotEmpty().WithMessage(localizer["CannotBeEmpty", fieldLocalizer["Date"]]);

RuleFor(e => e.Description)
.MaximumLength(DescriptionMaxLength).WithMessage(localizer["MaxLength", fieldLocalizer["Description"], DescriptionMaxLength]);

RuleFor(e => e.Location)
.MaximumLength(LocationMaxLength).WithMessage(localizer["MaxLength", fieldLocalizer["Location"], LocationMaxLength]);

RuleFor(e => e.Organizer)
.MaximumLength(OrganizerMaxLength).WithMessage(localizer["MaxLength", fieldLocalizer["Organizer"], OrganizerMaxLength]);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Missing validation for EventType field.

According to the DTO, the EventType is a required field but is not validated in this class. Consider adding validation for this field to ensure it contains valid values.

RuleFor(e => e.Organizer)
    .MaximumLength(OrganizerMaxLength).WithMessage(localizer["MaxLength", fieldLocalizer["Organizer"], OrganizerMaxLength]);
    
+RuleFor(e => e.EventType)
+    .NotEmpty().WithMessage(localizer["CannotBeEmpty", fieldLocalizer["EventType"]])
+    .Must(type => new[] { "Historical", "Custom" }.Contains(type))
+    .WithMessage(localizer["InvalidEventType"]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public BaseEventValidator(IStringLocalizer<FailedToValidateSharedResource> localizer, IStringLocalizer<FieldNamesSharedResource> fieldLocalizer)
{
RuleFor(e => e.Title)
.NotEmpty().WithMessage(localizer["CannotBeEmpty", fieldLocalizer["Title"]])
.Length(TitleMinLength, TitleMaxLength).WithMessage(localizer["LengthBetween", TitleMinLength, TitleMaxLength]);
RuleFor(e => e.Date)
.NotEmpty().WithMessage(localizer["CannotBeEmpty", fieldLocalizer["Date"]]);
RuleFor(e => e.Description)
.MaximumLength(DescriptionMaxLength).WithMessage(localizer["MaxLength", fieldLocalizer["Description"], DescriptionMaxLength]);
RuleFor(e => e.Location)
.MaximumLength(LocationMaxLength).WithMessage(localizer["MaxLength", fieldLocalizer["Location"], LocationMaxLength]);
RuleFor(e => e.Organizer)
.MaximumLength(OrganizerMaxLength).WithMessage(localizer["MaxLength", fieldLocalizer["Organizer"], OrganizerMaxLength]);
}
public BaseEventValidator(IStringLocalizer<FailedToValidateSharedResource> localizer, IStringLocalizer<FieldNamesSharedResource> fieldLocalizer)
{
RuleFor(e => e.Title)
.NotEmpty().WithMessage(localizer["CannotBeEmpty", fieldLocalizer["Title"]])
.Length(TitleMinLength, TitleMaxLength).WithMessage(localizer["LengthBetween", TitleMinLength, TitleMaxLength]);
RuleFor(e => e.Date)
.NotEmpty().WithMessage(localizer["CannotBeEmpty", fieldLocalizer["Date"]]);
RuleFor(e => e.Description)
.MaximumLength(DescriptionMaxLength).WithMessage(localizer["MaxLength", fieldLocalizer["Description"], DescriptionMaxLength]);
RuleFor(e => e.Location)
.MaximumLength(LocationMaxLength).WithMessage(localizer["MaxLength", fieldLocalizer["Location"], LocationMaxLength]);
RuleFor(e => e.Organizer)
.MaximumLength(OrganizerMaxLength).WithMessage(localizer["MaxLength", fieldLocalizer["Organizer"], OrganizerMaxLength]);
RuleFor(e => e.EventType)
.NotEmpty().WithMessage(localizer["CannotBeEmpty", fieldLocalizer["EventType"]])
.Must(type => new[] { "Historical", "Custom" }.Contains(type))
.WithMessage(localizer["InvalidEventType"]);
}

Comment on lines +50 to +61
switch (eventEntity.EventType)
{
case "Historical":
mappedEvent = _mapper.Map<HistoricalEventDto>(eventEntity);
break;
case "Custom":
mappedEvent = _mapper.Map<CustomEventDto>(eventEntity);
break;
default:
mappedEvent = _mapper.Map<EventDto>(eventEntity);
break;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Potential event-type mismatch.

The code checks for "Historical" and "Custom", but the test data and other references may use "HistoricalEvent" and "CustomEvent". This mismatch could prevent correct DTO mapping.

Here is a suggested fix to align the switch cases with the event types:

-case "Historical":
+case "HistoricalEvent":
    mappedEvent = _mapper.Map<HistoricalEventDto>(eventEntity);
    break;
-case "Custom":
+case "CustomEvent":
    mappedEvent = _mapper.Map<CustomEventDto>(eventEntity);
    break;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
switch (eventEntity.EventType)
{
case "Historical":
mappedEvent = _mapper.Map<HistoricalEventDto>(eventEntity);
break;
case "Custom":
mappedEvent = _mapper.Map<CustomEventDto>(eventEntity);
break;
default:
mappedEvent = _mapper.Map<EventDto>(eventEntity);
break;
}
switch (eventEntity.EventType)
{
case "HistoricalEvent":
mappedEvent = _mapper.Map<HistoricalEventDto>(eventEntity);
break;
case "CustomEvent":
mappedEvent = _mapper.Map<CustomEventDto>(eventEntity);
break;
default:
mappedEvent = _mapper.Map<EventDto>(eventEntity);
break;
}

Comment on lines +42 to +44
_mockFailedToUpdateLocalizer,
_mockAnErrorOccurredLocalizer,
_mockCanFindLocalizer);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Handler initialization needs to be updated

Update the handler initialization to use the corrected field name.

        _handler = new UpdateEventHandler(
            _mockMapper.Object,
            _mockRepository.Object,
            _mockLogger.Object,
            _mockFailedToUpdateLocalizer,
            _mockAnErrorOccurredLocalizer,
-            _mockCanFindLocalizer);
+            _mockCannotFindLocalizer);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
_mockFailedToUpdateLocalizer,
_mockAnErrorOccurredLocalizer,
_mockCanFindLocalizer);
_mockFailedToUpdateLocalizer,
_mockAnErrorOccurredLocalizer,
_mockCannotFindLocalizer);

Comment on lines +34 to +36
_mockCanFindLocalizer = new MockCannotFindLocalizer();
_mockFailedToUpdateLocalizer = new MockFailedToUpdateLocalizer();
_mockAnErrorOccurredLocalizer = new MockAnErrorOccurredLocalizer();
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix inconsistent variable naming in constructor

The constructor initializations don't match the field declarations.

-        _mockCanFindLocalizer = new MockCannotFindLocalizer();
+        _mockCannotFindLocalizer = new MockCannotFindLocalizer();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
_mockCanFindLocalizer = new MockCannotFindLocalizer();
_mockFailedToUpdateLocalizer = new MockFailedToUpdateLocalizer();
_mockAnErrorOccurredLocalizer = new MockAnErrorOccurredLocalizer();
_mockCannotFindLocalizer = new MockCannotFindLocalizer();
_mockFailedToUpdateLocalizer = new MockFailedToUpdateLocalizer();
_mockAnErrorOccurredLocalizer = new MockAnErrorOccurredLocalizer();

Comment on lines +73 to +74
string expectedErrorValue = _mockCanFindLocalizer[expectedErrorKey, eventId];

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Variable name mismatch with field name

The variable references the incorrectly named field.

-        string expectedErrorValue = _mockCanFindLocalizer[expectedErrorKey, eventId];
+        string expectedErrorValue = _mockCannotFindLocalizer[expectedErrorKey, eventId];
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
string expectedErrorValue = _mockCanFindLocalizer[expectedErrorKey, eventId];
string expectedErrorValue = _mockCannotFindLocalizer[expectedErrorKey, eventId];

Comment on lines +18 to +26
public class UpdateEventTests
{
private readonly Mock<IMapper> _mockMapper;
private readonly Mock<IRepositoryWrapper> _mockRepository;
private readonly Mock<ILoggerService> _mockLogger;
private readonly MockCannotFindLocalizer _mockCanFindLocalizer;
private readonly MockFailedToUpdateLocalizer _mockFailedToUpdateLocalizer;
private readonly MockAnErrorOccurredLocalizer _mockAnErrorOccurredLocalizer;
private readonly UpdateEventHandler _handler;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix naming inconsistency in mock localizer field

There's a naming inconsistency between the field declaration and its usage in the code.

-    private readonly MockCannotFindLocalizer _mockCanFindLocalizer;
+    private readonly MockCannotFindLocalizer _mockCannotFindLocalizer;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public class UpdateEventTests
{
private readonly Mock<IMapper> _mockMapper;
private readonly Mock<IRepositoryWrapper> _mockRepository;
private readonly Mock<ILoggerService> _mockLogger;
private readonly MockCannotFindLocalizer _mockCanFindLocalizer;
private readonly MockFailedToUpdateLocalizer _mockFailedToUpdateLocalizer;
private readonly MockAnErrorOccurredLocalizer _mockAnErrorOccurredLocalizer;
private readonly UpdateEventHandler _handler;
public class UpdateEventTests
{
private readonly Mock<IMapper> _mockMapper;
private readonly Mock<IRepositoryWrapper> _mockRepository;
private readonly Mock<ILoggerService> _mockLogger;
private readonly MockCannotFindLocalizer _mockCannotFindLocalizer;
private readonly MockFailedToUpdateLocalizer _mockFailedToUpdateLocalizer;
private readonly MockAnErrorOccurredLocalizer _mockAnErrorOccurredLocalizer;
private readonly UpdateEventHandler _handler;

Comment on lines +48 to +49
SetupRepositoryMock(saveSuccess: true);

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add mapper configuration for entity creation

The test doesn't configure the mock mapper to map the DTO to an entity. This is important to test that the handler correctly maps the input data.

 SetupRepositoryMock(saveSuccess: true);

+_mockMapper.Setup(m => m.Map<HistoricalEvent>(It.IsAny<CreateUpdateEventDto>()))
+    .Returns(new HistoricalEvent { Id = 1, EventType = "Historical", TimelineItemId = 1 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
SetupRepositoryMock(saveSuccess: true);
SetupRepositoryMock(saveSuccess: true);
_mockMapper.Setup(m => m.Map<HistoricalEvent>(It.IsAny<CreateUpdateEventDto>()))
.Returns(new HistoricalEvent { Id = 1, EventType = "Historical", TimelineItemId = 1 });

Comment on lines +35 to +94
public Task<Result<GetAllEventsResponseDto>> Handle(GetAllEventsQuery request, CancellationToken cancellationToken)
{
PaginationResponse<DAL.Entities.Event.Event> paginationResponse = _repositoryWrapper
.EventRepository
.GetAllPaginated(
request.page,
request.pageSize,
predicate: !string.IsNullOrEmpty(request.EventType)
? e => e.EventType == request.EventType
: null,
include: query => query
.Include(e => e.EventStreetcodes !)
.ThenInclude(es => es.StreetcodeContent !));

if (paginationResponse is null)
{
string errorMsg = _stringLocalizeCannotFind["CannotFindAnyEvents"].Value;
_logger.LogError(request, errorMsg);
return Task.FromResult(Result.Fail<GetAllEventsResponseDto>(new Error(errorMsg)));
}

IEnumerable<DAL.Entities.Event.Event> filteredEvents = paginationResponse.Entities;

IEnumerable<object> mappedEvents = filteredEvents
.Select(e =>
{
var eventDto = e switch
{
HistoricalEvent historicalEvent => _mapper.Map<HistoricalEventDto>(historicalEvent),
CustomEvent customEvent => _mapper.Map<CustomEventDto>(customEvent),
_ => _mapper.Map<EventDto>(e)
};

if(e.EventStreetcodes != null)
{
eventDto.Streetcodes = e.EventStreetcodes
.Where(es => es.StreetcodeContent != null)
.Select(es => new StreetcodeShortDTO
{
Id = es.StreetcodeContent.Id,
Title = es.StreetcodeContent.Title
})
.ToList();
}
else
{
eventDto.Streetcodes = new List<StreetcodeShortDTO>();
}

return eventDto;
});

GetAllEventsResponseDto getAllEventsResponseDTO = new GetAllEventsResponseDto()
{
TotalAmount = paginationResponse.TotalItems,
Events = mappedEvents,
};

return Task.FromResult(Result.Ok(getAllEventsResponseDTO));
}
Copy link
Contributor

@IceStorman IceStorman Apr 17, 2025

Choose a reason for hiding this comment

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

I think it would be better to divide this Handle method into smaller ones, because now it violates SRP

Copy link
Contributor

Choose a reason for hiding this comment

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

Same here, SRP

Comment on lines +3 to +5
using System.Linq;
using System.Text;
using System.Threading.Tasks;
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove all unused namespaces

Copy link
Contributor

Choose a reason for hiding this comment

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

the same remark for the code across whole file

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.

4 participants