feat: добавил эндпоинт для получения статистики админского дашборда
Backend CI / build-and-test (push) Successful in 40s
Frontend CI / build-and-check (push) Failing after 19s
🚀 Create and publish a Docker image / Detect changes in backend and frontend (push) Successful in 6s
🚀 Create and publish a Docker image / Build & publish backend image (push) Successful in 24s
🚀 Create and publish a Docker image / Build & publish frontend image (push) Successful in 27s
🚀 Create and publish a Docker image / Update stack on Portainer (push) Successful in 5s

This commit is contained in:
2026-05-28 05:09:47 +03:00
parent e8f7a64d15
commit a8d51df3f1
8 changed files with 123 additions and 23 deletions
@@ -159,6 +159,19 @@ public class UsersController : ControllerBase
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<UserStatsDto>> Stats(int id) => Ok(await _users.GetStatsAsync(id));
/// <summary>Получить статистику для админского дашборда.</summary>
/// <remarks>Только Admin.</remarks>
/// <response code="200">Агрегированная статистика дашборда.</response>
/// <response code="401">Требуется аутентификация.</response>
/// <response code="403">Требуется роль Admin.</response>
[Authorize(Roles = "Admin")]
[HttpGet("admin/stats")]
[ProducesResponseType(typeof(AdminDashboardStatsDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<ActionResult<AdminDashboardStatsDto>> AdminStats() =>
Ok(await _users.GetAdminDashboardStatsAsync());
/// <summary>Получить список записей пользователя на лекции.</summary>
/// <remarks>Только Admin. Для текущего пользователя используйте GET /api/v1/users/me/enrollments.</remarks>
/// <param name="id">ID пользователя.</param>
+68
View File
@@ -4158,6 +4158,52 @@
]
}
},
"/api/v1/users/admin/stats": {
"get": {
"tags": [
"Users"
],
"summary": "Получить статистику для админского дашборда.",
"description": "Только Admin.\n\n**Required roles:** Admin",
"responses": {
"200": {
"description": "Агрегированная статистика дашборда.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AdminDashboardStatsDto"
}
}
}
},
"401": {
"description": "Требуется аутентификация.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"403": {
"description": "Требуется роль Admin.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
},
"security": [
{
"Bearer": [ ]
}
]
}
},
"/api/v1/users/{id}/enrollments": {
"get": {
"tags": [
@@ -4758,6 +4804,28 @@
},
"additionalProperties": false
},
"AdminDashboardStatsDto": {
"type": "object",
"properties": {
"usersCount": {
"type": "integer",
"format": "int32"
},
"lecturesCount": {
"type": "integer",
"format": "int32"
},
"enrollmentsCount": {
"type": "integer",
"format": "int32"
},
"pendingReviewsCount": {
"type": "integer",
"format": "int32"
}
},
"additionalProperties": false
},
"AuthResponse": {
"type": "object",
"properties": {
@@ -42,6 +42,13 @@ public record UserStatsDto(
IReadOnlyList<EnrollmentSlotRuleDto> EnrollmentSlotRules
);
public record AdminDashboardStatsDto(
int UsersCount,
int LecturesCount,
int EnrollmentsCount,
int PendingReviewsCount
);
public record EnrollmentSlotRuleDto(int Level, int Slots);
public record UpdateUserRequest(
@@ -10,6 +10,7 @@ public interface IUserService
Task<UserDto> GetByIdAsync(int id);
Task<UserDto> UpdateProfileAsync(int id, UpdateUserRequest request);
Task<UserStatsDto> GetStatsAsync(int id);
Task<AdminDashboardStatsDto> GetAdminDashboardStatsAsync();
Task<PagedResult<LectureDto>> GetEnrollmentsAsync(int id, PaginationRequest pagination);
Task<PagedResult<UserDto>> GetAllAsync(UserFilterRequest filter);
Task SetRolesAsync(int id, IReadOnlyCollection<UserRole> roles);
@@ -74,6 +74,17 @@ public class UserService : IUserService
);
}
public async Task<AdminDashboardStatsDto> GetAdminDashboardStatsAsync()
{
var usersCount = await _db.Users
.CountAsync(user => !user.Roles.Any(role => role.Role == UserRole.Teacher));
var lecturesCount = await _db.Lectures.CountAsync();
var enrollmentsCount = await _db.LectureEnrollments.CountAsync();
var pendingReviewsCount = await _db.Reviews.CountAsync(review => review.LlmStatus == ReviewLlmStatus.Pending);
return new AdminDashboardStatsDto(usersCount, lecturesCount, enrollmentsCount, pendingReviewsCount);
}
public async Task<PagedResult<LectureDto>> GetEnrollmentsAsync(int id, PaginationRequest pagination)
{
if (!await _db.Users.AnyAsync(u => u.Id == id))