Skip to content

Conversation

@maximgorbatyuk
Copy link
Member

@maximgorbatyuk maximgorbatyuk commented May 11, 2025

Summary by CodeRabbit

  • New Features

    • Added an endpoint for updating existing company information, accessible to admin users.
    • Introduced support for updating company details such as name, description, logo, and links.
  • Improvements

    • Streamlined company rating recalculation for more consistent and accurate ratings.
    • Enhanced error logging to ignore specific validation and not found exceptions.
  • Refactor

    • Unified request types for creating and updating companies.
    • Improved internal structure for handling company update logic.
  • Other

    • Minor code style and structure updates for maintainability.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 11, 2025

Walkthrough

The changes introduce update functionality for company entities, including new API endpoints and command/handler classes. The company entity logic is refactored to centralize rating recalculation and add an update method. Supporting request and command types are renamed or adapted. Logging middleware and exception handling receive minor improvements, and some types are converted to records for value-based semantics.

Changes

File(s) Change Summary
src/Domain/Entities/Companies/Company.cs Refactored rating recalculation into a new RecalculateRating method; added an Update method for company details; updated internal logic of review methods to use new rating recalculation.
src/Domain/Validation/Exceptions/EntityInvalidException.cs Reformatted code and replaced Any() with Count == 0/Count != 0 in error checks; no behavioral changes.
src/Web.Api/Features/Companies/CompaniesController.cs Added UpdateCompany endpoint; changed CreateCompany to use EditCompanyBodyRequest instead of CreateCompanyBodyRequest.
src/Web.Api/Features/Companies/CreateCompany/CreateCompanyCommand.cs Changed base type and constructor parameter from CreateCompanyBodyRequest to EditCompanyBodyRequest.
src/Web.Api/Features/Companies/CreateCompany/EditCompanyBodyRequest.cs Renamed record type from CreateCompanyBodyRequest to EditCompanyBodyRequest.
src/Web.Api/Features/Companies/UpdateCompany/UpdateCompanyCommand.cs Added new UpdateCompanyCommand record for updating companies via CQRS.
src/Web.Api/Features/Companies/UpdateCompany/UpdateCompanyHandler.cs Added UpdateCompanyHandler to process update commands, validate, update, and save company data.
src/Web.Api/Features/Telegram/GetTelegramInlineUsageStats/TelegramInlineUsageChatDataItem.cs Changed TelegramInlineUsageChatDataItem from class to record for value-based equality and immutability.
src/Web.Api/Middlewares/LoggingMiddleware.cs Added EntityInvalidException and NotFoundException to ignored exceptions; improved log message formatting; reformatted constructor parameters.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant CompaniesController
    participant Mediator
    participant UpdateCompanyHandler
    participant DatabaseContext

    Client->>CompaniesController: PUT /companies/{companyId}
    CompaniesController->>Mediator: Send UpdateCompanyCommand(companyId, body)
    Mediator->>UpdateCompanyHandler: Handle(command)
    UpdateCompanyHandler->>DatabaseContext: Find company by ID
    UpdateCompanyHandler->>Company: Update(name, description, logoUrl, links)
    UpdateCompanyHandler->>DatabaseContext: SaveChangesAsync()
    UpdateCompanyHandler-->>Mediator: Unit
    Mediator-->>CompaniesController: Unit
    CompaniesController-->>Client: 200 OK
Loading

Poem

🐇
A hop, a skip, a company’s new tune,
With updates now launched, none too soon!
Ratings recalculated, info refreshed,
Commands and handlers, neatly enmeshed.
Logs are smarter, exceptions in line—
This rabbit’s code garden is looking just fine!
🌱✨

Tip

⚡️ Faster reviews with caching
  • CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.

Enjoy the performance boost—your workflow just got faster.

✨ Finishing Touches
  • 📝 Generate Docstrings

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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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 generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

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.

@maximgorbatyuk
Copy link
Member Author

Frontend Techinterview-space/frontend#76

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
src/Domain/Validation/Exceptions/EntityInvalidException.cs (1)

24-24: Redundant condition could be simplified.

This condition is always true at this point in the code flow since line 18 already ensures errors.Count > 0.

-        if (errors.Count != 0)
+        // No condition needed as errors.Count is always > 0 here
src/Web.Api/Features/Companies/UpdateCompany/UpdateCompanyHandler.cs (1)

13-43: Well-implemented handler following CQRS pattern.

This handler correctly implements the MediatR pattern for handling the company update command with proper separation of concerns:

  • Database access is properly injected via constructor
  • The handler performs appropriate validation and error handling
  • Business logic is delegated to the domain entity through the Update method
  • Async/await is used correctly for database operations

One suggestion would be to add some logging for successful updates and potential errors.

Consider adding logging to track successful updates:

 public async Task<Unit> Handle(
     UpdateCompanyCommand request,
     CancellationToken cancellationToken)
 {
     request.Body.ThrowIfInvalid();

     var company = await _context.Companies.FirstOrDefaultAsync(
         c => c.Id == request.CompanyId,
         cancellationToken)
         ?? throw NotFoundException.CreateFromEntity<Company>(request.CompanyId);

     company.Update(
         request.Body.Name,
         request.Body.Description,
         request.Body.LogoUrl,
         request.Body.Links);

     await _context.TrySaveChangesAsync(cancellationToken);
+    _logger.LogInformation("Company {CompanyId} updated successfully", request.CompanyId);
     return Unit.Value;
 }
src/Web.Api/Features/Companies/CompaniesController.cs (1)

57-57: Consider using PUT instead of POST for updates.

The endpoint currently uses HTTP POST for the update operation. RESTful API conventions suggest using PUT for complete resource updates or PATCH for partial updates. Consider changing the HTTP method to better align with REST standards.

-[HttpPost("{companyId:guid}")]
+[HttpPut("{companyId:guid}")]
 [HasAnyRole(Role.Admin)]
 public async Task<IActionResult> UpdateCompany(
src/Domain/Entities/Companies/Company.cs (1)

167-173: Consider using a more generic error message.

The error message in NotDeletedOrFail() is specific to marking a review as outdated, but this method is called from multiple contexts (e.g., AddReview, ApproveReview).

Consider using a more generic message:

public void NotDeletedOrFail()
{
    if (DeletedAt != null)
    {
-        throw new BadRequestException("Cannot mark a review as outdated.");
+        throw new BadRequestException("Cannot perform this operation on a deleted company.");
    }
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a46a28c and f390a71.

📒 Files selected for processing (9)
  • src/Domain/Entities/Companies/Company.cs (4 hunks)
  • src/Domain/Validation/Exceptions/EntityInvalidException.cs (1 hunks)
  • src/Web.Api/Features/Companies/CompaniesController.cs (3 hunks)
  • src/Web.Api/Features/Companies/CreateCompany/CreateCompanyCommand.cs (1 hunks)
  • src/Web.Api/Features/Companies/CreateCompany/EditCompanyBodyRequest.cs (1 hunks)
  • src/Web.Api/Features/Companies/UpdateCompany/UpdateCompanyCommand.cs (1 hunks)
  • src/Web.Api/Features/Companies/UpdateCompany/UpdateCompanyHandler.cs (1 hunks)
  • src/Web.Api/Features/Telegram/GetTelegramInlineUsageStats/TelegramInlineUsageChatDataItem.cs (1 hunks)
  • src/Web.Api/Middlewares/LoggingMiddleware.cs (2 hunks)
🔇 Additional comments (15)
src/Web.Api/Features/Telegram/GetTelegramInlineUsageStats/TelegramInlineUsageChatDataItem.cs (1)

3-3: Good choice converting to a record type.

Converting this class to a record provides value-based equality semantics and immutability, which is appropriate for this data transfer object. This enhances code quality with no behavioral changes.

src/Web.Api/Features/Companies/CreateCompany/EditCompanyBodyRequest.cs (1)

6-6: Good refactoring to support both create and update operations.

Renaming from CreateCompanyBodyRequest to EditCompanyBodyRequest makes this model more versatile and follows the DRY principle, allowing it to be used for both creating and updating companies.

src/Domain/Validation/Exceptions/EntityInvalidException.cs (2)

14-15: LGTM - Improved method signature formatting.

Breaking the parameter onto a new line improves readability for this method signature.


18-18: Good performance optimization using Count instead of Any().

Using Count == 0 is more efficient than !Any() for ICollection<T> as it avoids unnecessary LINQ operations.

src/Web.Api/Features/Companies/CreateCompany/CreateCompanyCommand.cs (2)

8-8: Properly updated inheritance to use EditCompanyBodyRequest.

The base class update aligns with the renaming of the request model while maintaining the same functionality.


11-11: Consistent parameter type update.

Parameter type correctly updated to match the renamed request model.

src/Web.Api/Middlewares/LoggingMiddleware.cs (2)

22-23: Good addition of domain exceptions to the ignore list.

Adding EntityInvalidException and NotFoundException to the ignored exceptions list is appropriate as these represent expected business cases rather than actual errors that require detailed logging.


44-47: Improved logging with structured format.

The updated logging now uses a structured format with a proper message template. This is a good practice as it:

  • Makes logs more searchable and filterable
  • Prevents log injection vulnerabilities
  • Maintains exception details by passing the exception object as the first parameter
src/Web.Api/Features/Companies/UpdateCompany/UpdateCompanyHandler.cs (1)

29-32: Concise null checking with the null-coalescing operator.

Good use of the null-coalescing operator combined with the throw expression to handle the case when the company isn't found. This is a clean and readable approach.

src/Web.Api/Features/Companies/UpdateCompany/UpdateCompanyCommand.cs (1)

7-20: Proper implementation of a command record.

Using a record type for the command provides valuable immutability and value-based semantics. The command is well-structured with:

  • Clear implementation of the IRequest interface
  • Constructor-based initialization
  • Read-only properties

This ensures the command data cannot be modified after creation, which helps prevent side effects during processing.

src/Web.Api/Features/Companies/CompaniesController.cs (2)

48-48: Consistent use of EditCompanyBodyRequest.

The parameter type change from CreateCompanyBodyRequest to EditCompanyBodyRequest reflects the refactoring to use a single request type for both creation and updates, which promotes consistency and reusability.


58-70: Well-implemented update endpoint with proper authorization.

The update endpoint correctly:

  • Restricts access to admin users with the HasAnyRole attribute
  • Receives the company ID from the route and update data from the body
  • Uses the mediator pattern to dispatch the command
  • Returns the result to the client

The implementation is consistent with other endpoints in the controller and follows the established patterns.

src/Domain/Entities/Companies/Company.cs (3)

111-116: Good refactoring to centralize rating calculation!

The change to use the extracted RecalculateRating method is a good refactoring that follows the DRY principle and centralizes the rating calculation logic.


136-141: Refactoring improves consistency in rating history updates.

The MarkReviewAsOutdated method now uses the centralized RecalculateRating method, making the code more maintainable and consistent with the ApproveReview method.


144-155: Well-designed centralized method for rating calculation.

The new RecalculateRating method effectively centralizes the logic for computing ratings, which was previously duplicated. It properly updates both Rating and ReviewsCount properties while returning the new rating value for immediate use.

@@ -0,0 +1,20 @@
using System;
using MediatR;
using Web.Api.Features.Companies.CreateCompany;
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Using the same request model for create and update operations.

The reuse of EditCompanyBodyRequest from the CreateCompany namespace for update operations promotes consistency and reduces duplication. This suggests the model has been renamed from its original CreateCompanyBodyRequest to better reflect its dual purpose.


🏁 Script executed:

#!/bin/bash
# Check if EditCompanyBodyRequest was renamed from CreateCompanyBodyRequest
git log -p -- "src/Web.Api/Features/Companies/CreateCompany/EditCompanyBodyRequest.cs" | grep -A 10 -B 10 "CreateCompanyBodyRequest"

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Locate the file that defines EditCompanyBodyRequest
file=$(rg -l "class EditCompanyBodyRequest" -n .)
echo "Found file: $file"

# Check its Git history (including renames) for occurrences of CreateCompanyBodyRequest
git log --follow --name-status -- "$file" | grep -E "^(R[0-9]+|[AMDR]\s)" | sed -n '1,20p'
git log --follow -p -- "$file" | grep -C 5 "CreateCompanyBodyRequest"

Length of output: 87


🏁 Script executed:

#!/bin/bash
# 1. List all BodyRequest classes in the repository
echo "=== All BodyRequest class definitions ==="
rg --ignore-case -n "class .*BodyRequest" -t cs || true

echo
# 2. List files in the CreateCompany feature folder
echo "=== Files in src/Web.Api/Features/Companies/CreateCompany ==="
find src/Web.Api/Features/Companies/CreateCompany -maxdepth 1 -type f -name "*.cs" -printf '%f\n' || true

echo
# 3. Show the top of UpdateCompanyCommand.cs to inspect its usings
echo "=== UpdateCompanyCommand.cs imports ==="
update_file=$(rg -l "class UpdateCompanyCommand" -n .)
if [ -n "$update_file" ]; then
  sed -n '1,20p' "$update_file"
else
  echo "UpdateCompanyCommand.cs not found"
fi

Length of output: 712


Standardize the shared request model and clarify its intent

The EditCompanyBodyRequest type is currently defined under the CreateCompany feature but is being reused by UpdateCompany. To avoid confusion and better reflect its dual role:

  • Consolidate this DTO into a neutral name (for example, CompanyBodyRequest)
  • Move it to a shared namespace/folder, e.g. src/Web.Api/Features/Companies/Models/CompanyBodyRequest.cs
  • Update both CreateCompanyCommand.cs and UpdateCompanyCommand.cs to import the new namespace:
- using Web.Api.Features.Companies.CreateCompany;
+ using Web.Api.Features.Companies.Models;

This will make its purpose clear, reduce coupling between feature folders, and improve maintainability.

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +175 to +199
public void Update(
string name,
string description,
string logoUrl,
List<string> links)
{
name = name?.Trim();
description = description?.Trim();

if (string.IsNullOrWhiteSpace(name))
{
throw new BadRequestException("Company name cannot be empty.");
}

if (string.IsNullOrWhiteSpace(description))
{
throw new BadRequestException("Company description cannot be empty.");
}

Name = name;
NormalizedName = name.ToUpperInvariant();
Description = description;
LogoUrl = logoUrl;
Links = links ?? new List<string>();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add check for deleted companies in Update method.

The Update method implementation looks good with proper validation and normalization of inputs. However, unlike other methods that modify the entity (AddReview, ApproveReview, MarkReviewAsOutdated), it doesn't check if the company has been deleted.

Consider adding a call to NotDeletedOrFail() at the beginning of the method:

public void Update(
    string name,
    string description,
    string logoUrl,
    List<string> links)
{
+    NotDeletedOrFail();
+
    name = name?.Trim();
    description = description?.Trim();
    
    // rest of the method...
}

@maximgorbatyuk maximgorbatyuk merged commit 970721b into main May 11, 2025
3 checks passed
@maximgorbatyuk maximgorbatyuk deleted the update-companies branch May 11, 2025 15:43
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.

2 participants