Skip to content

User Endpoints#25

Merged
hadeer-r merged 15 commits into
Askfm-clone:Developfrom
hadeer-r:User
Sep 4, 2025
Merged

User Endpoints#25
hadeer-r merged 15 commits into
Askfm-clone:Developfrom
hadeer-r:User

Conversation

@hadeer-r
Copy link
Copy Markdown
Contributor

@hadeer-r hadeer-r commented Aug 29, 2025

#22

  • Update User
  • Delete User
  • Follow User
  • UnFollow User
  • Update Password

Tests:

  • Update User Tests

TODO:

  • reset Password
  • reset Email
  • Decide how deleted endpoint will behave with relations

Summary by CodeRabbit

  • New Features

    • Added profile endpoints: fetch profile, update profile, delete account, follow/unfollow, and change password.
  • Changes

    • Profile updates no longer allow changing email; email-change flow postponed.
    • Backend now uses transactional updates for follow/unfollow and other profile operations.
  • Bug Fixes

    • Authentication endpoints return clearer error messages and more consistent token handling.
  • Documentation

    • API docs (Swagger) now support JWT authentication (Authorize).
  • Tests

    • Added unit tests for user update and delete scenarios.

- Update User
- Delete User
- Follow User
- UnFollow User
- Update Password

Tests:
- Update User Tests

TODO:
- reset Password
- reset Email
- Decide how deleted endpoint will behave with relations
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Aug 29, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Adds profile-focused user endpoints to the API, implements full user business logic with transactional follow/unfollow and password update in UserService, adjusts DTOs and auth behaviors (removing Logout and standardizing error responses), adds UnitOfWork transaction support, configures Swagger for JWT, and introduces unit tests and test dependencies.

Changes

Cohort / File(s) Summary
API Controllers: Auth
AskFm/AskFm.API/Controllers/AuthController.cs
Standardizes failure responses to return result.Errors; ensures setRefreshToken is invoked after successful token operations.
API Controllers: Users
AskFm/AskFm.API/Controllers/UserController.cs
Removes GetUsers; adds GET profile/{userId}, POST profile/update/{userId}, DELETE profile/{userId}, POST profile/{followerId}/follow/{targetUserId}, POST profile/{followerId}/unfollow/{targetUserId}, POST profile/update/pass/{userId} and a _checkCurrentUser helper plus auth checks.
API Program/Swagger
AskFm/AskFm.API/Program.cs
Replaces AddSwaggerGen() with configured SwaggerGen adding JWT Bearer OpenAPI security definition and requirement.
DTOs
AskFm/AskFm.BLL/DTO/UserDTOs/UpdateUserDTO.cs, AskFm/AskFm.BLL/DTO/UserDTOs/UpdatePasswordDTO.cs
Removes Email from UpdateUserDTO; adds new UpdatePasswordDTO with CurrentPassword and UpdatedPassword.
Auth Service Contracts & Impl
AskFm/AskFm.BLL/Services/UserIdentityService/IAuthService.cs, .../AuthService.cs
Removes Logout() from interface and implementation; LoginAsync rejects deleted users; RevokeRefreshTokenAsync no longer calls _userManager.UpdateAsync(user).
User Service Contract
AskFm/AskFm.BLL/Services/UserIdentityService/IUserService.cs
Changes signatures: UpdateUserAsyncTask<ServiceResult<bool>>; UpdateLastSeenAsyncTask<ServiceResult<bool>> (drops DateTime param); replaces ResetPassword with UpdatePassword(int userId, UpdatePasswordDTO); adds ResetEmail(int userId, string).
User Service Implementation
AskFm/AskFm.BLL/Services/UserIdentityService/UserService.cs
Implements update/delete/follow/unfollow/get-by-id/update-last-seen/update-password with EF Core and transactions; adds ResetEmail stub and a null-check helper; updates return types to ServiceResult<bool/ReadUserDTO> as appropriate.
DAL Unit of Work (Interface & Impl)
AskFm/AskFm.DAL/Interfaces/IUnitOfWork.cs, AskFm/AskFm.DAL/UnitOfWork.cs
Adds Task<IDbContextTransaction> BeginTransactionAsync() to interface and impl; makes SaveAsync() async/await and uses BeginTransactionAsync() (adds EF transaction using directive).
Repository (Cosmetic)
AskFm/AskFm.DAL/Repositories/UserRepository.cs
Minor whitespace insertion (no functional change).
Tests: Project & Unit Tests
AskFm/Tests/Tests.csproj, AskFm/Tests/UserTests.cs
Adds EF InMemory and Moq packages, references BLL/DAL projects, and introduces unit tests for UserService (update/delete scenarios) using Moq and xUnit.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Client
  participant API as UserController
  participant BLL as UserService
  participant UoW as UnitOfWork
  participant Repo as UserRepository
  participant IdMgr as UserManager

  rect rgb(235,245,255)
  note over Client,API: Update profile flow
  Client->>API: POST /profile/update/{userId} (UpdateUserDTO)
  API->>API: _checkCurrentUser(userId)
  API->>BLL: UpdateUserAsync(userId, dto)
  BLL->>UoW: GetByIdAsync(userId)
  UoW->>Repo: GetByIdAsync
  Repo-->>UoW: ApplicationUser
  UoW-->>BLL: ApplicationUser
  BLL->>UoW: UpdateAsync(user)
  BLL->>UoW: SaveAsync()
  BLL-->>API: ServiceResult<bool>
  API-->>Client: 200 OK / 400 BadRequest (result.Errors)
  end
Loading
sequenceDiagram
  autonumber
  actor Client
  participant API as UserController
  participant BLL as UserService
  participant UoW as UnitOfWork
  participant Users as UsersRepo
  participant Follows as FollowsRepo

  rect rgb(240,255,240)
  note over Client,API: Follow user flow (transactional)
  Client->>API: POST /profile/{followerId}/follow/{targetUserId}
  API->>API: validate & auth check
  API->>BLL: FollowUserAsync(followerId, targetUserId)
  BLL->>UoW: BeginTransactionAsync()
  BLL->>Users: GetByIdAsync(followerId)
  BLL->>Users: GetByIdAsync(targetUserId)
  BLL->>Follows: GetRelation(followerId,targetUserId)
  alt relation exists
    BLL->>Follows: Reactivate relation
  else
    BLL->>Follows: Create relation
  end
  BLL->>Users: Update follower/following counts
  BLL->>UoW: SaveAsync()
  BLL->>UoW: Commit()
  BLL-->>API: ServiceResult<bool>
  API-->>Client: 200 OK / 400 BadRequest (result.Errors)
  end
Loading
sequenceDiagram
  autonumber
  actor Client
  participant API as AuthController
  participant Auth as AuthService

  rect rgb(255,250,235)
  note over Client,API: Refresh token handling
  Client->>API: POST /auth/refresh
  API->>Auth: RefreshTokenAsync()
  alt success
    API->>API: setRefreshToken(cookie)
    API-->>Client: 200 OK (token data)
  else failure
    API-->>Client: 400 BadRequest (result.Errors)
  end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

I twitch my nose at brand-new routes,
Hop through follows, fix old doubts.
Transactions burrow safe and neat,
Tokens snug in Swagger's seat.
A carrot patch of tests in spring—hop, ship, repeat! 🐰✨

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.
    • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

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

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit 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.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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.

@ziad-ashraf7
Copy link
Copy Markdown
Contributor

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Sep 4, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
AskFm/AskFm.API/Controllers/UserController.cs (2)

17-17: Make _userService field private.

The _userService field should be private to maintain proper encapsulation.

-    public IUserService _userService;
+    private IUserService _userService;

27-37: GetAllUsers method lacks pagination and may cause performance issues.

Loading all users without pagination can cause performance problems as the user base grows.

Would you like me to help implement pagination for this endpoint?

AskFm/AskFm.BLL/Services/UserIdentityService/UserService.cs (1)

199-209: Null-claims NRE risk in GetCurrentUserAsync

Accessing .Value without checking the claim or HttpContext can throw.

-        string email = _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.Email).Value;
-        if (string.IsNullOrEmpty(email))
+        var emailClaim = _httpContextAccessor.HttpContext?.User?.FindFirst(ClaimTypes.Email);
+        if (emailClaim == null || string.IsNullOrEmpty(emailClaim.Value))
         {
             var errors = new List<string>()
             {
-                "Can't Access Current user"
+                "Cannot access current user"
             };
             return await ServiceResult<ApplicationUser>.Failure(errors);
         }
-        var currentAppUser = await _userManager.FindByEmailAsync(email);
+        var currentAppUser = await _userManager.FindByEmailAsync(emailClaim.Value);
🧹 Nitpick comments (16)
AskFm/Tests/Tests.csproj (1)

14-14: Mark Moq as test-only to avoid transitive flow.

Add PrivateAssets to keep it scoped to tests.

-        <PackageReference Include="Moq" Version="4.20.72" />
+        <PackageReference Include="Moq" Version="4.20.72" PrivateAssets="all" />
AskFm/AskFm.API/Program.cs (1)

49-75: Minor cleanup: remove duplicate AddControllers and unify auth scheme.

  • You call AddControllers twice (Lines 28 and 47). Keep one.
  • Prefer JwtBearerDefaults.AuthenticationScheme for both DefaultAuthenticateScheme and DefaultChallengeScheme.

Outside-diff tweaks:

// Remove the second call:
// builder.Services.AddControllers(); // (Line 47)

// Auth defaults:
builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
AskFm/AskFm.BLL/Services/UserIdentityService/IAuthService.cs (1)

9-9: Remove commented-out API from the interface.

Use an issue/TODO tracker instead of commented signatures.

-    // public Task<ServiceResult<bool>> ResetPasswordAsync(string Email);
AskFm/AskFm.DAL/Interfaces/IUnitOfWork.cs (1)

20-21: Consider CT/isolation overloads for transactions.

Add CancellationToken and optional IsolationLevel to future-proof transaction usage.

Example:

Task<IDbContextTransaction> BeginTransactionAsync(
    IsolationLevel isolationLevel = IsolationLevel.ReadCommitted,
    CancellationToken cancellationToken = default);
AskFm/AskFm.BLL/Services/UserIdentityService/IUserService.cs (1)

8-8: Consider returning the updated user data instead of just a boolean.

The change from Task<ServiceResult<UpdateUserDTO>> to Task<ServiceResult<bool>> reduces the information returned to the client. Consider returning the updated user data for better client experience and to avoid an additional API call.

AskFm/Tests/UserTests.cs (2)

29-29: Fix typo in comment.

-        // uesr repo setup
+        // user repo setup

68-69: Unnecessary Task.CompletedTask and Task.FromResult usage.

The mock setup can be simplified:

-        _mockUnitOfWork.Setup(u => u.Users.UpdateAsync(It.IsAny<ApplicationUser>())).Returns(Task.CompletedTask);
-        _mockUnitOfWork.Setup(u => u.SaveAsync()).Returns(Task.FromResult(1));
+        _mockUnitOfWork.Setup(u => u.Users.UpdateAsync(It.IsAny<ApplicationUser>())).Returns(Task.CompletedTask);
+        _mockUnitOfWork.Setup(u => u.SaveAsync()).ReturnsAsync(1);
AskFm/AskFm.API/Controllers/UserController.cs (3)

41-59: Code duplication in GetCurrentUserAsync.

The manual mapping to ReadUserDTO duplicates logic that likely exists in the service layer.

Consider having the service return a properly mapped DTO directly, or use AutoMapper to avoid manual mapping.


75-75: UpdateUserDTO should be from request body.

Add [FromBody] attribute to explicitly indicate the source of the DTO.

-    public async Task<IActionResult> UpdateUserAsync(int userId, UpdateUserDTO updatedUser)
+    public async Task<IActionResult> UpdateUserAsync(int userId, [FromBody] UpdateUserDTO updatedUser)

177-181: Track TODO items mentioned in comments.

The comments indicate pending work for email updates and user deletion checks during login.

Would you like me to create issues to track these TODO items: reset email functionality, email confirmation, and checking user deletion status during login?

AskFm/AskFm.BLL/Services/UserIdentityService/UserService.cs (6)

36-42: Avoid null-overwrites; return explicit true for consistency

  • Only overwrite fields when provided (patch semantics).
  • Align return value with other methods that return Success(true).
-        AppUserToUpdate.Name =  updatedUser.Name;
-        AppUserToUpdate.Bio =  updatedUser.Bio;
-        AppUserToUpdate.AvatarPath = updatedUser.AvatarPath;
+        if (updatedUser.Name is not null)        AppUserToUpdate.Name = updatedUser.Name;
+        if (updatedUser.Bio is not null)         AppUserToUpdate.Bio = updatedUser.Bio;
+        if (updatedUser.AvatarPath is not null)  AppUserToUpdate.AvatarPath = updatedUser.AvatarPath;
@@
-        return await ServiceResult<bool>.Success();
+        return await ServiceResult<bool>.Success(true);

47-53: Prefer async repository calls and clarify delete behavior

  • Use GetByIdAsync for consistency with EF Core async usage.
  • Define deletion semantics (soft delete vs. hard delete + cascades), per PR TODO.
-        var appUser = _unitOfWork.Users.GetById(userId);
+        var appUser = await _unitOfWork.Users.GetByIdAsync(userId);

Please confirm: Should related data (questions, answers, follows) be soft-deleted, reassigned, or cascaded? I can draft the approach once decided.


61-62: Clarify error message

Be explicit to aid client handling.

-            return await ServiceResult<bool>.Failure(new List<string> { "Invalid user" });
+            return await ServiceResult<bool>.Failure(new List<string> { "Cannot follow yourself" });

75-104: Ensure uniqueness and counter integrity for follows

  • Add a unique DB constraint on (FollowerId, FollowedId) to prevent races/dupes.
  • Consider recalculating or validating counters periodically to guard against drift.

If you’d like, I can provide the EF Core Fluent config and migration to enforce the unique index.


182-194: Use async retrieval; verify DTO property casing

  • Prefer GetByIdAsync.
  • Check that ReadUserDTO has followerCount (lowercase f). If it’s FollowerCount, this won’t compile.
-        var user = _unitOfWork.Users.GetById(userId);
+        var user = await _unitOfWork.Users.GetByIdAsync(userId);

Please confirm the exact property name on ReadUserDTO.


241-251: Avoid throwing NotImplemented from a service method

Return a structured failure until implemented; prevents 500s and keeps API contracts consistent.

-        //
-        throw new NotImplementedException();
+        // Not implemented yet
+        return await ServiceResult<ReadUserDTO>.Failure(new List<string> { "ResetEmail is not implemented yet." });

I can wire this up with GenerateChangeEmailTokenAsync, email sender, and a confirmation endpoint when ready.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a55ae4b and b5277c3.

📒 Files selected for processing (13)
  • AskFm/AskFm.API/Controllers/AuthController.cs (4 hunks)
  • AskFm/AskFm.API/Controllers/UserController.cs (2 hunks)
  • AskFm/AskFm.API/Program.cs (1 hunks)
  • AskFm/AskFm.BLL/DTO/UserDTOs/UpdateUserDTO.cs (0 hunks)
  • AskFm/AskFm.BLL/Services/UserIdentityService/AuthService.cs (0 hunks)
  • AskFm/AskFm.BLL/Services/UserIdentityService/IAuthService.cs (1 hunks)
  • AskFm/AskFm.BLL/Services/UserIdentityService/IUserService.cs (1 hunks)
  • AskFm/AskFm.BLL/Services/UserIdentityService/UserService.cs (3 hunks)
  • AskFm/AskFm.DAL/Interfaces/IUnitOfWork.cs (2 hunks)
  • AskFm/AskFm.DAL/Repositories/UserRepository.cs (1 hunks)
  • AskFm/AskFm.DAL/UnitOfWork.cs (2 hunks)
  • AskFm/Tests/Tests.csproj (2 hunks)
  • AskFm/Tests/UserTests.cs (1 hunks)
💤 Files with no reviewable changes (2)
  • AskFm/AskFm.BLL/DTO/UserDTOs/UpdateUserDTO.cs
  • AskFm/AskFm.BLL/Services/UserIdentityService/AuthService.cs
🔇 Additional comments (10)
AskFm/AskFm.DAL/Repositories/UserRepository.cs (1)

19-19: No-op whitespace change — OK.

No functional impact.

AskFm/Tests/Tests.csproj (2)

12-12: EF Core InMemory dependency — OK.

Version aligns with net9.0.


23-26: Project references added — OK.

Keeps tests close to BLL/DAL surfaces.

AskFm/AskFm.API/Program.cs (1)

49-75: JWT security in Swagger — LGTM.

Security scheme + requirement are correctly wired.

AskFm/AskFm.DAL/Interfaces/IUnitOfWork.cs (1)

2-2: Import for transactions — OK.

Required for IDbContextTransaction.

AskFm/AskFm.API/Controllers/AuthController.cs (2)

33-33: Good improvement in error response consistency.

The consistent return of result.Errors instead of the full result object improves API response uniformity and reduces information leakage.

Also applies to: 50-50, 71-71, 91-91


52-53: LGTM! Simplified token refresh flow.

The unconditional call to setRefreshToken after success check simplifies the control flow and aligns with the updated authentication service behavior.

Also applies to: 73-73

AskFm/AskFm.DAL/UnitOfWork.cs (2)

134-137: Good fix for async method implementation.

Properly implementing the async method by awaiting SaveChangesAsync() instead of returning the task directly ensures correct exception handling and stack traces.


139-139: Transaction support added correctly.

The implementation of BeginTransactionAsync enables transactional operations across the data layer, which is essential for maintaining data consistency in complex operations.

AskFm/AskFm.BLL/Services/UserIdentityService/IUserService.cs (1)

12-12: Good improvement in UpdateLastSeenAsync signature.

Removing the DateTime lastSeen parameter and letting the service determine the current time internally prevents client-side time inconsistencies.

Comment thread AskFm/AskFm.API/Controllers/UserController.cs
Comment thread AskFm/AskFm.API/Controllers/UserController.cs Outdated
Comment thread AskFm/AskFm.API/Controllers/UserController.cs Outdated
Comment thread AskFm/AskFm.API/Controllers/UserController.cs
Comment thread AskFm/AskFm.API/Controllers/UserController.cs
Comment thread AskFm/AskFm.BLL/Services/UserIdentityService/UserService.cs
Comment thread AskFm/AskFm.BLL/Services/UserIdentityService/UserService.cs
Comment thread AskFm/AskFm.BLL/Services/UserIdentityService/UserService.cs Outdated
@@ -1,4 +1,5 @@
using AskFm.DAL.Models;
using Microsoft.EntityFrameworkCore.Storage;
using Thread = System.Threading.Thread;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Critical: Repository typed to System.Threading.Thread, not your domain Thread.

The alias forces IRepository to mean System.Threading.Thread, likely breaking data access for threads.

Apply this diff within the using block:

-using Thread = System.Threading.Thread;
+using DalThread = AskFm.DAL.Models.Thread;

Then update the property type (outside this diffed range):

IRepository<DalThread> Threads { get; }
🤖 Prompt for AI Agents
In AskFm/AskFm.DAL/Interfaces/IUnitOfWork.cs around line 3, the file currently
aliases Thread to System.Threading.Thread which causes IRepository<Thread> to
refer to the framework Thread type instead of your domain entity; remove that
alias, add or ensure the using for your DAL thread entity namespace (so
DalThread is in scope), and update the interface property declaration (outside
the shown diff) to use IRepository<DalThread> Threads { get; }.

Comment thread AskFm/Tests/UserTests.cs
@hadeer-r
Copy link
Copy Markdown
Contributor Author

hadeer-r commented Sep 4, 2025

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Sep 4, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
AskFm/AskFm.BLL/Services/UserIdentityService/AuthService.cs (1)

223-238: Replace obsolete RNGCryptoServiceProvider.

Use RandomNumberGenerator APIs; fewer allocations and no obsolete type warnings.

-    private async Task<RefreshToken> generateRefreshToken()
+    private async Task<RefreshToken> generateRefreshToken()
     {
-        var randomNumber = new byte[32];
-
-        using var generator = new RNGCryptoServiceProvider();
-
-        generator.GetBytes(randomNumber);
+        var randomNumber = RandomNumberGenerator.GetBytes(32);
 
         return new RefreshToken
         {
             Token = Convert.ToBase64String(randomNumber),
             ExpireOn = DateTime.UtcNow.AddDays(10),
             CreatedOn = DateTime.UtcNow
         };
     }
AskFm/AskFm.BLL/Services/UserIdentityService/UserService.cs (1)

206-214: Null-safety for current-user claim lookup

Avoid potential NRE when HttpContext/User/claim is missing.

-        string email = _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.Email).Value;
+        var email = _httpContextAccessor.HttpContext?.User?.FindFirst(ClaimTypes.Email)?.Value;
         if (string.IsNullOrEmpty(email))
♻️ Duplicate comments (2)
AskFm/AskFm.BLL/Services/UserIdentityService/UserService.cs (2)

173-176: Prefer UTC timestamps for LastSeen

-            appUser.LastSeen = DateTime.Now;
+            appUser.LastSeen = DateTime.UtcNow;

141-156: Fix duplicate flag assignment and use CommitAsync

  • IsDeleted is set twice.
  • Mixing async transaction with sync Commit() risks incomplete commits.
             if (followExist != null)
             {
-                followExist.IsDeleted = true;
-                followExist.IsDeleted = true;
+                followExist.IsDeleted = true;
                 followExist.IsActive = false;
                 if (userFollower.FollowingCount > 0) userFollower.FollowingCount--;
                 if (targetUser.FollowersCount > 0)   targetUser.FollowersCount--;
                 await _unitOfWork.Follows.UpdateAsync(followExist);
                 await _unitOfWork.Users.UpdateAsync(userFollower);
                 await _unitOfWork.Users.UpdateAsync(targetUser);
                 await _unitOfWork.SaveAsync();
             }
 
-            transaction.Commit();
+            await transaction.CommitAsync();
🧹 Nitpick comments (19)
AskFm/AskFm.BLL/DTO/UserDTOs/UpdatePasswordDTO.cs (1)

3-7: Naming nit: “UpdatedPassword” reads awkwardly.

Consider “NewPassword” for clarity across API and service layers. Low-cost rename now before external clients depend on it.

AskFm/AskFm.BLL/Services/UserIdentityService/AuthService.cs (2)

122-128: Use async repository calls and stronger token param validation.

These paths likely hit the DB; prefer async and guard against whitespace tokens.

-        if (refreshToken == null)
+        if (string.IsNullOrWhiteSpace(refreshToken))
         {
             var errors = new List<string> { "Invalid Token." };
             return await ServiceResult<AuthResponseDTO>.Failure(errors);
         }
-        var user = _unitOfWork.Users.GetById(id);
+        var user = await _unitOfWork.Users.GetByIdAsync(id);
-        if (!user.RefreshTokens.Any(r => r.Token == refreshToken))
+        if (!user.RefreshTokens.Any(r => r.Token == refreshToken))
         {
             var errors = new List<string> { "Invalid Token." };
             return await ServiceResult<bool>.Failure(errors);
         }
-        var oldRefreshToken = user.RefreshTokens.Single(t => t.Token == refreshToken);
+        var oldRefreshToken = user.RefreshTokens.Single(t => t.Token == refreshToken);
         oldRefreshToken.RevokedOn = DateTime.UtcNow;
-        await _userManager.UpdateAsync(user);
+        await _userManager.UpdateAsync(user);

Also applies to: 169-179


239-257: JWT hardening (optional).

Consider adding jti and sub claims and including roles if you authorize by role later.

-            Subject = new ClaimsIdentity(new Claim[] 
+            Subject = new ClaimsIdentity(new Claim[] 
             {
                 new(ClaimTypes.Name, appUser.Name),
                 new(ClaimTypes.Email, appUser.Email),
                 new("UserId", appUser.Id.ToString())
+                // new(JwtRegisteredClaimNames.Sub, appUser.Id.ToString()),
+                // new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
             })
AskFm/AskFm.BLL/Services/UserIdentityService/IUserService.cs (2)

8-8: Returning only bool forces extra fetches.

Returning ReadUserDTO from UpdateUserAsync reduces an extra GetByIdAsync in the controller.

-    Task<ServiceResult<bool>> UpdateUserAsync(int userId, UpdateUserDTO updatedUser);
+    Task<ServiceResult<ReadUserDTO>> UpdateUserAsync(int userId, UpdateUserDTO updatedUser);

12-16: Add CancellationToken to service methods.

Improves request cancellation and scalability under load.

-    Task<ServiceResult<bool>> UpdateLastSeenAsync(int userId);
+    Task<ServiceResult<bool>> UpdateLastSeenAsync(int userId, CancellationToken ct = default);
-    Task<ServiceResult<bool>> UpdatePassword(int userId, UpdatePasswordDTO updatePasswordDto);
+    Task<ServiceResult<bool>> UpdatePassword(int userId, UpdatePasswordDTO updatePasswordDto, CancellationToken ct = default);
-    Task<ServiceResult<ReadUserDTO>> ResetEmail(int userId, string updatedEmail);
+    Task<ServiceResult<ReadUserDTO>> ResetEmail(int userId, string updatedEmail, CancellationToken ct = default);
AskFm/Tests/UserTests.cs (4)

49-80: Strengthen assertions to verify updated fields.

Also assert passed entity contains new values, not just that UpdateAsync was called.

-        _mockUnitOfWork.Verify(u => u.Users.UpdateAsync(It.Is<ApplicationUser>(u => u.Id == userId)), Times.Once);
+        _mockUnitOfWork.Verify(u => u.Users.UpdateAsync(It.Is<ApplicationUser>(u =>
+            u.Id == userId &&
+            u.Name == updatedUser.Name &&
+            u.Bio == updatedUser.Bio &&
+            u.AvatarPath == updatedUser.AvatarPath
+        )), Times.Once);

83-119: Fix typos in test names (“Faild” → “Failed”).

Improves readability in test reports.

-    public async Task UpdatedUser_ThePassedUserIsNull_UpdateFaild()
+    public async Task UpdatedUser_ThePassedUserIsNull_UpdateFailed()
...
-    public async Task UpdatedUser_ThePassedUserIsNotFound_UpdateFaild()
+    public async Task UpdatedUser_ThePassedUserIsNotFound_UpdateFailed()

125-138: Add coverage for follow/unfollow and update password.

Current suite misses business-critical paths added in this PR. I can scaffold tests using Moq for transactions and ChangePasswordAsync.

Also applies to: 140-167


176-201: UserManager mock: consider strict setup for ChangePasswordAsync.

You’ll need this when adding UpdatePassword tests.

_mockUserManager
    .Setup(um => um.ChangePasswordAsync(It.IsAny<ApplicationUser>(), It.IsAny<string>(), It.IsAny<string>()))
    .ReturnsAsync(IdentityResult.Success);
AskFm/AskFm.API/Controllers/UserController.cs (6)

48-58: Consider 404 for missing users.

If the service indicates “not found”, return NotFound instead of BadRequest.

-        if (!result.success)
-        {
-            return BadRequest(result.Errors);
-        }
+        if (!result.success)
+        {
+            // if service distinguishes NotFound, surface it here
+            return NotFound(result.Errors);
+        }

78-93: Prefer 204 NoContent on successful delete and fix Forbid usage.

-        if (!await _checkCurrentUser(userId))
-        {
-            return Forbid("Cannot Remove this user");
-        }
+        if (!await _checkCurrentUser(userId))
+        {
+            return Forbid();
+        }
 ...
-        return Ok();
+        return NoContent();

95-114: Status code semantics and Forbid usage.

Self-follow is a business rule violation; BadRequest or Conflict is clearer than Forbid. Also remove string arg.

-        if (await _checkCurrentUser(targetUserId))
-        {
-            return Forbid("Cannot Follow the current user");
-        }
+        if (await _checkCurrentUser(targetUserId))
+        {
+            return BadRequest("Cannot follow yourself.");
+        }
-        if (!await _checkCurrentUser(followerId))
-        {
-            return Forbid("User can't perform this follow");
-        }
+        if (!await _checkCurrentUser(followerId))
+        {
+            return Forbid();
+        }

116-135: Mirror follow endpoint behavior and fix Forbid usage.

-        if (await _checkCurrentUser(targetUserId))
-        {
-            return Forbid("Cannot unFollow the current user");
-        }
+        if (await _checkCurrentUser(targetUserId))
+        {
+            return BadRequest("Cannot unfollow yourself.");
+        }
-        if (!await _checkCurrentUser(followerId))
-        {
-            return Forbid("User can't perform this unfollow");
-        }
+        if (!await _checkCurrentUser(followerId))
+        {
+            return Forbid();
+        }

165-171: Outdated TODO.

“check user not deleted in login” is implemented in AuthService.LoginAsync; remove or update the TODO.


60-66: Remove string arguments from Forbid() calls

  • In AskFm/AskFm.API/Controllers/UserController.cs at lines 66, 84, 101, 105, 122, 126, 143: replace calls like Forbid("…") with Forbid() (or use return StatusCode(403, "…") if you need to include a response body).
AskFm/AskFm.BLL/Services/UserIdentityService/UserService.cs (4)

241-245: Neutral/error message clarity

-            var errors = new List<string> { "Cannot Update Current Password." };
+            var errors = new List<string> { "Cannot update password." };

36-38: Optional: patch semantics to avoid overwriting with nulls

If DTO fields are optional, guard assignments to prevent nulling existing values.

-        AppUserToUpdate.Name =  updatedUser.Name;
-        AppUserToUpdate.Bio =  updatedUser.Bio;
-        AppUserToUpdate.AvatarPath = updatedUser.AvatarPath;
+        if (updatedUser.Name is not null)        AppUserToUpdate.Name = updatedUser.Name;
+        if (updatedUser.Bio is not null)         AppUserToUpdate.Bio = updatedUser.Bio;
+        if (updatedUser.AvatarPath is not null)  AppUserToUpdate.AvatarPath = updatedUser.AvatarPath;

75-104: Add DB uniqueness and concurrency guards for follow relations

  • Enforce unique index on (FollowerId, FollowedId) to prevent duplicates under race.
  • Consider optimistic concurrency (rowversion) on user counters to avoid drift.

Also applies to: 136-151


250-260: ResetEmail stub — can help implement end-to-end

Token generation, confirmation link, and ChangeEmailAsync flow are pending. I can provide a complete implementation wired to Identity options and email sender.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b5277c3 and afc5f70.

📒 Files selected for processing (6)
  • AskFm/AskFm.API/Controllers/UserController.cs (1 hunks)
  • AskFm/AskFm.BLL/DTO/UserDTOs/UpdatePasswordDTO.cs (1 hunks)
  • AskFm/AskFm.BLL/Services/UserIdentityService/AuthService.cs (2 hunks)
  • AskFm/AskFm.BLL/Services/UserIdentityService/IUserService.cs (1 hunks)
  • AskFm/AskFm.BLL/Services/UserIdentityService/UserService.cs (3 hunks)
  • AskFm/Tests/UserTests.cs (1 hunks)
🔇 Additional comments (2)
AskFm/AskFm.BLL/Services/UserIdentityService/AuthService.cs (1)

54-61: Good: Block login for soft-deleted users without leaking info.

Returning the same generic error string prevents user enumeration. Looks solid.

AskFm/AskFm.BLL/Services/UserIdentityService/UserService.cs (1)

228-239: Good fix: validate current password and prevent reuse

Comment on lines +60 to +76
[HttpPost]
[Route("profile/update/{userId}")]
public async Task<IActionResult> UpdateUserAsync(int userId, UpdateUserDTO updatedUser)
{
if (!await _checkCurrentUser(userId))
{
return Forbid("Cannot Update this user");
}
var result = await _userService.UpdateUserAsync(userId, updatedUser);
if (!result.success)
{
return BadRequest(result.Errors);
}

var userRead = await _userService.GetUserByIdAsync(userId);
return Ok(userRead);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Fix response shape and Forbid usage.

  • Forbid(string) treats the string as an auth scheme, not a message.
  • Return the DTO, not the ServiceResult wrapper.
-        if (!await _checkCurrentUser(userId))
-        {
-            return Forbid("Cannot Update this user");
-        }
+        if (!await _checkCurrentUser(userId))
+        {
+            return Forbid();
+        }
         var result = await _userService.UpdateUserAsync(userId, updatedUser);
         if (!result.success)
         {
             return BadRequest(result.Errors);
         }
-
-        var userRead = await _userService.GetUserByIdAsync(userId);
-        return Ok(userRead);
+        var userRead = await _userService.GetUserByIdAsync(userId);
+        return Ok(userRead.Data);
📝 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
[HttpPost]
[Route("profile/update/{userId}")]
public async Task<IActionResult> UpdateUserAsync(int userId, UpdateUserDTO updatedUser)
{
if (!await _checkCurrentUser(userId))
{
return Forbid("Cannot Update this user");
}
var result = await _userService.UpdateUserAsync(userId, updatedUser);
if (!result.success)
{
return BadRequest(result.Errors);
}
var userRead = await _userService.GetUserByIdAsync(userId);
return Ok(userRead);
}
[HttpPost]
[Route("profile/update/{userId}")]
public async Task<IActionResult> UpdateUserAsync(int userId, UpdateUserDTO updatedUser)
{
if (!await _checkCurrentUser(userId))
{
return Forbid();
}
var result = await _userService.UpdateUserAsync(userId, updatedUser);
if (!result.success)
{
return BadRequest(result.Errors);
}
var userRead = await _userService.GetUserByIdAsync(userId);
return Ok(userRead.Data);
}
🤖 Prompt for AI Agents
In AskFm/AskFm.API/Controllers/UserController.cs around lines 60 to 76, change
the Forbid call to not pass a string (use Forbid() or return ForbidResult())
because Forbid(string) is treated as an auth scheme, and when returning the
updated user unwrap the service result and return the DTO itself (e.g., check
GetUserByIdAsync result for success and return Ok(result.Value or .Data) instead
of returning the ServiceResult wrapper); also handle a failed GetUserByIdAsync
by returning an appropriate error status.

Comment on lines +137 to +154
[HttpPost]
[Route("profile/update/pass/{userId}")]
public async Task<IActionResult> UpdatePassword(int userId, UpdatePasswordDTO udpatePasswordDto)
{
if (await _checkCurrentUser(userId))
{
return Forbid("Cannot update password for another user");
}

var result = await _userService.UpdatePassword(userId, udpatePasswordDto);
if (!result.success)
{
return BadRequest(result.Errors);
}

return Ok();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Critical: Authorization check inverted + parameter typo.

This currently forbids the current user from changing their own password and allows others. Also fix the variable name and Forbid usage.

-    public async Task<IActionResult> UpdatePassword(int userId, UpdatePasswordDTO udpatePasswordDto)
+    public async Task<IActionResult> UpdatePassword(int userId, UpdatePasswordDTO updatePasswordDto)
     {
-        if (await _checkCurrentUser(userId))
-        {
-            return Forbid("Cannot update password for another user");
-        }
+        if (!await _checkCurrentUser(userId))
+        {
+            return Forbid();
+        }
         
-        var result = await _userService.UpdatePassword(userId, udpatePasswordDto);
+        var result = await _userService.UpdatePassword(userId, updatePasswordDto);
         if (!result.success)
         {
             return BadRequest(result.Errors);
         }
 
         return Ok();
     }
📝 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
[HttpPost]
[Route("profile/update/pass/{userId}")]
public async Task<IActionResult> UpdatePassword(int userId, UpdatePasswordDTO udpatePasswordDto)
{
if (await _checkCurrentUser(userId))
{
return Forbid("Cannot update password for another user");
}
var result = await _userService.UpdatePassword(userId, udpatePasswordDto);
if (!result.success)
{
return BadRequest(result.Errors);
}
return Ok();
}
[HttpPost]
[Route("profile/update/pass/{userId}")]
public async Task<IActionResult> UpdatePassword(int userId, UpdatePasswordDTO updatePasswordDto)
{
if (!await _checkCurrentUser(userId))
{
return Forbid();
}
var result = await _userService.UpdatePassword(userId, updatePasswordDto);
if (!result.success)
{
return BadRequest(result.Errors);
}
return Ok();
}
🤖 Prompt for AI Agents
In AskFm/AskFm.API/Controllers/UserController.cs around lines 137 to 154, the
authorization check is inverted and the DTO parameter is misspelled; change the
method signature parameter from udpatePasswordDto to updatePasswordDto, and
invert the conditional so that if the current user is NOT the target user you
return Forbid(); also remove the message passed to Forbid (use Forbid() or
return ForbidResult) and use the corrected updatePasswordDto variable when
calling _userService.UpdatePassword.

Comment on lines +156 to +163
//-------------------------------------------------------------------
// Helper functions
private async Task<bool> _checkCurrentUser(int userId)
{
var current_user = await _userService.GetCurrentUserAsync();
return current_user.Data.Id == userId;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Guard against null current user to avoid NRE.

Return false if service failed or Data is null.

-    private async Task<bool> _checkCurrentUser(int userId)
+    private async Task<bool> _checkCurrentUser(int userId)
     {
-        var current_user = await _userService.GetCurrentUserAsync();
-        return current_user.Data.Id == userId;
+        var currentUser = await _userService.GetCurrentUserAsync();
+        return currentUser.success && currentUser.Data != null && currentUser.Data.Id == userId;
     }
📝 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
//-------------------------------------------------------------------
// Helper functions
private async Task<bool> _checkCurrentUser(int userId)
{
var current_user = await _userService.GetCurrentUserAsync();
return current_user.Data.Id == userId;
}
//-------------------------------------------------------------------
// Helper functions
private async Task<bool> _checkCurrentUser(int userId)
{
var currentUser = await _userService.GetCurrentUserAsync();
return currentUser.success
&& currentUser.Data != null
&& currentUser.Data.Id == userId;
}
🤖 Prompt for AI Agents
In AskFm/AskFm.API/Controllers/UserController.cs around lines 156-163, the
helper _checkCurrentUser assumes _userService.GetCurrentUserAsync() returns a
non-null response and Data is present; change it to guard against null or failed
service results by returning false when the service call fails or the returned
object or its Data is null (e.g., await the call, check for null response,
optional success flag and response.Data null, and then only compare Id when
safe), ensuring no null-reference exception.

Comment on lines +5 to +6
public string CurrentPassword { get; set; }
public string UpdatedPassword { get; set; }
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add basic validation and avoid nullable strings in DTO.

Mark fields as required and set non-null defaults to prevent nulls from slipping through model binding.

+using System.ComponentModel.DataAnnotations;
+
 public class UpdatePasswordDTO
 {
-    public string CurrentPassword { get; set; }
-    public string UpdatedPassword { get; set; }
+    [Required, DataType(DataType.Password), MinLength(8)]
+    public string CurrentPassword { get; set; } = string.Empty;
+    
+    [Required, DataType(DataType.Password), MinLength(8)]
+    public string UpdatedPassword { get; set; } = string.Empty;
 }
📝 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 string CurrentPassword { get; set; }
public string UpdatedPassword { get; set; }
using System.ComponentModel.DataAnnotations;
public class UpdatePasswordDTO
{
[Required, DataType(DataType.Password), MinLength(8)]
public string CurrentPassword { get; set; } = string.Empty;
[Required, DataType(DataType.Password), MinLength(8)]
public string UpdatedPassword { get; set; } = string.Empty;
}
🤖 Prompt for AI Agents
In AskFm/AskFm.BLL/DTO/UserDTOs/UpdatePasswordDTO.cs around lines 5-6, the
CurrentPassword and UpdatedPassword properties are nullable and lack validation;
update them to be non-nullable by initializing to string.Empty and add basic
DataAnnotations (e.g., [Required] on both and a [MinLength] constraint as
appropriate) and include the System.ComponentModel.DataAnnotations using
directive so model binding enforces presence and minimal length.

Comment on lines +41 to 43
await _unitOfWork.SaveAsync();
return await ServiceResult<bool>.Success();
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Return Success(true) to reflect an actual update

Currently returns default bool (false). Align with other methods returning true on success.

-        await _unitOfWork.SaveAsync();
-        return await ServiceResult<bool>.Success();
+        await _unitOfWork.SaveAsync();
+        return await ServiceResult<bool>.Success(true);
📝 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
await _unitOfWork.SaveAsync();
return await ServiceResult<bool>.Success();
}
await _unitOfWork.SaveAsync();
return await ServiceResult<bool>.Success(true);
}
🤖 Prompt for AI Agents
In AskFm/AskFm.BLL/Services/UserIdentityService/UserService.cs around lines 41
to 43, the method currently returns ServiceResult<bool>.Success() which yields
the default bool (false); change the return to ServiceResult<bool>.Success(true)
so the method returns true on successful update to match other service methods
and reflect the actual success state.

Comment on lines +81 to +90
Follow follow = new Follow()
{
FollowerId = followerId,
FollowedId = targetUserId,

};

userFollower.FollowingCount++;
targetUser.FollowersCount++;
await _unitOfWork.Follows.AddAsync(follow);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

New follow should be active (and not deleted) on insert

Without setting flags, queries relying on IsActive may ignore new relations.

             if (followExist == null)
             {
                 Follow follow = new Follow()
                 {
                     FollowerId = followerId,
                     FollowedId = targetUserId,
+                    IsActive = true,
+                    IsDeleted = false
                 };
 
                 userFollower.FollowingCount++;
                 targetUser.FollowersCount++;
                 await _unitOfWork.Follows.AddAsync(follow);
             }
📝 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
Follow follow = new Follow()
{
FollowerId = followerId,
FollowedId = targetUserId,
};
userFollower.FollowingCount++;
targetUser.FollowersCount++;
await _unitOfWork.Follows.AddAsync(follow);
if (followExist == null)
{
Follow follow = new Follow()
{
FollowerId = followerId,
FollowedId = targetUserId,
IsActive = true,
IsDeleted = false
};
userFollower.FollowingCount++;
targetUser.FollowersCount++;
await _unitOfWork.Follows.AddAsync(follow);
}
🤖 Prompt for AI Agents
In AskFm/AskFm.BLL/Services/UserIdentityService/UserService.cs around lines 81
to 90, the new Follow entity is created without initializing its active/deleted
flags so queries that filter by IsActive may ignore it; set the follow's
IsActive = true (and optionally IsDeleted = false if that flag exists in the
model) before calling _unitOfWork.Follows.AddAsync(follow) so the relation is
immediately considered active, and keep the existing increments to
FollowingCount/FollowersCount as-is.

Comment on lines +189 to +201
var user = _unitOfWork.Users.GetById(userId);
var res = await CheckNullObjectAsync<ReadUserDTO, ApplicationUser>(user);
if (!res.success) return res;

return await ServiceResult<ReadUserDTO>.Success(new ReadUserDTO()
{
Name = user.Name,
Email = user.Email,
LastSeen = user.LastSeen,
Bio = user.Bio,
AvatarPath = user.AvatarPath,
followerCount = user.FollowersCount
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Use async repository call; verify DTO property casing

-        var user = _unitOfWork.Users.GetById(userId);
+        var user = await _unitOfWork.Users.GetByIdAsync(userId);

Also confirm ReadUserDTO uses followerCount (camelCase) vs FollowerCount (PascalCase).


🏁 Script executed:

#!/bin/bash
# Verify ReadUserDTO property casing and definition
rg -n -C2 -g '!**/bin/**' -g '!**/obj/**' 'class\s+ReadUserDTO|followerCount|FollowerCount' --type cs

Length of output: 2127


Use async repository call and rename followerCount to PascalCase

  • In UserService.cs, replace
    var user = _unitOfWork.Users.GetById(userId);
    with
    var user = await _unitOfWork.Users.GetByIdAsync(userId);
    and mark the method as async.
  • In ReadUserDTO.cs, change
    public int followerCount { get; set; }
    to
    public int FollowersCount { get; set; }
    then update all initializers and references (in both BLL services and the API controller) to use FollowersCount.
🤖 Prompt for AI Agents
In AskFm/AskFm.BLL/Services/UserIdentityService/UserService.cs around lines
189-201, the repository call is synchronous and the DTO property uses
non-PascalCase; change the method to use the async repository call (await
_unitOfWork.Users.GetByIdAsync(userId)) and mark the service method async so you
await the user retrieval and subsequent null check, and rename the ReadUserDTO
property followerCount to FollowersCount (update the DTO class) and update this
initializer and every reference across BLL services and the API controller to
use FollowersCount.

@hadeer-r
Copy link
Copy Markdown
Contributor Author

hadeer-r commented Sep 4, 2025

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Sep 4, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@hadeer-r hadeer-r merged commit e012b09 into Askfm-clone:Develop Sep 4, 2025
2 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Sep 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants