From e33e076b2a84a69516f8c50cc9650cd0c775bc8d Mon Sep 17 00:00:00 2001 From: Alex King <89047260+Kinglykrab@users.noreply.github.com> Date: Thu, 23 May 2024 16:45:21 -0400 Subject: [PATCH] [Bug Fix] Fix issue with #suspend (#4314) * [Bug Fix] Fix issue with #suspend * Add suspension clearing * Update character_data_repository.h * Final push. --- common/database.cpp | 14 ++- common/database.h | 2 +- .../repositories/character_data_repository.h | 16 ++++ world/console.cpp | 2 +- world/login_server.cpp | 4 +- zone/api_service.cpp | 2 +- zone/client.cpp | 2 +- zone/gm_commands/suspend.cpp | 90 +++++++++++-------- 8 files changed, 85 insertions(+), 47 deletions(-) diff --git a/common/database.cpp b/common/database.cpp index d150801b6..0acf77cd6 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -206,9 +206,19 @@ void Database::LoginIP(uint32 account_id, const std::string& login_ip) QueryDatabase(query); } -int16 Database::CheckStatus(uint32 account_id) +int16 Database::GetAccountStatus(uint32 account_id) { - return AccountRepository::GetAccountStatus(*this, account_id); + auto e = AccountRepository::FindOne(*this, account_id); + + if (e.suspendeduntil > 0 && e.suspendeduntil < std::time(nullptr)) { + e.status = 0; + e.suspendeduntil = 0; + e.suspend_reason = ""; + + AccountRepository::UpdateOne(*this, e); + } + + return e.status; } uint32 Database::CreateAccount( diff --git a/common/database.h b/common/database.h index 25d129ac1..d4078e815 100644 --- a/common/database.h +++ b/common/database.h @@ -170,7 +170,7 @@ public: bool SetAccountStatus(const std::string& account_name, int16 status); bool SetLocalPassword(uint32 account_id, const std::string& password); bool UpdateLiveChar(const std::string& name, uint32 account_id); - int16 CheckStatus(uint32 account_id); + int16 GetAccountStatus(uint32 account_id); void SetAccountCRCField(uint32 account_id, const std::string& field_name, uint64 checksum); uint32 CheckLogin(const std::string& name, const std::string& password, const std::string& loginserver, int16* status = 0); uint32 CreateAccount( diff --git a/common/repositories/character_data_repository.h b/common/repositories/character_data_repository.h index 6facc720b..249218279 100644 --- a/common/repositories/character_data_repository.h +++ b/common/repositories/character_data_repository.h @@ -64,6 +64,22 @@ public: return Strings::ToUnsignedInt(row[0]); } + + static CharacterData FindByName( + Database& db, + const std::string& character_name + ) + { + auto l = CharacterDataRepository::GetWhere( + db, + fmt::format( + "`name` = '{}' LIMIT 1", + Strings::Escape(character_name) + ) + ); + + return l.empty() ? CharacterDataRepository::NewEntity() : l.front(); + } }; #endif //EQEMU_CHARACTER_DATA_REPOSITORY_H diff --git a/world/console.cpp b/world/console.cpp index 0e1151173..25a7cd793 100644 --- a/world/console.cpp +++ b/world/console.cpp @@ -60,7 +60,7 @@ struct EQ::Net::ConsoleLoginStatus CheckLogin(const std::string &username, const const std::string& account_name = database.GetAccountName(ret.account_id); ret.account_name = account_name; - ret.status = database.CheckStatus(ret.account_id); + ret.status = database.GetAccountStatus(ret.account_id); return ret; } diff --git a/world/login_server.cpp b/world/login_server.cpp index 671fbad59..c32141721 100644 --- a/world/login_server.cpp +++ b/world/login_server.cpp @@ -66,7 +66,7 @@ void LoginServer::ProcessUsertoWorldReqLeg(uint16_t opcode, EQ::Net::Packet &p) UsertoWorldRequestLegacy_Struct *utwr = (UsertoWorldRequestLegacy_Struct *) p.Data(); uint32 id = database.GetAccountIDFromLSID("eqemu", utwr->lsaccountid); - int16 status = database.CheckStatus(id); + int16 status = database.GetAccountStatus(id); LogDebug( "id [{}] status [{}] account_id [{}] world_id [{}] from_id [{}] to_id [{}] ip [{}]", @@ -146,7 +146,7 @@ void LoginServer::ProcessUsertoWorldReq(uint16_t opcode, EQ::Net::Packet &p) UsertoWorldRequest_Struct *utwr = (UsertoWorldRequest_Struct *) p.Data(); uint32 id = database.GetAccountIDFromLSID(utwr->login, utwr->lsaccountid); - int16 status = database.CheckStatus(id); + int16 status = database.GetAccountStatus(id); LogDebug( "id [{}] status [{}] account_id [{}] world_id [{}] from_id [{}] to_id [{}] ip [{}]", diff --git a/zone/api_service.cpp b/zone/api_service.cpp index edc52ffbe..25335a784 100644 --- a/zone/api_service.cpp +++ b/zone/api_service.cpp @@ -59,7 +59,7 @@ EQ::Net::WebsocketLoginStatus CheckLogin( ret.account_name = database.GetAccountName(static_cast(ret.account_id)); ret.logged_in = true; - ret.status = database.CheckStatus(ret.account_id); + ret.status = database.GetAccountStatus(ret.account_id); return ret; } diff --git a/zone/client.cpp b/zone/client.cpp index e7073a647..db77be18d 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -1849,7 +1849,7 @@ void Client::FriendsWho(char *FriendsString) { void Client::UpdateAdmin(bool from_database) { int16 tmp = admin; if (from_database) { - admin = database.CheckStatus(account_id); + admin = database.GetAccountStatus(account_id); } if (tmp == admin && from_database) { diff --git a/zone/gm_commands/suspend.cpp b/zone/gm_commands/suspend.cpp index 3e4d7e9f2..1bd5f4ae2 100755 --- a/zone/gm_commands/suspend.cpp +++ b/zone/gm_commands/suspend.cpp @@ -6,46 +6,56 @@ extern WorldServer worldserver; void command_suspend(Client *c, const Seperator *sep) { - auto arguments = sep->argnum; + const uint16 arguments = sep->argnum; if (arguments < 2 || !sep->IsNumber(2)) { c->Message(Chat::White, "Usage: #suspend [Character Name] [Days] [Reason]"); - c->Message(Chat::White, "Note: Specify 0 days to lift a suspension"); + c->Message(Chat::White, "Note: Specify 0 days to lift a suspension, reason is not required when removing a suspension"); return; } - const std::string character_name = Strings::ToLower(sep->arg[1]); - auto days = Strings::ToUnsignedInt(sep->arg[2]); + const std::string& character_name = sep->arg[1]; - const std::string reason = sep->arg[3] ? sep->argplus[3] : ""; + const auto& e = CharacterDataRepository::FindByName(database, character_name); - auto l = AccountRepository::GetWhere( - database, - fmt::format( - "LOWER(charname) = '{}'", - Strings::Escape(character_name) - ) - ); - - if (l.empty()) { + if (!e.id) { c->Message( Chat::White, fmt::format( "Character '{}' does not exist.", - sep->arg[1] + character_name ).c_str() ); return; } - l[0].status = -1; - l[0].suspendeduntil = std::time(nullptr) + (days * 86400); - l[0].suspend_reason = reason; + auto a = AccountRepository::FindOne(database, e.account_id); - if (!AccountRepository::UpdateOne(database, l[0])) { + if (!a.id) { c->Message( Chat::White, fmt::format( - "Failed to suspend {}.", + "Character '{}' is not attached to an account.", + character_name + ).c_str() + ); + return; + } + + const uint32 days = Strings::ToUnsignedInt(sep->arg[2]); + const bool is_suspend = days != 0; + + const std::string reason = sep->arg[3] ? sep->argplus[3] : ""; + + a.status = is_suspend ? -1 : 0; + a.suspendeduntil = is_suspend ? std::time(nullptr) + (days * 86400) : 0; + a.suspend_reason = is_suspend ? reason : ""; + + if (!AccountRepository::UpdateOne(database, a)) { + c->Message( + Chat::White, + fmt::format( + "Failed to {}suspend {}.", + is_suspend ? "" : "un", character_name ).c_str() ); @@ -56,13 +66,13 @@ void command_suspend(Client *c, const Seperator *sep) Chat::White, fmt::format( "Account {} ({}) with the character {} {}.", - l[0].name, - l[0].id, + a.name, + a.id, character_name, ( - days ? + is_suspend ? fmt::format( - "has been temporarily suspended for {} day{}.", + "has been suspended for {} day{}", days, days != 1 ? "s" : "" ) : @@ -71,22 +81,24 @@ void command_suspend(Client *c, const Seperator *sep) ).c_str() ); - auto* b = entity_list.GetClientByName(character_name.c_str()); + if (is_suspend) { // Only kick if we're suspending, otherwise there's no reason to kick someone who is already suspended + Client* b = entity_list.GetClientByName(character_name.c_str()); - if (b) { - b->WorldKick(); - return; + if (b) { + b->WorldKick(); + return; + } + + auto pack = new ServerPacket(ServerOP_KickPlayer, sizeof(ServerKickPlayer_Struct)); + auto* k = (ServerKickPlayer_Struct*) pack->pBuffer; + + strn0cpy(k->adminname, c->GetName(), sizeof(k->adminname)); + strn0cpy(k->name, character_name.c_str(), sizeof(k->name)); + k->adminrank = c->Admin(); + + worldserver.SendPacket(pack); + + safe_delete(pack); } - - auto pack = new ServerPacket(ServerOP_KickPlayer, sizeof(ServerKickPlayer_Struct)); - auto* k = (ServerKickPlayer_Struct *) pack->pBuffer; - - strn0cpy(k->adminname, c->GetName(), sizeof(k->adminname)); - strn0cpy(k->name, character_name.c_str(), sizeof(k->name)); - k->adminrank = c->Admin(); - - worldserver.SendPacket(pack); - - safe_delete(pack); }