Files
DarkflameServer/dDatabase/GameDatabase/SQLite/Tables/ServerOperations.cpp
Aaron Kimbrell e213a7aeff feat: web dashboard and playground work
The NexusDashboard-parity dashboard (dDashboardServer) and everything built on it on the experimental branch:
accounts, characters, properties and moderation tools, permissions shared with in-game slash commands, economy
reports, World 3D and property 3D views with client scenery, scheduled events (features, vanity changes, live
events, announcements, restarts), vanity files and events, the CDClient browser, the message inspector with saved
captures, chat filter tools, community challenges, live ops, the AI moderator helper, and the server-side changes
they need.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:30:43 -05:00

141 lines
7.1 KiB
C++

#include "SQLiteDatabase.h"
#include "GeneralUtils.h"
namespace {
std::string JoinZones(const std::vector<uint32_t>& zones) {
std::string text;
for (const auto zone : zones) text += (text.empty() ? "" : ",") + std::to_string(zone);
return text;
}
std::vector<uint32_t> SplitZones(const std::string& text) {
std::vector<uint32_t> zones;
for (const auto& part : GeneralUtils::SplitString(text, ',')) {
if (const auto zone = GeneralUtils::TryParse<uint32_t>(part)) zones.push_back(*zone);
}
return zones;
}
IServerOperations::ScheduledAnnouncement ReadAnnouncement(CppSQLite3Query& result) {
IServerOperations::ScheduledAnnouncement row;
row.id = static_cast<uint64_t>(result.getInt64Field("id"));
row.title = result.getStringField("title");
row.message = result.getStringField("message");
row.zones = SplitZones(result.getStringField("zones"));
row.schedule = result.getStringField("schedule");
row.startsAt = result.getInt64Field("starts_at");
row.endsAt = result.getInt64Field("ends_at");
row.enabled = result.getIntField("enabled") != 0;
row.lastSentAt = result.getInt64Field("last_sent_at");
row.sentCount = static_cast<uint32_t>(result.getIntField("sent_count"));
row.createdAt = result.getInt64Field("created_at");
row.createdBy = result.getStringField("created_by");
row.updatedAt = result.getInt64Field("updated_at");
row.updatedBy = result.getStringField("updated_by");
return row;
}
IServerOperations::ScheduledEvent ReadEvent(CppSQLite3Query& result) {
IServerOperations::ScheduledEvent row;
row.id = static_cast<uint64_t>(result.getInt64Field("id"));
row.name = result.getStringField("name");
row.note = result.getStringField("note");
row.mode = static_cast<uint8_t>(result.getIntField("mode"));
row.schedule = result.getStringField("schedule");
row.startsAt = result.getInt64Field("starts_at");
row.endsAt = result.getInt64Field("ends_at");
row.priority = result.getIntField("priority");
row.parts = result.getStringField("parts");
row.state = static_cast<IServerOperations::eEventState>(result.getIntField("state"));
row.status = result.getStringField("status");
row.createdAt = result.getInt64Field("created_at");
row.createdBy = result.getStringField("created_by");
row.updatedAt = result.getInt64Field("updated_at");
row.updatedBy = result.getStringField("updated_by");
return row;
}
}
std::vector<IServerOperations::ScheduledAnnouncement> SQLiteDatabase::GetScheduledAnnouncements() {
std::vector<ScheduledAnnouncement> rows;
auto [_, result] = ExecuteSelect("SELECT * FROM scheduled_announcements ORDER BY id;");
for (; !result.eof(); result.nextRow()) rows.push_back(ReadAnnouncement(result));
return rows;
}
uint64_t SQLiteDatabase::InsertScheduledAnnouncement(const ScheduledAnnouncement& row) {
ExecuteInsert("INSERT INTO scheduled_announcements (title, message, zones, schedule, starts_at, ends_at, enabled, created_at, created_by, updated_at, updated_by) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);",
row.title, row.message, JoinZones(row.zones), row.schedule, row.startsAt, row.endsAt, row.enabled, row.createdAt, row.createdBy, row.updatedAt, row.updatedBy);
auto [_, result] = ExecuteSelect("SELECT last_insert_rowid() AS id;");
return result.eof() ? 0 : static_cast<uint64_t>(result.getInt64Field("id"));
}
void SQLiteDatabase::UpdateScheduledAnnouncement(const ScheduledAnnouncement& row) {
ExecuteUpdate("UPDATE scheduled_announcements SET title = ?, message = ?, zones = ?, schedule = ?, starts_at = ?, ends_at = ?, enabled = ?, updated_at = ?, updated_by = ? WHERE id = ?;",
row.title, row.message, JoinZones(row.zones), row.schedule, row.startsAt, row.endsAt, row.enabled, row.updatedAt, row.updatedBy, static_cast<int64_t>(row.id));
}
void SQLiteDatabase::MarkAnnouncementSent(uint64_t id, int64_t time) {
ExecuteUpdate("UPDATE scheduled_announcements SET last_sent_at = ?, sent_count = sent_count + 1 WHERE id = ?;", time, static_cast<int64_t>(id));
}
void SQLiteDatabase::DeleteScheduledAnnouncement(uint64_t id) {
ExecuteDelete("DELETE FROM scheduled_announcements WHERE id = ?;", static_cast<int64_t>(id));
}
std::vector<IServerOperations::ScheduledEvent> SQLiteDatabase::GetScheduledEvents() {
std::vector<ScheduledEvent> rows;
auto [_, result] = ExecuteSelect("SELECT * FROM scheduled_events ORDER BY id;");
for (; !result.eof(); result.nextRow()) rows.push_back(ReadEvent(result));
return rows;
}
uint64_t SQLiteDatabase::InsertScheduledEvent(const ScheduledEvent& row) {
ExecuteInsert("INSERT INTO scheduled_events (feature, name, note, mode, schedule, starts_at, ends_at, priority, parts, state, status, created_at, created_by, updated_at, updated_by) "
"VALUES ('', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);",
row.name, row.note, static_cast<uint32_t>(row.mode), row.schedule, row.startsAt, row.endsAt, row.priority, row.parts, static_cast<uint8_t>(row.state), row.status,
row.createdAt, row.createdBy, row.updatedAt, row.updatedBy);
auto [_, result] = ExecuteSelect("SELECT last_insert_rowid() AS id;");
return result.eof() ? 0 : static_cast<uint64_t>(result.getInt64Field("id"));
}
void SQLiteDatabase::UpdateScheduledEvent(const ScheduledEvent& row) {
ExecuteUpdate("UPDATE scheduled_events SET name = ?, note = ?, mode = ?, schedule = ?, starts_at = ?, ends_at = ?, priority = ?, parts = ?, state = ?, status = ?, "
"updated_at = ?, updated_by = ? WHERE id = ?;",
row.name, row.note, static_cast<uint32_t>(row.mode), row.schedule, row.startsAt, row.endsAt, row.priority, row.parts, static_cast<uint8_t>(row.state), row.status,
row.updatedAt, row.updatedBy, static_cast<int64_t>(row.id));
}
void SQLiteDatabase::DeleteScheduledEvent(uint64_t id) {
ExecuteDelete("DELETE FROM scheduled_events WHERE id = ?;", static_cast<int64_t>(id));
}
std::vector<IServerOperations::ZoneLimit> SQLiteDatabase::GetZoneLimits() {
std::vector<ZoneLimit> rows;
auto [_, result] = ExecuteSelect("SELECT * FROM zone_limits ORDER BY zone_id;");
for (; !result.eof(); result.nextRow()) {
ZoneLimit row;
row.zoneId = static_cast<uint32_t>(result.getIntField("zone_id"));
if (!result.fieldIsNull("soft_cap")) row.softCap = static_cast<uint32_t>(result.getIntField("soft_cap"));
if (!result.fieldIsNull("hard_cap")) row.hardCap = static_cast<uint32_t>(result.getIntField("hard_cap"));
row.spareInstances = static_cast<uint32_t>(result.getIntField("spare_instances"));
row.updatedAt = result.getInt64Field("updated_at");
row.updatedBy = result.getStringField("updated_by");
rows.push_back(std::move(row));
}
return rows;
}
void SQLiteDatabase::SetZoneLimit(const ZoneLimit& row) {
ExecuteInsert("INSERT INTO zone_limits (zone_id, soft_cap, hard_cap, spare_instances, updated_at, updated_by) VALUES (?, ?, ?, ?, ?, ?) "
"ON CONFLICT(zone_id) DO UPDATE SET soft_cap = excluded.soft_cap, hard_cap = excluded.hard_cap, spare_instances = excluded.spare_instances, "
"updated_at = excluded.updated_at, updated_by = excluded.updated_by;",
row.zoneId, row.softCap, row.hardCap, row.spareInstances, row.updatedAt, row.updatedBy);
}
void SQLiteDatabase::DeleteZoneLimit(uint32_t zoneId) {
ExecuteDelete("DELETE FROM zone_limits WHERE zone_id = ?;", zoneId);
}