beeta/backend/src/controllers/AdminController.cpp

181 lines
7.2 KiB
C++
Raw Normal View History

2025-08-03 21:53:15 -04:00
#include "AdminController.h"
#include "../services/OmeClient.h"
#include "../services/RedisHelper.h"
using namespace drogon::orm;
namespace {
HttpResponsePtr jsonResp(const Json::Value& j, HttpStatusCode c = k200OK) {
auto r = HttpResponse::newHttpJsonResponse(j);
r->setStatusCode(c);
return r;
}
HttpResponsePtr jsonError(const std::string& error, HttpStatusCode code = k400BadRequest) {
Json::Value j;
j["success"] = false;
j["error"] = error;
return jsonResp(j, code);
}
}
UserInfo AdminController::getUserFromRequest(const HttpRequestPtr &req) {
UserInfo user;
std::string auth = req->getHeader("Authorization");
if (auth.empty() || auth.substr(0, 7) != "Bearer ") {
return user;
}
std::string token = auth.substr(7);
AuthService::getInstance().validateToken(token, user);
return user;
}
void AdminController::getUsers(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback) {
UserInfo user = getUserFromRequest(req);
if (user.id == 0 || !user.isAdmin) {
callback(jsonError("Unauthorized", k403Forbidden));
return;
}
auto dbClient = app().getDbClient();
*dbClient << "SELECT u.id, u.username, u.is_admin, u.is_streamer, u.created_at, "
"(SELECT COUNT(*) FROM realms WHERE user_id = u.id) as realm_count "
"FROM users u ORDER BY u.created_at DESC"
>> [callback](const Result& r) {
Json::Value resp;
resp["success"] = true;
Json::Value users(Json::arrayValue);
for (const auto& row : r) {
Json::Value user;
user["id"] = static_cast<Json::Int64>(row["id"].as<int64_t>());
user["username"] = row["username"].as<std::string>();
user["isAdmin"] = row["is_admin"].as<bool>();
user["isStreamer"] = row["is_streamer"].as<bool>();
user["createdAt"] = row["created_at"].as<std::string>();
user["realmCount"] = static_cast<Json::Int64>(row["realm_count"].as<int64_t>());
users.append(user);
}
resp["users"] = users;
callback(jsonResp(resp));
}
>> [callback](const DrogonDbException& e) {
LOG_ERROR << "Failed to get users: " << e.base().what();
callback(jsonError("Failed to get users"));
};
}
void AdminController::getActiveStreams(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback) {
UserInfo user = getUserFromRequest(req);
if (user.id == 0 || !user.isAdmin) {
callback(jsonError("Unauthorized", k403Forbidden));
return;
}
// Get live realms from database
auto dbClient = app().getDbClient();
*dbClient << "SELECT r.id, r.name, r.stream_key, r.viewer_count, "
"u.username FROM realms r "
"JOIN users u ON r.user_id = u.id "
"WHERE r.is_live = true"
>> [callback](const Result& r) {
Json::Value resp;
resp["success"] = true;
Json::Value streams(Json::arrayValue);
for (const auto& row : r) {
Json::Value stream;
stream["id"] = static_cast<Json::Int64>(row["id"].as<int64_t>());
stream["name"] = row["name"].as<std::string>();
stream["streamKey"] = row["stream_key"].as<std::string>();
stream["viewerCount"] = static_cast<Json::Int64>(row["viewer_count"].as<int64_t>());
stream["username"] = row["username"].as<std::string>();
streams.append(stream);
}
resp["streams"] = streams;
callback(jsonResp(resp));
}
>> [callback](const DrogonDbException& e) {
LOG_ERROR << "Failed to get active streams: " << e.base().what();
callback(jsonError("Failed to get active streams"));
};
}
void AdminController::disconnectStream(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
const std::string &streamKey) {
UserInfo user = getUserFromRequest(req);
if (user.id == 0 || !user.isAdmin) {
callback(jsonError("Unauthorized", k403Forbidden));
return;
}
// Add to Redis set for OpenResty to disconnect
RedisHelper::addToSet("streams_to_disconnect", streamKey);
// Also try direct disconnect
OmeClient::getInstance().disconnectStream(streamKey, [callback](bool) {
Json::Value resp;
resp["success"] = true;
resp["message"] = "Stream disconnect initiated";
callback(jsonResp(resp));
});
}
void AdminController::promoteToStreamer(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
const std::string &userId) {
UserInfo user = getUserFromRequest(req);
if (user.id == 0 || !user.isAdmin) {
callback(jsonError("Unauthorized", k403Forbidden));
return;
}
int64_t targetUserId = std::stoll(userId);
auto dbClient = app().getDbClient();
*dbClient << "UPDATE users SET is_streamer = true WHERE id = $1"
<< targetUserId
>> [callback](const Result&) {
Json::Value resp;
resp["success"] = true;
resp["message"] = "User promoted to streamer";
callback(jsonResp(resp));
}
>> [callback](const DrogonDbException& e) {
LOG_ERROR << "Failed to promote user: " << e.base().what();
callback(jsonError("Failed to promote user"));
};
}
void AdminController::demoteFromStreamer(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
const std::string &userId) {
UserInfo user = getUserFromRequest(req);
if (user.id == 0 || !user.isAdmin) {
callback(jsonError("Unauthorized", k403Forbidden));
return;
}
int64_t targetUserId = std::stoll(userId);
auto dbClient = app().getDbClient();
*dbClient << "UPDATE users SET is_streamer = false WHERE id = $1"
<< targetUserId
>> [callback](const Result&) {
Json::Value resp;
resp["success"] = true;
resp["message"] = "User demoted from streamer";
callback(jsonResp(resp));
}
>> [callback](const DrogonDbException& e) {
LOG_ERROR << "Failed to demote user: " << e.base().what();
callback(jsonError("Failed to demote user"));
};
}