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

@@ -0,0 +1,29 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Managing.Infrastructure.Databases.Migrations
{
/// <inheritdoc />
public partial class AddLastConnectionDateToUsers : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<DateTimeOffset>(
name: "LastConnectionDate",
table: "Users",
type: "timestamp with time zone",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "LastConnectionDate",
table: "Users");
}
}
}

View File

@@ -1413,6 +1413,9 @@ namespace Managing.Infrastructure.Databases.Migrations
b.Property<bool>("IsAdmin")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("LastConnectionDate")
.HasColumnType("timestamp with time zone");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(255)

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));
}
}