Spaces:
Running
Running
File size: 5,517 Bytes
f0d69b8 47e77e5 f0d69b8 47e77e5 f0d69b8 47e77e5 f0d69b8 7f6afc2 f0d69b8 7f6afc2 f0d69b8 64a3c1d 47e77e5 f0d69b8 ecb51fa f0d69b8 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using TaskTrackingSystem.Database.AppDbContextModels;
using TaskTrackingSystem.Shared;
using TaskTrackingSystem.Shared.Models.Comment;
using TaskTrackingSystem.WebApi.Infrastructure;
namespace TaskTrackingSystem.WebApi.Features.Task
{
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class TaskDetailsController : ControllerBase
{
private readonly AppDbContext _db;
private readonly TaskTrackingSystem.WebApi.Features.Notification.FirebaseNotificationService _notificationService;
public TaskDetailsController(AppDbContext db, TaskTrackingSystem.WebApi.Features.Notification.FirebaseNotificationService notificationService)
{
_db = db;
_notificationService = notificationService;
}
// βββ COMMENTS ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[HttpGet("tasks/{taskId}/comments")]
public async Task<ActionResult<IEnumerable<CommentDto>>> GetComments(long taskId)
{
var taskExists = await _db.Tasks.AnyAsync(t => t.Id == taskId && !t.IsDeleted && !t.IsArchived);
if (!taskExists)
{
return NotFound(new { message = $"Task with ID {taskId} not found." });
}
var comments = await _db.Comments
.Include(c => c.User)
.ThenInclude(u => u.Role)
.Where(c => c.TaskId == taskId && !c.IsDeleted)
.OrderBy(c => c.CreatedAt)
.Select(c => new CommentDto
{
Id = c.Id,
TaskId = c.TaskId,
UserId = c.UserId,
UserFullName = $"{c.User.FirstName} {c.User.LastName}",
UserRoleName = c.User.Role != null ? c.User.Role.Name : "User",
Message = c.Message,
CreatedAt = c.CreatedAt ?? DateTime.UtcNow,
UpdatedAt = c.UpdatedAt
})
.ToListAsync();
return Ok(comments);
}
[HttpPost("tasks/{taskId}/comments")]
public async Task<ActionResult<Result<CommentDto>>> CreateComment(long taskId, [FromBody] CreateCommentDto dto)
{
if (string.IsNullOrWhiteSpace(dto.Message))
{
return BadRequest(Result<CommentDto>.Failure("Comment message cannot be empty.", 400));
}
var task = await _db.Tasks.FirstOrDefaultAsync(t => t.Id == taskId && !t.IsDeleted && !t.IsArchived);
if (task == null)
{
return NotFound(Result<CommentDto>.Failure($"Task with ID {taskId} not found.", 404));
}
var userId = User.GetUserId();
var user = await _db.Users
.Include(u => u.Role)
.FirstOrDefaultAsync(u => u.Id == userId);
if (user == null)
{
return Unauthorized();
}
var comment = new Comment
{
TaskId = taskId,
UserId = userId,
Message = dto.Message.Trim(),
CreatedAt = DateTime.UtcNow,
CreatedBy = userId,
IsDeleted = false
};
_db.Comments.Add(comment);
await _db.SaveChangesAsync();
var actorName = $"{user.FirstName} {user.LastName}";
await _notificationService.NotifyCommentAddedAsync(task, userId, actorName, comment.Message);
await _notificationService.NotifyMentionedAsync(task, userId, actorName, comment.Message);
var resultDto = new CommentDto
{
Id = comment.Id,
TaskId = comment.TaskId,
UserId = comment.UserId,
UserFullName = $"{user.FirstName} {user.LastName}",
UserRoleName = user.Role != null ? user.Role.Name : "User",
Message = comment.Message,
CreatedAt = comment.CreatedAt ?? DateTime.UtcNow
};
return StatusCode(201, Result<CommentDto>.Success(resultDto, 201));
}
[HttpDelete("comments/{commentId}")]
public async Task<ActionResult<Result>> DeleteComment(long commentId)
{
var comment = await _db.Comments.FirstOrDefaultAsync(c => c.Id == commentId && !c.IsDeleted);
if (comment == null)
{
return NotFound(Result.Failure("Comment not found.", 404));
}
var userId = User.GetUserId();
var isAdmin = await DataScopeAuthorization.IsAdminScopeAsync(_db, User.GetRoleId());
// Only comment creator or Admin can delete
if (comment.UserId != userId && !isAdmin)
{
return Forbid();
}
comment.IsDeleted = true;
comment.UpdatedAt = DateTime.UtcNow;
comment.UpdatedBy = userId;
_db.Comments.Update(comment);
await _db.SaveChangesAsync();
return Ok(Result.Success(200));
}
}
}
|