Add paginated user retrieval functionality in AdminController and related services. Implemented UsersFilter for filtering user queries and added LastConnectionDate property to User model. Updated database schema and frontend API to support new user management features.

This commit is contained in:
2025-11-17 20:04:17 +07:00
parent 06ef33b7ab
commit 02e46e8d0d
20 changed files with 2559 additions and 6 deletions

View File

@@ -263,5 +263,94 @@ public class AdminController : BaseController
RelatedBacktestsDeleted = backtestsDeleted
});
}
/// <summary>
/// Retrieves paginated users for admin users.
/// This endpoint returns all users with all their properties.
/// </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 "Id")</param>
/// <param name="sortOrder">Sort order - "asc" or "desc" (defaults to "desc")</param>
/// <param name="userNameContains">Filter by user name contains</param>
/// <param name="ownerAddressContains">Filter by owner address contains</param>
/// <param name="agentNameContains">Filter by agent name contains</param>
/// <param name="telegramChannelContains">Filter by telegram channel contains</param>
/// <returns>A paginated list of users.</returns>
[HttpGet]
[Route("Users/Paginated")]
public async Task<ActionResult<PaginatedUsersResponse>> GetUsersPaginated(
[FromQuery] int page = 1,
[FromQuery] int pageSize = 50,
[FromQuery] UserSortableColumn sortBy = UserSortableColumn.Id,
[FromQuery] string sortOrder = "desc",
[FromQuery] string? userNameContains = null,
[FromQuery] string? ownerAddressContains = null,
[FromQuery] string? agentNameContains = null,
[FromQuery] string? telegramChannelContains = null)
{
if (!await IsUserAdmin())
{
_logger.LogWarning("Non-admin user attempted to access admin users 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'");
}
// Build filter
var filter = new UsersFilter
{
UserNameContains = string.IsNullOrWhiteSpace(userNameContains) ? null : userNameContains.Trim(),
OwnerAddressContains = string.IsNullOrWhiteSpace(ownerAddressContains) ? null : ownerAddressContains.Trim(),
AgentNameContains = string.IsNullOrWhiteSpace(agentNameContains) ? null : agentNameContains.Trim(),
TelegramChannelContains = string.IsNullOrWhiteSpace(telegramChannelContains) ? null : telegramChannelContains.Trim()
};
var (users, totalCount) =
await _userService.GetUsersPaginatedAsync(
page,
pageSize,
sortBy,
sortOrder,
filter);
var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize);
var response = new PaginatedUsersResponse
{
Users = users.Select(u => new UserListItemResponse
{
Id = u.Id,
Name = u.Name,
AgentName = u.AgentName,
AvatarUrl = u.AvatarUrl,
TelegramChannel = u.TelegramChannel,
OwnerWalletAddress = u.OwnerWalletAddress,
IsAdmin = u.IsAdmin,
LastConnectionDate = u.LastConnectionDate
}),
TotalCount = totalCount,
CurrentPage = page,
PageSize = pageSize,
TotalPages = totalPages,
HasNextPage = page < totalPages,
HasPreviousPage = page > 1
};
return Ok(response);
}
}

View File

@@ -42,6 +42,47 @@ public class PaginatedBundleBacktestRequestsResponse
public bool HasPreviousPage { get; set; }
}
/// <summary>
/// Response model for paginated users
/// </summary>
public class PaginatedUsersResponse
{
/// <summary>
/// The list of users for the current page
/// </summary>
public IEnumerable<UserListItemResponse> Users { get; set; } = new List<UserListItemResponse>();
/// <summary>
/// Total number of users across all pages
/// </summary>
public int TotalCount { get; set; }
/// <summary>
/// Current page number
/// </summary>
public int CurrentPage { get; set; }
/// <summary>
/// Number of items per page
/// </summary>
public int PageSize { get; set; }
/// <summary>
/// Total number of pages
/// </summary>
public int TotalPages { get; set; }
/// <summary>
/// Whether there are more pages available
/// </summary>
public bool HasNextPage { get; set; }
/// <summary>
/// Whether there are previous pages available
/// </summary>
public bool HasPreviousPage { get; set; }
}
/// <summary>
/// Response model for a bundle backtest request list item (summary view)
/// </summary>
@@ -65,4 +106,19 @@ public class BundleBacktestRequestListItemResponse
public int? EstimatedTimeRemainingSeconds { get; set; }
}
/// <summary>
/// Response model for a user list item (summary view)
/// </summary>
public class UserListItemResponse
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string AgentName { get; set; } = string.Empty;
public string AvatarUrl { get; set; } = string.Empty;
public string TelegramChannel { get; set; } = string.Empty;
public string OwnerWalletAddress { get; set; } = string.Empty;
public bool IsAdmin { get; set; }
public DateTimeOffset? LastConnectionDate { get; set; }
}