using _0_Framework.Application;
using AccountManagement.Application.Contracts.Task;
using AccountManagement.Application.Contracts.Ticket;
using AccountManagement.Application.Contracts.TicketAccessAccount;
using CompanyManagment.App.Contracts.Workshop;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using ServiceHost.BaseControllers;
namespace ServiceHost.Areas.Admin.Controllers
{
///
/// API controller for admin ticket management functionality
///
public class TicketController : AdminBaseController
{
private readonly ITicketApplication _ticketApplication;
private readonly IWorkshopApplication _workshopApplication;
private readonly IAuthHelper _authHelper;
private readonly ITicketAccessAccountApplication _ticketAccessAccountApplication;
///
/// Initialize a new instance of the TicketController
///
public TicketController(
ITicketApplication ticketApplication,
IWorkshopApplication workshopApplication,
IAuthHelper authHelper,
ITicketAccessAccountApplication ticketAccessAccountApplication)
{
_ticketApplication = ticketApplication;
_workshopApplication = workshopApplication;
_authHelper = authHelper;
_ticketAccessAccountApplication = ticketAccessAccountApplication;
}
private bool HasTicketAccess()
{
return _ticketAccessAccountApplication.HasTicketAccess(_authHelper.CurrentAccountId());
}
///
/// Get ticket overview including types count and trash count
///
/// Search criteria for tickets
/// Ticket overview data including counts by type
[HttpGet]
public IActionResult GetTickets([FromQuery] TicketSearchModel searchModel)
{
if (!HasTicketAccess())
return Forbid();
var typesCount = _ticketApplication.GetTypesCountOfTicketForAdmin();
var trashCount = _ticketApplication.GetDeletedTicket().Count();
return Ok(new
{
success = true,
data = new
{
typesCount,
trashCount
}
});
}
///
/// Get paginated ticket data with filtering options
///
/// Page index for pagination (default: 1)
/// Filter by ticket status
/// Filter by ticket number
/// General search term
/// Paginated list of tickets matching the criteria
[HttpGet("data")]
public IActionResult GetTicketData([FromQuery] int pageIndex = 1, [FromQuery] string status = "",
[FromQuery] string ticketNumber = "", [FromQuery] string generalSearch = "")
{
if (!HasTicketAccess())
return Forbid();
var searchModel = new TicketSearchModel()
{
PageIndex = pageIndex,
Status = status,
TicketNumber = generalSearch,
GeneralSearch = generalSearch,
};
List tickets;
tickets = status != "زباله" ? _ticketApplication.GetAll(searchModel) : _ticketApplication.GetDeletedTicket();
return Ok(new
{
success = true,
data = tickets,
pageIndex = tickets.Count
});
}
///
/// Get detailed information about a specific ticket
///
/// The ID of the ticket to retrieve
/// Detailed ticket information including workshop name
[HttpGet("{ticketId}/detail")]
public IActionResult GetTicketDetail(long ticketId)
{
if (!HasTicketAccess())
return Forbid();
var ticket = _ticketApplication.GetDetails(ticketId);
if (ticket == null)
return NotFound();
ticket.WorkshopName = _workshopApplication.GetDetails(ticket.WorkshopId).WorkshopFullName;
return Ok(new
{
success = true,
data = ticket
});
}
///
/// Get all messages for a specific ticket
///
/// The ID of the ticket
/// Ticket details including all messages
[HttpGet("{ticketId}/messages")]
public IActionResult GetTicketMessages(long ticketId)
{
if (!HasTicketAccess())
return Forbid();
var ticketDetail = _ticketApplication.GetDetails(ticketId);
if (ticketDetail == null)
return NotFound();
return Ok(new
{
success = true,
data = ticketDetail
});
}
///
/// Submit an admin response to a ticket
///
/// Response details including ticket ID and response text
/// Operation result indicating success or failure
[HttpPost("response")]
public IActionResult SaveAdminResponse([FromBody] ResponseTicket command)
{
if (!HasTicketAccess())
return Forbid();
command.AdminId = _authHelper.CurrentAccountId();
command.Response = command.Response?.Replace("\n", "
");
var result = _ticketApplication.AdminResponseTicket(command);
return Ok(new
{
success = result.IsSuccedded,
message = result.Message
});
}
///
/// Upload a media file for ticket
///
/// The file to upload
/// Upload result with file ID if successful
[HttpPost("upload")]
public IActionResult UploadFile(IFormFile media)
{
if (!HasTicketAccess())
return Forbid();
var accountId = _authHelper.CurrentAccountId();
var operation = _ticketApplication.UploadMedia(media, accountId);
return Ok(new
{
success = operation.IsSuccedded,
message = operation.Message,
id = operation.SendId,
});
}
///
/// Delete a media file from the system
///
/// The ID of the media file to delete
/// Operation result indicating success or failure
[HttpDelete("media/{mediaId}")]
public IActionResult DeleteFile(long mediaId)
{
if (!HasTicketAccess())
return Forbid();
var operation = _ticketApplication.RemoveMedia(mediaId);
return Ok(new
{
success = operation.IsSuccedded,
message = operation.Message,
});
}
///
/// Remove all temporary uploaded files for the current user
///
/// Operation result indicating success
[HttpDelete("temp-files")]
public IActionResult RemoveAllTempFiles()
{
if (!HasTicketAccess())
return Forbid();
var accId = _authHelper.CurrentAccountId();
_ticketApplication.RemoveTempUploadedFiles(accId);
return Ok(new
{
success = true,
message = "فایلهای موقت با موفقیت حذف شدند"
});
}
///
/// Assign a task from a ticket to specific users
///
/// Task assignment details including description, title, and assignees
/// Operation result indicating success or failure
[HttpPost("assign-task")]
public IActionResult AssignTask([FromBody] CreateTaskRequest request)
{
if (!HasTicketAccess())
return Forbid();
var command = new CreateTask
{
SenderId = _authHelper.CurrentAccountId(),
Description = request.Description?.Replace("\n", "
"),
Title = request.Title,
EndTaskDate = request.EndTaskDate,
EndTaskTime = request.EndTaskTime,
ReceiverId = request.ReceiverId ?? new List(),
PositionId = request.PositionId ?? new List(),
UploadedMedia = request.UploadedMedia ?? new List()
};
var result = _ticketApplication.AssignTicket(command, request.TicketId);
return Ok(new
{
success = result.IsSuccedded,
message = result.Message,
});
}
///
/// Download or view a file from the system
///
/// The file path on the server
/// The file ID for naming purposes
/// File content for download or viewing
[HttpGet("file")]
public IActionResult GetFile([FromQuery] string filePath, [FromQuery] long id)
{
if (!HasTicketAccess())
return Forbid();
if (string.IsNullOrEmpty(filePath) || !System.IO.File.Exists(filePath))
return NotFound();
var contentType = Tools.GetContentTypeImage(Path.GetExtension(filePath));
if (string.IsNullOrWhiteSpace(contentType))
{
byte[] fileContent = System.IO.File.ReadAllBytes(filePath);
var extension = Tools.GetContentType(Path.GetExtension(filePath));
return File(fileContent, extension, $"Task_{id}{Path.GetExtension(filePath)}");
}
else
{
return PhysicalFile(filePath, contentType);
}
}
///
/// Download or play a voice file
///
/// The voice file path on the server
/// Voice file content as audio/ogg
[HttpGet("voice")]
public IActionResult GetVoice([FromQuery] string filePath)
{
if (!HasTicketAccess())
return Forbid();
if (string.IsNullOrEmpty(filePath) || !System.IO.File.Exists(filePath))
return NotFound();
byte[] voiceContent = System.IO.File.ReadAllBytes(filePath);
return File(voiceContent, "audio/ogg", "Task_voice.ogg");
}
///
/// View a picture file
///
/// The image file path on the server
/// Image file content
[HttpGet("picture")]
public IActionResult GetPicture([FromQuery] string filePath)
{
if (!HasTicketAccess())
return Forbid();
if (string.IsNullOrEmpty(filePath) || !System.IO.File.Exists(filePath))
return NotFound();
var contentType = Tools.GetContentTypeImage(Path.GetExtension(filePath));
return PhysicalFile(filePath, contentType);
}
///
/// Accept a pending admin response
///
/// The ID of the admin response to accept
/// Operation result indicating success or failure
[HttpPost("response/{adminResId}/accept")]
public IActionResult AcceptPendingAdminResponse(long adminResId)
{
if (!HasTicketAccess())
return Forbid();
var result = _ticketApplication.AcceptPendingAdminResponse(adminResId);
return Ok(new
{
success = result.IsSuccedded,
message = result.Message
});
}
///
/// Reject a pending admin response
///
/// The ID of the admin response to reject
/// Operation result indicating success or failure
[HttpPost("response/{adminResId}/reject")]
public IActionResult RejectPendingAdminResponse(long adminResId)
{
if (!HasTicketAccess())
return Forbid();
var result = _ticketApplication.RejectPendingAdminResponse(adminResId);
return Ok(new
{
success = result.IsSuccedded,
message = result.Message
});
}
///
/// Edit and accept a pending admin response
///
/// The ID of the admin response to edit
/// The new response text
/// Operation result indicating success or failure
[HttpPut("response/{adminResId}")]
public IActionResult EditPendingAdminResponse(long adminResId, [FromBody] EditResponseRequest request)
{
if (!HasTicketAccess())
return Forbid();
var result = _ticketApplication.EditAndAcceptPendingAdminResponse(adminResId, request.NewResponse.Replace("\n", "
"));
return Ok(new
{
success = result.IsSuccedded,
message = result.Message
});
}
///
/// Close a ticket (mark as closed)
///
/// The ID of the ticket to close
/// Operation result indicating success or failure
[HttpPost("{ticketId}/close")]
public IActionResult CloseTicket(long ticketId)
{
if (!HasTicketAccess())
return Forbid();
var result = _ticketApplication.CloseTicket(ticketId);
return Ok(new
{
success = result.IsSuccedded,
message = result.Message
});
}
///
/// Delete a ticket (move to trash)
///
/// The ID of the ticket to delete
/// Operation result indicating success or failure
[HttpDelete("{ticketId}")]
public IActionResult DeleteTicket(long ticketId)
{
if (!HasTicketAccess())
return Forbid();
var result = _ticketApplication.DeleteTicket(ticketId);
return Ok(new
{
success = result.IsSuccedded,
message = result.Message
});
}
///
/// Get current ticket counts by status (open, closed, answered, pending, etc.)
///
/// Ticket counts grouped by status
[HttpGet("counts")]
public IActionResult GetTicketCounts()
{
if (!HasTicketAccess())
return Forbid();
var typesCount = _ticketApplication.GetTypesCountOfTicketForAdmin();
var deletedCount = _ticketApplication.GetDeletedTicket().Count();
return Ok(new
{
success = true,
data = new
{
open = typesCount.Open,
closed = typesCount.Closed,
answered = typesCount.Answered,
pending = typesCount.Pending,
all = typesCount.All,
deleted = deletedCount
}
});
}
///
/// Restore a deleted ticket from trash
///
/// The ID of the ticket to restore
/// Operation result indicating success or failure
[HttpPost("{ticketId}/restore")]
public IActionResult RestoreDeletedTicket(long ticketId)
{
if (!HasTicketAccess())
return Forbid();
var result = _ticketApplication.RestoreDeletedTicket(ticketId);
return Ok(new
{
success = result.IsSuccedded,
message = result.Message
});
}
///
/// Check if the current user has access to ticket functionality
///
/// Access status for the current user
[HttpGet("access")]
public IActionResult CheckTicketAccess()
{
var accountId = _authHelper.CurrentAccountId();
var hasAccess = _ticketAccessAccountApplication.HasTicketAccess(accountId);
return Ok(new
{
success = true,
hasAccess
});
}
}
///
/// Request model for creating and assigning tasks from tickets
///
public class CreateTaskRequest
{
///
/// Task description
///
public string Description { get; set; }
///
/// Task title
///
public string Title { get; set; }
///
/// Task end date
///
public string EndTaskDate { get; set; }
///
/// Task end time
///
public string EndTaskTime { get; set; }
///
/// List of receiver IDs for task assignment
///
public List ReceiverId { get; set; }
///
/// List of position IDs for task assignment
///
public List PositionId { get; set; }
///
/// List of uploaded media file IDs
///
public List UploadedMedia { get; set; }
///
/// The ticket ID to assign task from
///
public long TicketId { get; set; }
}
///
/// Request model for editing admin responses
///
public class EditResponseRequest
{
///
/// The new response text
///
public string NewResponse { get; set; }
}
}