feat: add file management entities and services for chat message handling
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
using GozareshgirProgramManager.Application._Common.Models;
|
||||
using GozareshgirProgramManager.Application.Modules.TaskChat.Commands.DeleteMessage;
|
||||
using GozareshgirProgramManager.Application.Modules.TaskChat.Commands.EditMessage;
|
||||
using GozareshgirProgramManager.Application.Modules.TaskChat.Commands.PinMessage;
|
||||
using GozareshgirProgramManager.Application.Modules.TaskChat.Commands.SendMessage;
|
||||
using GozareshgirProgramManager.Application.Modules.TaskChat.Commands.UnpinMessage;
|
||||
using GozareshgirProgramManager.Application.Modules.TaskChat.DTOs;
|
||||
using GozareshgirProgramManager.Application.Modules.TaskChat.Queries.GetMessages;
|
||||
using GozareshgirProgramManager.Application.Modules.TaskChat.Queries.GetPinnedMessages;
|
||||
using GozareshgirProgramManager.Application.Modules.TaskChat.Queries.SearchMessages;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using ServiceHost.BaseControllers;
|
||||
|
||||
namespace ServiceHost.Areas.Admin.Controllers.ProgramManager;
|
||||
|
||||
/// <summary>
|
||||
/// کنترلر مدیریت چت تسک
|
||||
/// </summary>
|
||||
public class TaskChatController : ProgramManagerBaseController
|
||||
{
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
public TaskChatController(IMediator mediator)
|
||||
{
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// دریافت لیست پیامهای یک تسک
|
||||
/// </summary>
|
||||
/// <param name="taskId">شناسه تسک</param>
|
||||
/// <param name="page">صفحه (پیشفرض: 1)</param>
|
||||
/// <param name="pageSize">تعداد در هر صفحه (پیشفرض: 50)</param>
|
||||
[HttpGet("{taskId:guid}/messages")]
|
||||
public async Task<ActionResult<OperationResult<PaginationResult<MessageDto>>>> GetMessages(
|
||||
Guid taskId,
|
||||
[FromQuery] int page = 1,
|
||||
[FromQuery] int pageSize = 50)
|
||||
{
|
||||
var query = new GetMessagesQuery(taskId, page, pageSize);
|
||||
var result = await _mediator.Send(query);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// دریافت پیامهای پین شده یک تسک
|
||||
/// </summary>
|
||||
/// <param name="taskId">شناسه تسک</param>
|
||||
[HttpGet("{taskId:guid}/messages/pinned")]
|
||||
public async Task<ActionResult<OperationResult<List<MessageDto>>>> GetPinnedMessages(Guid taskId)
|
||||
{
|
||||
var query = new GetPinnedMessagesQuery(taskId);
|
||||
var result = await _mediator.Send(query);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// جستجو در پیامهای یک تسک
|
||||
/// </summary>
|
||||
/// <param name="taskId">شناسه تسک</param>
|
||||
/// <param name="search">متن جستجو</param>
|
||||
/// <param name="page">صفحه</param>
|
||||
/// <param name="pageSize">تعداد در هر صفحه</param>
|
||||
[HttpGet("{taskId:guid}/messages/search")]
|
||||
public async Task<ActionResult<OperationResult<List<MessageDto>>>> SearchMessages(
|
||||
Guid taskId,
|
||||
[FromQuery] string search,
|
||||
[FromQuery] int page = 1,
|
||||
[FromQuery] int pageSize = 20)
|
||||
{
|
||||
var query = new SearchMessagesQuery(taskId, search, page, pageSize);
|
||||
var result = await _mediator.Send(query);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ارسال پیام جدید (با یا بدون فایل)
|
||||
/// </summary>
|
||||
[HttpPost("messages")]
|
||||
public async Task<ActionResult<OperationResult<MessageDto>>> SendMessage(
|
||||
[FromForm] SendMessageCommand command)
|
||||
{
|
||||
var result = await _mediator.Send(command);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ویرایش پیام (فقط متن)
|
||||
/// </summary>
|
||||
/// <param name="messageId">شناسه پیام</param>
|
||||
/// <param name="request">محتوای جدید</param>
|
||||
[HttpPut("messages/{messageId:guid}")]
|
||||
public async Task<ActionResult<OperationResult>> EditMessage(
|
||||
Guid messageId,
|
||||
[FromBody] EditMessageRequest request)
|
||||
{
|
||||
var command = new EditMessageCommand(messageId, request.NewTextContent);
|
||||
var result = await _mediator.Send(command);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// حذف پیام
|
||||
/// </summary>
|
||||
/// <param name="messageId">شناسه پیام</param>
|
||||
[HttpDelete("messages/{messageId:guid}")]
|
||||
public async Task<ActionResult<OperationResult>> DeleteMessage(Guid messageId)
|
||||
{
|
||||
var command = new DeleteMessageCommand(messageId);
|
||||
var result = await _mediator.Send(command);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// پین کردن پیام
|
||||
/// </summary>
|
||||
/// <param name="messageId">شناسه پیام</param>
|
||||
[HttpPost("messages/{messageId:guid}/pin")]
|
||||
public async Task<ActionResult<OperationResult>> PinMessage(Guid messageId)
|
||||
{
|
||||
var command = new PinMessageCommand(messageId);
|
||||
var result = await _mediator.Send(command);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// برداشتن پین پیام
|
||||
/// </summary>
|
||||
/// <param name="messageId">شناسه پیام</param>
|
||||
[HttpPost("messages/{messageId:guid}/unpin")]
|
||||
public async Task<ActionResult<OperationResult>> UnpinMessage(Guid messageId)
|
||||
{
|
||||
var command = new UnpinMessageCommand(messageId);
|
||||
var result = await _mediator.Send(command);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public class EditMessageRequest
|
||||
{
|
||||
public string NewTextContent { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
@@ -492,6 +492,24 @@ app.UseHttpsRedirection();
|
||||
|
||||
app.UseStaticFiles();
|
||||
|
||||
// Static files برای فایلهای آپلود شده
|
||||
var uploadsPath = builder.Configuration["FileStorage:LocalPath"] ?? Path.Combine(Directory.GetCurrentDirectory(), "Uploads");
|
||||
if (!Directory.Exists(uploadsPath))
|
||||
{
|
||||
Directory.CreateDirectory(uploadsPath);
|
||||
}
|
||||
|
||||
app.UseStaticFiles(new StaticFileOptions
|
||||
{
|
||||
FileProvider = new Microsoft.Extensions.FileProviders.PhysicalFileProvider(uploadsPath),
|
||||
RequestPath = "/uploads",
|
||||
OnPrepareResponse = ctx =>
|
||||
{
|
||||
// Cache برای فایلها (30 روز)
|
||||
ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=2592000");
|
||||
}
|
||||
});
|
||||
|
||||
app.UseCookiePolicy();
|
||||
|
||||
|
||||
|
||||
@@ -64,8 +64,14 @@
|
||||
"Issuer": "GozareshgirApp",
|
||||
"Audience": "GozareshgirUsers",
|
||||
"ExpirationMinutes": 30
|
||||
},
|
||||
"FileStorage": {
|
||||
"BaseUrl": "https://localhost:7032/uploads",
|
||||
"MaxFileSizeBytes": 104857600,
|
||||
"AllowedImageExtensions": [ ".jpg", ".jpeg", ".png", ".gif", ".webp" ],
|
||||
"AllowedVideoExtensions": [ ".mp4", ".avi", ".mov", ".wmv" ],
|
||||
"AllowedAudioExtensions": [ ".mp3", ".wav", ".ogg", ".m4a" ],
|
||||
"AllowedDocumentExtensions": [ ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".txt" ]
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -50,5 +50,13 @@
|
||||
"Issuer": "GozareshgirApp",
|
||||
"Audience": "GozareshgirUsers",
|
||||
"ExpirationMinutes": 30
|
||||
},
|
||||
"FileStorage": {
|
||||
"BaseUrl": "https://api.pm.gozareshgir.ir/uploads",
|
||||
"MaxFileSizeBytes": 104857600,
|
||||
"AllowedImageExtensions": [ ".jpg", ".jpeg", ".png", ".gif", ".webp" ],
|
||||
"AllowedVideoExtensions": [ ".mp4", ".avi", ".mov", ".wmv" ],
|
||||
"AllowedAudioExtensions": [ ".mp3", ".wav", ".ogg", ".m4a" ],
|
||||
"AllowedDocumentExtensions": [ ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".txt" ]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user