Add admin page for bundle

This commit is contained in:
2025-11-10 11:50:20 +07:00
parent ecf07a7863
commit 0861e9a8d2
18 changed files with 2071 additions and 49 deletions

View File

@@ -0,0 +1,232 @@
using Managing.Api.Models.Responses;
using Managing.Application.Abstractions.Services;
using Managing.Application.Abstractions.Shared;
using Managing.Application.Shared;
using Managing.Domain.Backtests;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using static Managing.Common.Enums;
namespace Managing.Api.Controllers;
/// <summary>
/// Controller for admin operations.
/// Provides endpoints for administrative tasks that require admin authorization.
/// All endpoints in this controller require admin access.
/// </summary>
[ApiController]
[Authorize]
[Route("[controller]")]
[Produces("application/json")]
public class AdminController : BaseController
{
private readonly IBacktester _backtester;
private readonly IAdminConfigurationService _adminService;
private readonly ILogger<AdminController> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="AdminController"/> class.
/// </summary>
/// <param name="userService">The service for user management.</param>
/// <param name="backtester">The service for backtesting operations.</param>
/// <param name="adminService">The admin configuration service for authorization checks.</param>
/// <param name="logger">The logger instance.</param>
public AdminController(
IUserService userService,
IBacktester backtester,
IAdminConfigurationService adminService,
ILogger<AdminController> logger) : base(userService)
{
_backtester = backtester;
_adminService = adminService;
_logger = logger;
}
/// <summary>
/// Checks if the current user is an admin
/// </summary>
private async Task<bool> IsUserAdmin()
{
try
{
var user = await GetUser();
if (user == null)
return false;
return await _adminService.IsUserAdminAsync(user.Name);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error checking if user is admin");
return false;
}
}
/// <summary>
/// Retrieves paginated bundle backtest requests for admin users.
/// This endpoint returns all bundle backtest requests without user filtering.
/// </summary>
/// <param name="page">Page number (defaults to 1)</param>
/// <param name="pageSize">Number of items per page (defaults to 50, max 100)</param>
/// <param name="sortBy">Field to sort by (defaults to "CreatedAt")</param>
/// <param name="sortOrder">Sort order - "asc" or "desc" (defaults to "desc")</param>
/// <param name="nameContains">Filter by name contains</param>
/// <param name="status">Filter by status (Pending, Running, Completed, Failed, Saved)</param>
/// <param name="userId">Filter by user ID</param>
/// <param name="userNameContains">Filter by user name contains</param>
/// <param name="totalBacktestsMin">Filter by minimum total backtests</param>
/// <param name="totalBacktestsMax">Filter by maximum total backtests</param>
/// <param name="completedBacktestsMin">Filter by minimum completed backtests</param>
/// <param name="completedBacktestsMax">Filter by maximum completed backtests</param>
/// <param name="progressPercentageMin">Filter by minimum progress percentage (0-100)</param>
/// <param name="progressPercentageMax">Filter by maximum progress percentage (0-100)</param>
/// <param name="createdAtFrom">Filter by created date from</param>
/// <param name="createdAtTo">Filter by created date to</param>
/// <returns>A paginated list of bundle backtest requests.</returns>
[HttpGet]
[Route("BundleBacktestRequests/Paginated")]
public async Task<ActionResult<PaginatedBundleBacktestRequestsResponse>> GetBundleBacktestRequestsPaginated(
[FromQuery] int page = 1,
[FromQuery] int pageSize = 50,
[FromQuery] BundleBacktestRequestSortableColumn sortBy = BundleBacktestRequestSortableColumn.CreatedAt,
[FromQuery] string sortOrder = "desc",
[FromQuery] string? nameContains = null,
[FromQuery] BundleBacktestRequestStatus? status = null,
[FromQuery] int? userId = null,
[FromQuery] string? userNameContains = null,
[FromQuery] int? totalBacktestsMin = null,
[FromQuery] int? totalBacktestsMax = null,
[FromQuery] int? completedBacktestsMin = null,
[FromQuery] int? completedBacktestsMax = null,
[FromQuery] double? progressPercentageMin = null,
[FromQuery] double? progressPercentageMax = null,
[FromQuery] DateTime? createdAtFrom = null,
[FromQuery] DateTime? createdAtTo = null)
{
if (!await IsUserAdmin())
{
_logger.LogWarning("Non-admin user attempted to access admin bundle backtest requests endpoint");
return StatusCode(403, new { error = "Only admin users can access this endpoint" });
}
if (page < 1)
{
return BadRequest("Page must be greater than 0");
}
if (pageSize < 1 || pageSize > 100)
{
return BadRequest("Page size must be between 1 and 100");
}
if (sortOrder != "asc" && sortOrder != "desc")
{
return BadRequest("Sort order must be 'asc' or 'desc'");
}
// Validate progress percentage ranges [0,100]
if (progressPercentageMin.HasValue && (progressPercentageMin < 0 || progressPercentageMin > 100))
{
return BadRequest("progressPercentageMin must be between 0 and 100");
}
if (progressPercentageMax.HasValue && (progressPercentageMax < 0 || progressPercentageMax > 100))
{
return BadRequest("progressPercentageMax must be between 0 and 100");
}
if (progressPercentageMin.HasValue && progressPercentageMax.HasValue && progressPercentageMin > progressPercentageMax)
{
return BadRequest("progressPercentageMin must be less than or equal to progressPercentageMax");
}
// Build filter
var filter = new BundleBacktestRequestsFilter
{
NameContains = string.IsNullOrWhiteSpace(nameContains) ? null : nameContains.Trim(),
Status = status,
UserId = userId,
UserNameContains = string.IsNullOrWhiteSpace(userNameContains) ? null : userNameContains.Trim(),
TotalBacktestsMin = totalBacktestsMin,
TotalBacktestsMax = totalBacktestsMax,
CompletedBacktestsMin = completedBacktestsMin,
CompletedBacktestsMax = completedBacktestsMax,
ProgressPercentageMin = progressPercentageMin,
ProgressPercentageMax = progressPercentageMax,
CreatedAtFrom = createdAtFrom,
CreatedAtTo = createdAtTo
};
var (bundleRequests, totalCount) =
await _backtester.GetBundleBacktestRequestsPaginatedAsync(
page,
pageSize,
sortBy,
sortOrder,
filter);
var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize);
var response = new PaginatedBundleBacktestRequestsResponse
{
BundleRequests = bundleRequests.Select(b => new BundleBacktestRequestListItemResponse
{
RequestId = b.RequestId,
Name = b.Name,
Version = b.Version,
Status = b.Status.ToString(),
CreatedAt = b.CreatedAt,
CompletedAt = b.CompletedAt,
UpdatedAt = b.UpdatedAt,
TotalBacktests = b.TotalBacktests,
CompletedBacktests = b.CompletedBacktests,
FailedBacktests = b.FailedBacktests,
ProgressPercentage = b.ProgressPercentage,
UserId = b.User?.Id,
UserName = b.User?.Name,
ErrorMessage = b.ErrorMessage,
CurrentBacktest = b.CurrentBacktest,
EstimatedTimeRemainingSeconds = b.EstimatedTimeRemainingSeconds
}),
TotalCount = totalCount,
CurrentPage = page,
PageSize = pageSize,
TotalPages = totalPages,
HasNextPage = page < totalPages,
HasPreviousPage = page > 1
};
return Ok(response);
}
/// <summary>
/// Gets a summary of bundle backtest requests grouped by status with counts.
/// Admin only endpoint.
/// </summary>
/// <returns>Summary statistics of bundle backtest requests</returns>
[HttpGet]
[Route("BundleBacktestRequests/Summary")]
public async Task<ActionResult<BundleBacktestRequestSummaryResponse>> GetBundleBacktestRequestsSummary()
{
if (!await IsUserAdmin())
{
_logger.LogWarning("Non-admin user attempted to get bundle backtest requests summary");
return StatusCode(403, new { error = "Only admin users can access bundle backtest requests summary" });
}
var summary = await _backtester.GetBundleBacktestRequestsSummaryAsync();
var response = new BundleBacktestRequestSummaryResponse
{
StatusSummary = summary.StatusCounts.Select(s => new BundleBacktestRequestStatusSummary
{
Status = s.Status.ToString(),
Count = s.Count
}).ToList(),
TotalRequests = summary.TotalRequests
};
return Ok(response);
}
}