mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2025-09-27 10:30:06 +00:00
[refactor] Split Database.cpp into db subdirectory
* Database.hpp is still the only external include file (moved to db/) * The header is still uppercase to match its namespace * db/internal.hpp is the shared header for the DB source files * Added -Isrc/ compile flag for src-relative include paths * Hoisted CHDR above CSRC in Makefile (it was bothering me) * make clean now removes all objects in the subdirectories as well
This commit is contained in:
335
src/db/email.cpp
Normal file
335
src/db/email.cpp
Normal file
@@ -0,0 +1,335 @@
|
||||
#include "db/internal.hpp"
|
||||
|
||||
// Email-related DB interactions
|
||||
|
||||
int Database::getUnreadEmailCount(int playerID) {
|
||||
std::lock_guard<std::mutex> lock(dbCrit);
|
||||
|
||||
const char* sql = R"(
|
||||
SELECT COUNT(*) FROM EmailData
|
||||
WHERE PlayerID = ? AND ReadFlag = 0;
|
||||
)";
|
||||
sqlite3_stmt* stmt;
|
||||
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||
sqlite3_bind_int(stmt, 1, playerID);
|
||||
sqlite3_step(stmt);
|
||||
int ret = sqlite3_column_int(stmt, 0);
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<EmailData> Database::getEmails(int playerID, int page) {
|
||||
std::lock_guard<std::mutex> lock(dbCrit);
|
||||
|
||||
std::vector<EmailData> emails;
|
||||
|
||||
const char* sql = R"(
|
||||
SELECT
|
||||
MsgIndex, ItemFlag, ReadFlag, SenderID,
|
||||
SenderFirstName, SenderLastName, SubjectLine,
|
||||
MsgBody, Taros, SendTime, DeleteTime
|
||||
FROM EmailData
|
||||
WHERE PlayerID = ?
|
||||
ORDER BY MsgIndex DESC
|
||||
LIMIT 5
|
||||
OFFSET ?;
|
||||
)";
|
||||
sqlite3_stmt* stmt;
|
||||
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||
sqlite3_bind_int(stmt, 1, playerID);
|
||||
int offset = 5 * page - 5;
|
||||
sqlite3_bind_int(stmt, 2, offset);
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
EmailData toAdd;
|
||||
toAdd.PlayerId = playerID;
|
||||
toAdd.MsgIndex = sqlite3_column_int(stmt, 0);
|
||||
toAdd.ItemFlag = sqlite3_column_int(stmt, 1);
|
||||
toAdd.ReadFlag = sqlite3_column_int(stmt, 2);
|
||||
toAdd.SenderId = sqlite3_column_int(stmt, 3);
|
||||
toAdd.SenderFirstName = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4)));
|
||||
toAdd.SenderLastName = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 5)));
|
||||
toAdd.SubjectLine = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 6)));
|
||||
toAdd.MsgBody = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 7)));
|
||||
toAdd.Taros = sqlite3_column_int(stmt, 8);
|
||||
toAdd.SendTime = sqlite3_column_int64(stmt, 9);
|
||||
toAdd.DeleteTime = sqlite3_column_int64(stmt, 10);
|
||||
|
||||
emails.push_back(toAdd);
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
return emails;
|
||||
}
|
||||
|
||||
EmailData Database::getEmail(int playerID, int index) {
|
||||
std::lock_guard<std::mutex> lock(dbCrit);
|
||||
|
||||
const char* sql = R"(
|
||||
SELECT
|
||||
ItemFlag, ReadFlag, SenderID, SenderFirstName,
|
||||
SenderLastName, SubjectLine, MsgBody,
|
||||
Taros, SendTime, DeleteTime
|
||||
FROM EmailData
|
||||
WHERE PlayerID = ? AND MsgIndex = ?;
|
||||
)";
|
||||
sqlite3_stmt* stmt;
|
||||
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||
sqlite3_bind_int(stmt, 1, playerID);
|
||||
sqlite3_bind_int(stmt, 2, index);
|
||||
|
||||
EmailData result;
|
||||
if (sqlite3_step(stmt) != SQLITE_ROW) {
|
||||
std::cout << "[WARN] Database: Email not found!" << std::endl;
|
||||
sqlite3_finalize(stmt);
|
||||
return result;
|
||||
}
|
||||
|
||||
result.PlayerId = playerID;
|
||||
result.MsgIndex = index;
|
||||
result.ItemFlag = sqlite3_column_int(stmt, 0);
|
||||
result.ReadFlag = sqlite3_column_int(stmt, 1);
|
||||
result.SenderId = sqlite3_column_int(stmt, 2);
|
||||
result.SenderFirstName = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)));
|
||||
result.SenderLastName = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4)));
|
||||
result.SubjectLine = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 5)));
|
||||
result.MsgBody = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 6)));
|
||||
result.Taros = sqlite3_column_int(stmt, 7);
|
||||
result.SendTime = sqlite3_column_int64(stmt, 8);
|
||||
result.DeleteTime = sqlite3_column_int64(stmt, 9);
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
return result;
|
||||
}
|
||||
|
||||
sItemBase* Database::getEmailAttachments(int playerID, int index) {
|
||||
std::lock_guard<std::mutex> lock(dbCrit);
|
||||
|
||||
sItemBase* items = new sItemBase[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
items[i] = { 0, 0, 0, 0 };
|
||||
|
||||
const char* sql = R"(
|
||||
SELECT Slot, ID, Type, Opt, TimeLimit
|
||||
FROM EmailItems
|
||||
WHERE PlayerID = ? AND MsgIndex = ?;
|
||||
)";
|
||||
sqlite3_stmt* stmt;
|
||||
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||
sqlite3_bind_int(stmt, 1, playerID);
|
||||
sqlite3_bind_int(stmt, 2, index);
|
||||
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
int slot = sqlite3_column_int(stmt, 0) - 1;
|
||||
if (slot < 0 || slot > 3) {
|
||||
std::cout << "[WARN] Email item has invalid slot number ?!" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
items[slot].iID = sqlite3_column_int(stmt, 1);
|
||||
items[slot].iType = sqlite3_column_int(stmt, 2);
|
||||
items[slot].iOpt = sqlite3_column_int(stmt, 3);
|
||||
items[slot].iTimeLimit = sqlite3_column_int(stmt, 4);
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
return items;
|
||||
}
|
||||
|
||||
void Database::updateEmailContent(EmailData* data) {
|
||||
std::lock_guard<std::mutex> lock(dbCrit);
|
||||
|
||||
const char* sql = R"(
|
||||
SELECT COUNT(*)
|
||||
FROM EmailItems
|
||||
WHERE PlayerID = ? AND MsgIndex = ?;
|
||||
)";
|
||||
sqlite3_stmt* stmt;
|
||||
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||
sqlite3_bind_int(stmt, 1, data->PlayerId);
|
||||
sqlite3_bind_int(stmt, 2, data->MsgIndex);
|
||||
sqlite3_step(stmt);
|
||||
int attachmentsCount = sqlite3_column_int(stmt, 0);
|
||||
|
||||
data->ItemFlag = (data->Taros > 0 || attachmentsCount > 0) ? 1 : 0; // set attachment flag dynamically
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
sql = R"(
|
||||
UPDATE EmailData
|
||||
SET
|
||||
PlayerID = ?,
|
||||
MsgIndex = ?,
|
||||
ReadFlag = ?,
|
||||
ItemFlag = ?,
|
||||
SenderID = ?,
|
||||
SenderFirstName = ?,
|
||||
SenderLastName = ?,
|
||||
SubjectLine = ?,
|
||||
MsgBody = ?,
|
||||
Taros = ?,
|
||||
SendTime = ?,
|
||||
DeleteTime = ?
|
||||
WHERE PlayerID = ? AND MsgIndex = ?;
|
||||
)";
|
||||
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||
sqlite3_bind_int(stmt, 1, data->PlayerId);
|
||||
sqlite3_bind_int(stmt, 2, data->MsgIndex);
|
||||
sqlite3_bind_int(stmt, 3, data->ReadFlag);
|
||||
sqlite3_bind_int(stmt, 4, data->ItemFlag);
|
||||
sqlite3_bind_int(stmt, 5, data->SenderId);
|
||||
sqlite3_bind_text(stmt, 6, data->SenderFirstName.c_str(), -1, NULL);
|
||||
sqlite3_bind_text(stmt, 7, data->SenderLastName.c_str(), -1, NULL);
|
||||
sqlite3_bind_text(stmt, 8, data->SubjectLine.c_str(), -1, NULL);
|
||||
sqlite3_bind_text(stmt, 9, data->MsgBody.c_str(), -1, NULL);
|
||||
sqlite3_bind_int(stmt, 10, data->Taros);
|
||||
sqlite3_bind_int64(stmt, 11, data->SendTime);
|
||||
sqlite3_bind_int64(stmt, 12, data->DeleteTime);
|
||||
sqlite3_bind_int(stmt, 13, data->PlayerId);
|
||||
sqlite3_bind_int(stmt, 14, data->MsgIndex);
|
||||
|
||||
if (sqlite3_step(stmt) != SQLITE_DONE)
|
||||
std::cout << "[WARN] Database: failed to update email: " << sqlite3_errmsg(db) << std::endl;
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
void Database::deleteEmailAttachments(int playerID, int index, int slot) {
|
||||
std::lock_guard<std::mutex> lock(dbCrit);
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
std::string sql(R"(
|
||||
DELETE FROM EmailItems
|
||||
WHERE PlayerID = ? AND MsgIndex = ?;
|
||||
)");
|
||||
|
||||
if (slot != -1)
|
||||
sql += " AND \"Slot\" = ? ";
|
||||
sql += ";";
|
||||
|
||||
sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, NULL);
|
||||
sqlite3_bind_int(stmt, 1, playerID);
|
||||
sqlite3_bind_int(stmt, 2, index);
|
||||
if (slot != -1)
|
||||
sqlite3_bind_int(stmt, 3, slot);
|
||||
|
||||
if (sqlite3_step(stmt) != SQLITE_DONE)
|
||||
std::cout << "[WARN] Database: Failed to delete email attachments: " << sqlite3_errmsg(db) << std::endl;
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
void Database::deleteEmails(int playerID, int64_t* indices) {
|
||||
std::lock_guard<std::mutex> lock(dbCrit);
|
||||
|
||||
sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
const char* sql = R"(
|
||||
DELETE FROM EmailData
|
||||
WHERE PlayerID = ? AND MsgIndex = ?;
|
||||
)";
|
||||
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
sqlite3_bind_int(stmt, 1, playerID);
|
||||
sqlite3_bind_int64(stmt, 2, indices[i]);
|
||||
if (sqlite3_step(stmt) != SQLITE_DONE) {
|
||||
std::cout << "[WARN] Database: Failed to delete an email: " << sqlite3_errmsg(db) << std::endl;
|
||||
}
|
||||
sqlite3_reset(stmt);
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
int Database::getNextEmailIndex(int playerID) {
|
||||
std::lock_guard<std::mutex> lock(dbCrit);
|
||||
|
||||
const char* sql = R"(
|
||||
SELECT MsgIndex
|
||||
FROM EmailData
|
||||
WHERE PlayerID = ?
|
||||
ORDER BY MsgIndex DESC
|
||||
LIMIT 1;
|
||||
)";
|
||||
sqlite3_stmt* stmt;
|
||||
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||
sqlite3_bind_int(stmt, 1, playerID);
|
||||
sqlite3_step(stmt);
|
||||
int index = sqlite3_column_int(stmt, 0);
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
return (index > 0 ? index + 1 : 1);
|
||||
}
|
||||
|
||||
bool Database::sendEmail(EmailData* data, std::vector<sItemBase> attachments) {
|
||||
std::lock_guard<std::mutex> lock(dbCrit);
|
||||
|
||||
sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
|
||||
|
||||
const char* sql = R"(
|
||||
INSERT INTO EmailData
|
||||
(PlayerID, MsgIndex, ReadFlag, ItemFlag,
|
||||
SenderID, SenderFirstName, SenderLastName,
|
||||
SubjectLine, MsgBody, Taros, SendTime, DeleteTime)
|
||||
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||
)";
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||
sqlite3_bind_int(stmt, 1, data->PlayerId);
|
||||
sqlite3_bind_int(stmt, 2, data->MsgIndex);
|
||||
sqlite3_bind_int(stmt, 3, data->ReadFlag);
|
||||
sqlite3_bind_int(stmt, 4, data->ItemFlag);
|
||||
sqlite3_bind_int(stmt, 5, data->SenderId);
|
||||
sqlite3_bind_text(stmt, 6, data->SenderFirstName.c_str(), -1, NULL);
|
||||
sqlite3_bind_text(stmt, 7, data->SenderLastName.c_str(), -1, NULL);
|
||||
sqlite3_bind_text(stmt, 8, data->SubjectLine.c_str(), -1, NULL);
|
||||
sqlite3_bind_text(stmt, 9, data->MsgBody.c_str(), -1, NULL);
|
||||
sqlite3_bind_int(stmt, 10, data->Taros);
|
||||
sqlite3_bind_int64(stmt, 11, data->SendTime);
|
||||
sqlite3_bind_int64(stmt, 12, data->DeleteTime);
|
||||
|
||||
if (sqlite3_step(stmt) != SQLITE_DONE) {
|
||||
std::cout << "[WARN] Database: Failed to send email: " << sqlite3_errmsg(db) << std::endl;
|
||||
sqlite3_exec(db, "ROLLBACK TRANSACTION;", NULL, NULL, NULL);
|
||||
sqlite3_finalize(stmt);
|
||||
return false;
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
sql = R"(
|
||||
INSERT INTO EmailItems
|
||||
(PlayerID, MsgIndex, Slot, ID, Type, Opt, TimeLimit)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?);
|
||||
)";
|
||||
|
||||
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||
|
||||
// send attachments
|
||||
int slot = 1;
|
||||
for (sItemBase item : attachments) {
|
||||
sqlite3_bind_int(stmt, 1, data->PlayerId);
|
||||
sqlite3_bind_int(stmt, 2, data->MsgIndex);
|
||||
sqlite3_bind_int(stmt, 3, slot++);
|
||||
sqlite3_bind_int(stmt, 4, item.iID);
|
||||
sqlite3_bind_int(stmt, 5, item.iType);
|
||||
sqlite3_bind_int(stmt, 6, item.iOpt);
|
||||
sqlite3_bind_int(stmt, 7, item.iTimeLimit);
|
||||
|
||||
if (sqlite3_step(stmt) != SQLITE_DONE) {
|
||||
std::cout << "[WARN] Database: Failed to send email: " << sqlite3_errmsg(db) << std::endl;
|
||||
sqlite3_exec(db, "ROLLBACK TRANSACTION;", NULL, NULL, NULL);
|
||||
sqlite3_finalize(stmt);
|
||||
return false;
|
||||
}
|
||||
sqlite3_reset(stmt);
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL);
|
||||
return true;
|
||||
}
|
Reference in New Issue
Block a user