feat: expand platform management, admin controls, and learning workflows

这个提交包含在:
Codex CLI
2026-02-15 15:41:56 +08:00
父节点 ad29a9f62d
当前提交 f209ae82da
修改 75 个文件,包含 9663 行新增794 行删除

查看文件

@@ -9,10 +9,12 @@
#include "csp/services/problem_solution_runner.h"
#include "csp/services/problem_workspace_service.h"
#include "csp/services/submission_service.h"
#include "csp/services/user_service.h"
#include "http_auth.h"
#include <algorithm>
#include <exception>
#include <optional>
#include <string>
namespace csp::controllers {
@@ -47,6 +49,25 @@ int ParsePositiveInt(const std::string& s,
return std::max(min_value, std::min(max_value, v));
}
std::optional<int64_t> RequireAdminUserId(
const drogon::HttpRequestPtr& req,
std::function<void(const drogon::HttpResponsePtr&)>& cb) {
std::string auth_error;
const auto user_id = GetAuthedUserId(req, auth_error);
if (!user_id.has_value()) {
cb(JsonError(drogon::k401Unauthorized, auth_error));
return std::nullopt;
}
services::UserService users(csp::AppState::Instance().db());
const auto user = users.GetById(*user_id);
if (!user.has_value() || user->username != "admin") {
cb(JsonError(drogon::k403Forbidden, "admin only"));
return std::nullopt;
}
return user_id;
}
Json::Value BuildOpenApiSpec() {
Json::Value root;
root["openapi"] = "3.1.0";
@@ -173,6 +194,8 @@ void MetaController::backendLogs(
const drogon::HttpRequestPtr& req,
std::function<void(const drogon::HttpResponsePtr&)>&& cb) {
try {
if (!RequireAdminUserId(req, cb).has_value()) return;
const int limit =
ParsePositiveInt(req->getParameter("limit"), 100, 1, 500);
const int running_limit =
@@ -274,9 +297,11 @@ void MetaController::backendLogs(
}
void MetaController::kbRefreshStatus(
const drogon::HttpRequestPtr& /*req*/,
const drogon::HttpRequestPtr& req,
std::function<void(const drogon::HttpResponsePtr&)>&& cb) {
try {
if (!RequireAdminUserId(req, cb).has_value()) return;
const auto& runner = services::KbImportRunner::Instance();
Json::Value payload;
payload["running"] = runner.IsRunning();
@@ -299,12 +324,7 @@ void MetaController::triggerKbRefresh(
const drogon::HttpRequestPtr& req,
std::function<void(const drogon::HttpResponsePtr&)>&& cb) {
try {
std::string auth_error;
const auto user_id = GetAuthedUserId(req, auth_error);
if (!user_id.has_value()) {
cb(JsonError(drogon::k401Unauthorized, auth_error));
return;
}
if (!RequireAdminUserId(req, cb).has_value()) return;
auto& runner = services::KbImportRunner::Instance();
const bool started = runner.TriggerAsync("manual");
@@ -332,12 +352,8 @@ void MetaController::triggerMissingSolutions(
const drogon::HttpRequestPtr& req,
std::function<void(const drogon::HttpResponsePtr&)>&& cb) {
try {
std::string auth_error;
const auto user_id = GetAuthedUserId(req, auth_error);
if (!user_id.has_value()) {
cb(JsonError(drogon::k401Unauthorized, auth_error));
return;
}
const auto user_id = RequireAdminUserId(req, cb);
if (!user_id.has_value()) return;
int limit = 50000;
int max_solutions = 3;