Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AskFm/AskFm.API/AskFm.API.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AutoMapper" Version="15.0.1" />
<PackageReference Include="AutoMapper" Version="13.0.1" />
<PackageReference Include="DotNetEnv" Version="3.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
Expand Down
97 changes: 67 additions & 30 deletions AskFm/AskFm.API/Controllers/CommentController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@ namespace AskFm.API.Controllers;
[Authorize(AuthenticationSchemes = "Bearer")]
public class CommentController : ControllerBase
{

private readonly ICommentLikeService _commentLikeService;
private readonly ICommentService _commentService;
private readonly ILogger<CommentController> _logger;
private readonly IUserService _userService;



public CommentController(
ICommentLikeService commentLikeService,
ICommentService commentService,
Expand All @@ -31,11 +29,7 @@ public CommentController(
_commentService = commentService;
_userService = userService;
}






// GET api/comment/{id}/likes -> get all the likes for a Comment with id = id
[HttpGet("{id}/likes")]
public async Task<IActionResult> GetAllLikes(int id)
Expand All @@ -55,7 +49,6 @@ public async Task<IActionResult> GetAllLikes(int id)
return NotFound(new
{
message = ex.Message,

});
}
catch (Exception ex)
Expand All @@ -65,31 +58,28 @@ public async Task<IActionResult> GetAllLikes(int id)
}
}




// POST api/comment/{id}/likes -> add a like for a Comment with id = id
[HttpPost("{id}/likes")]
public async Task<IActionResult> AddLike(int id)
{
try
{
var user = await _userService.GetCurrentUserAsync();

if (!user.success)
{
return BadRequest(user.Errors);
}

var createdLike = await _commentLikeService.AddLikeAsync(id, user.Data.Id);

if (!createdLike.success)
{
return BadRequest(createdLike.Errors);
}
return CreatedAtAction(
nameof(GetAllLikes),
new { id = id },
nameof(GetAllLikes),
new { id = id },
createdLike.Data);
}
catch (ArgumentException ex)
Expand All @@ -108,37 +98,31 @@ public async Task<IActionResult> AddLike(int id)
return StatusCode(500, new { message = "An error occurred while adding like" });
}
}





[HttpDelete("{id}/likes")]
public async Task<IActionResult> DeleteLike(int id)
{
int userId = 0;
try
{

var user = await _userService.GetCurrentUserAsync();

if (user==null || !user.success)
if (user == null || !user.success)
return BadRequest(user.Errors);



userId = user.Data.Id;
var comment = await _commentService.GetCommentAsync(id);

if (comment == null || !user.success)
return BadRequest(user.Errors);
Comment on lines +110 to 117
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 | 🟠 Major

Fix comment existence check in DeleteLike

This block reuses the user result when validating the comment, so a missing comment slips through and user.Errors is returned even when the user lookup succeeded. It also risks a null dereference if user is null. Validate comment.success and surface its errors instead.

-            if (user == null || !user.success)
-                return BadRequest(user.Errors);
+            if (user == null || !user.success)
+            {
+                return BadRequest(user?.Errors ?? new[] { "Unable to resolve current user." });
+            }
 
             userId = user.Data.Id;
             var comment = await _commentService.GetCommentAsync(id);
 
-            if (comment == null || !user.success)
-                return BadRequest(user.Errors);
+            if (comment == null || !comment.success)
+            {
+                return BadRequest(comment?.Errors ?? new[] { "Comment not found." });
+            }
🤖 Prompt for AI Agents
In AskFm/AskFm.API/Controllers/CommentController.cs around lines 110 to 117, the
code incorrectly reuses the user result when validating the comment; replace the
second conditional so it verifies the comment result instead of user (i.e.,
check comment == null || !comment.success) and return comment.Errors; also
ensure you don't dereference user in that branch so the null-safety check is
correct.




var result = await _commentLikeService.DeleteLikeAsync(id, userId);

if (!result.success)
{
return BadRequest(result.Errors);
}

return NoContent();
}
catch (ArgumentException ex)
Expand All @@ -157,5 +141,58 @@ public async Task<IActionResult> DeleteLike(int id)
return StatusCode(500, new { message = "An error occurred while deleting like" });
}
}


// POST api/threads/{id}/comments - Add a comment to the thread with id = {id}
[HttpPost]
[Route("threads/{id}/comments")]
public async Task<IActionResult> AddComment([FromRoute] int id, [FromBody] CreateCommentDto createCommentDto)
{
var user = await _userService.GetCurrentUserAsync();
if (!user.success)
{
return BadRequest(user.Errors);
}

var result = await _commentService.AddComment(id, user.Data.Id, createCommentDto);
if (!result.success)
{
return BadRequest(result.Errors);
}

return Ok(result.Data);
}

// GET api/threads/{id}/comments - Get all comments for the thread with id = {id}
[HttpGet]
[Route("threads/{id}/comments")]
public async Task<IActionResult> GetComments([FromRoute] int id, [FromQuery] int page = 1, [FromQuery] int pageSize = 10)
{
var result = await _commentService.GetCommentsByThreadId(id, page, pageSize);
if (!result.success)
{
return BadRequest(result.Errors);
}

return Ok(result.Data);
}

// DELETE api/threads/{threadId}/comments/{commentId} - Delete a comment with id = {commentId}
[HttpDelete]
[Route("threads/{threadId}/comments/{commentId}")]
public async Task<IActionResult> DeleteComment([FromRoute] int threadId, [FromRoute] int commentId)
{
var user = await _userService.GetCurrentUserAsync();
if (!user.success)
{
return BadRequest(user.Errors);
}

var result = await _commentService.DeleteComment(threadId, commentId, user.Data.Id);
if (!result.success)
{
return BadRequest(result.Errors);
}

return Ok(new { message = "Comment deleted successfully" });
}
Comment on lines +145 to +197
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 | 🟠 Major

Expose comment endpoints under /api/threads as documented

With [Route("api/[controller]")], these actions currently register at /api/comment/threads/..., not the advertised /api/threads/{...}/comments. Use absolute route templates (prefixed with /) or restructure the base route so clients hit the intended paths.

-    [HttpPost]
-    [Route("threads/{id}/comments")]
+    [HttpPost("/api/threads/{id}/comments")]
     public async Task<IActionResult> AddComment([FromRoute] int id, [FromBody] CreateCommentDto createCommentDto)
...
-    [HttpGet]
-    [Route("threads/{id}/comments")]
+    [HttpGet("/api/threads/{id}/comments")]
     public async Task<IActionResult> GetComments([FromRoute] int id, [FromQuery] int page = 1, [FromQuery] int pageSize = 10)
...
-    [HttpDelete]
-    [Route("threads/{threadId}/comments/{commentId}")]
+    [HttpDelete("/api/threads/{threadId}/comments/{commentId}")]
     public async Task<IActionResult> DeleteComment([FromRoute] int threadId, [FromRoute] int commentId)

Alternatively, move these actions to a controller whose base route is api/threads and adjust the templates accordingly.

🤖 Prompt for AI Agents
In AskFm/AskFm.API/Controllers/CommentController.cs around lines 145-197 the
comment-related actions are being registered under /api/comment/threads/...
because the controller base route is api/[controller]; update the route
attributes to use absolute paths (prefix each route template with a leading '/')
so they register as /api/threads/{id}/comments (e.g.
"/api/threads/{id}/comments", "/api/threads/{id}/comments" for GET/POST and
"/api/threads/{threadId}/comments/{commentId}" for DELETE), or alternatively
change the controller's base route to "api/threads" and adjust the action
templates to relative paths ("{id}/comments", "{threadId}/comments/{commentId}")
so the endpoints match the documented /api/threads/... paths.

}
Loading
Loading