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

@@ -14,6 +14,7 @@ public class UserEntity
public string? AvatarUrl { get; set; }
public string? TelegramChannel { get; set; }
public string? OwnerWalletAddress { get; set; }
public DateTimeOffset? LastConnectionDate { get; set; }
public bool IsAdmin { get; set; }
// Navigation properties

View File

@@ -1,10 +1,12 @@
using Managing.Application.Abstractions.Repositories;
using Managing.Application.Abstractions.Services;
using Managing.Application.Abstractions.Shared;
using Managing.Domain.Accounts;
using Managing.Domain.Users;
using Managing.Infrastructure.Databases.PostgreSql.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using static Managing.Common.Enums;
namespace Managing.Infrastructure.Databases.PostgreSql;
@@ -318,4 +320,77 @@ public class PostgreSqlUserRepository : BaseRepositoryWithLogging, IUserReposito
}
}, nameof(SaveOrUpdateUserAsync), ("userName", user.Name), ("userId", user.Id));
}
public async Task<(IEnumerable<User> Users, int TotalCount)> GetUsersPaginatedAsync(int page, int pageSize, UserSortableColumn sortBy, string sortOrder, UsersFilter filter)
{
return await ExecuteWithLoggingAsync(async () =>
{
try
{
await PostgreSqlConnectionHelper.EnsureConnectionOpenAsync(_context);
var query = _context.Users.AsNoTracking();
// Apply filters
if (!string.IsNullOrWhiteSpace(filter.UserNameContains))
{
query = query.Where(u => EF.Functions.ILike(u.Name, $"%{filter.UserNameContains.Trim()}%"));
}
if (!string.IsNullOrWhiteSpace(filter.OwnerAddressContains))
{
query = query.Where(u => EF.Functions.ILike(u.OwnerWalletAddress, $"%{filter.OwnerAddressContains.Trim()}%"));
}
if (!string.IsNullOrWhiteSpace(filter.AgentNameContains))
{
query = query.Where(u => EF.Functions.ILike(u.AgentName, $"%{filter.AgentNameContains.Trim()}%"));
}
if (!string.IsNullOrWhiteSpace(filter.TelegramChannelContains))
{
query = query.Where(u => EF.Functions.ILike(u.TelegramChannel, $"%{filter.TelegramChannelContains.Trim()}%"));
}
// Get total count for pagination
var totalCount = await query.CountAsync().ConfigureAwait(false);
// Apply sorting
query = sortBy switch
{
UserSortableColumn.Id => sortOrder.ToLower() == "desc" ? query.OrderByDescending(u => u.Id) : query.OrderBy(u => u.Id),
UserSortableColumn.Name => sortOrder.ToLower() == "desc" ? query.OrderByDescending(u => u.Name) : query.OrderBy(u => u.Name),
UserSortableColumn.OwnerWalletAddress => sortOrder.ToLower() == "desc" ? query.OrderByDescending(u => u.OwnerWalletAddress) : query.OrderBy(u => u.OwnerWalletAddress),
UserSortableColumn.AgentName => sortOrder.ToLower() == "desc" ? query.OrderByDescending(u => u.AgentName) : query.OrderBy(u => u.AgentName),
_ => query.OrderBy(u => u.Id) // Default sorting
};
// Apply pagination
var users = await query
.Skip((page - 1) * pageSize)
.Take(pageSize)
.Select(u => new UserEntity
{
Id = u.Id,
Name = u.Name,
AgentName = u.AgentName,
AvatarUrl = u.AvatarUrl,
TelegramChannel = u.TelegramChannel,
OwnerWalletAddress = u.OwnerWalletAddress,
IsAdmin = u.IsAdmin,
LastConnectionDate = u.LastConnectionDate
})
.ToListAsync()
.ConfigureAwait(false);
var domainUsers = users.Select(PostgreSqlMappers.Map).ToList();
return (domainUsers, totalCount);
}
finally
{
await PostgreSqlConnectionHelper.SafeCloseConnectionAsync(_context);
}
}, nameof(GetUsersPaginatedAsync), ("page", page), ("pageSize", pageSize), ("sortBy", sortBy), ("sortOrder", sortOrder));
}
}