From 1822d16a7210e06d763f4b87674f18a010b4e0d3 Mon Sep 17 00:00:00 2001 From: BruebachL <44814898+BruebachL@users.noreply.github.com> Date: Tue, 10 Nov 2026 12:16:30 +0100 Subject: [PATCH] [Server] Serve card-art rules and params through the database interface (#7850) The four card-art commands still prepared their statements inline through Servatrice_DatabaseInterface: the two card_art_params updates in cmdSetCardArtParams, the rule upsert and delete, and the rule listing that mapped rows to protocol entries. Add CardArtRuleRecord, upsertCardArtRule, removeCardArtRule, getCardArtRules, setCardArtParams and clearCardArtParams to Server_DatabaseInterface with fail-closed defaults, implement them with the previous statements, and keep the validation, clamping, in-memory userInfo sync and broadcast in the handler. --- .../server/remote/server_database_interface.h | 32 +++++++ .../src/servatrice_database_interface.cpp | 86 +++++++++++++++++++ .../src/servatrice_database_interface.h | 9 ++ servatrice/src/serversocketinterface.cpp | 51 +++-------- 4 files changed, 140 insertions(+), 38 deletions(-) diff --git a/libcockatrice_network/libcockatrice/network/server/remote/server_database_interface.h b/libcockatrice_network/libcockatrice/network/server/remote/server_database_interface.h index abdeab6c1..77dcbc63b 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/server_database_interface.h +++ b/libcockatrice_network/libcockatrice/network/server/remote/server_database_interface.h @@ -875,6 +875,38 @@ public: { return false; } + /** @brief One card-art name rule. */ + struct CardArtRuleRecord + { + QString cardName; + QString cardProviderId; + QString mode; + QString reason; + }; + virtual bool upsertCardArtRule(const QString & /* cardName */, + const QString & /* cardProviderId */, + const QString & /* mode */, + const QString & /* reason */, + int /* createdBy */) + { + return false; + } + virtual bool removeCardArtRule(const QString & /* cardName */, const QString & /* cardProviderId */) + { + return false; + } + virtual bool getCardArtRules(QList & /* rules */) + { + return false; + } + virtual bool setCardArtParams(int /* userId */, const QString & /* paramsJson */) + { + return false; + } + virtual bool clearCardArtParams(int /* userId */) + { + return false; + } /** * @brief Whether the given card art may be shown (card art rules). * diff --git a/servatrice/src/servatrice_database_interface.cpp b/servatrice/src/servatrice_database_interface.cpp index 4f651ba08..d187910d4 100644 --- a/servatrice/src/servatrice_database_interface.cpp +++ b/servatrice/src/servatrice_database_interface.cpp @@ -4628,3 +4628,89 @@ bool Servatrice_DatabaseInterface::isCardArtAllowed(const QString &cardName, con return q->value(0).toString() != "DENY"; } + +bool Servatrice_DatabaseInterface::upsertCardArtRule(const QString &cardName, + const QString &cardProviderId, + const QString &mode, + const QString &reason, + int createdBy) +{ + if (!checkSql()) { + return false; + } + + QSqlQuery *q = prepareQuery("INSERT INTO {prefix}_card_art_name_rules " + "(card_name, card_provider_id, mode, reason, created_by) " + "VALUES (:name, :provider, :mode, :reason, :uid) " + "ON DUPLICATE KEY UPDATE mode=:mode2, reason=:reason2"); + + q->bindValue(":name", cardName); + q->bindValue(":provider", cardProviderId); + q->bindValue(":mode", mode); + q->bindValue(":mode2", mode); + q->bindValue(":reason", reason); + q->bindValue(":reason2", reason); + q->bindValue(":uid", createdBy); + + return execSqlQuery(q); +} + +bool Servatrice_DatabaseInterface::removeCardArtRule(const QString &cardName, const QString &cardProviderId) +{ + if (!checkSql()) { + return false; + } + + QSqlQuery *q = + prepareQuery("DELETE FROM {prefix}_card_art_name_rules WHERE card_name=:name AND card_provider_id=:provider"); + q->bindValue(":name", cardName); + q->bindValue(":provider", cardProviderId); + + return execSqlQuery(q); +} + +bool Servatrice_DatabaseInterface::getCardArtRules(QList &rules) +{ + if (!checkSql()) { + return false; + } + + QSqlQuery *q = prepareQuery("SELECT card_name, card_provider_id, mode, reason FROM {prefix}_card_art_name_rules"); + if (!execSqlQuery(q)) { + return false; + } + + while (q->next()) { + CardArtRuleRecord rule; + rule.cardName = q->value(0).toString(); + rule.cardProviderId = q->value(1).toString(); + rule.mode = q->value(2).toString(); + rule.reason = q->value(3).toString(); + rules.append(rule); + } + + return true; +} + +bool Servatrice_DatabaseInterface::setCardArtParams(int userId, const QString ¶msJson) +{ + if (!checkSql()) { + return false; + } + + QSqlQuery *query = prepareQuery("update {prefix}_users set card_art_params=:params where id=:id"); + query->bindValue(":params", paramsJson); + query->bindValue(":id", userId); + return execSqlQuery(query); +} + +bool Servatrice_DatabaseInterface::clearCardArtParams(int userId) +{ + if (!checkSql()) { + return false; + } + + QSqlQuery *query = prepareQuery("UPDATE {prefix}_users SET card_art_params = NULL WHERE id = :id"); + query->bindValue(":id", userId); + return execSqlQuery(query); +} diff --git a/servatrice/src/servatrice_database_interface.h b/servatrice/src/servatrice_database_interface.h index 98be67994..e394ccbe9 100644 --- a/servatrice/src/servatrice_database_interface.h +++ b/servatrice/src/servatrice_database_interface.h @@ -283,6 +283,15 @@ public: int clearBlacklistedBanners() override; bool getUserAdminFlags(const QString &userName, int &adminFlags) override; bool isCardArtAllowed(const QString &cardName, const QString &cardProviderId) override; + bool upsertCardArtRule(const QString &cardName, + const QString &cardProviderId, + const QString &mode, + const QString &reason, + int createdBy) override; + bool removeCardArtRule(const QString &cardName, const QString &cardProviderId) override; + bool getCardArtRules(QList &rules) override; + bool setCardArtParams(int userId, const QString ¶msJson) override; + bool clearCardArtParams(int userId) override; bool addForgotPassword(const QString &user) override; bool removeForgotPassword(const QString &user) override; bool doesForgotPasswordExist(const QString &user) override; diff --git a/servatrice/src/serversocketinterface.cpp b/servatrice/src/serversocketinterface.cpp index 93bb7e585..d180ce34d 100644 --- a/servatrice/src/serversocketinterface.cpp +++ b/servatrice/src/serversocketinterface.cpp @@ -2972,9 +2972,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdSetCardArtParams(const if (cardName.isEmpty()) { // Removal path - QSqlQuery *q = sqlInterface->prepareQuery("UPDATE {prefix}_users SET card_art_params = NULL WHERE id = :id"); - q->bindValue(":id", userInfo->id()); - if (!sqlInterface->execSqlQuery(q)) { + if (!databaseInterface->clearCardArtParams(userInfo->id())) { return Response::RespInternalError; } userInfo->clear_card_art_params(); @@ -2982,7 +2980,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdSetCardArtParams(const return Response::RespOk; } - if (!sqlInterface->isCardArtAllowed(cardName, cardProviderId)) { + if (!databaseInterface->isCardArtAllowed(cardName, cardProviderId)) { return Response::RespFunctionNotAllowed; } @@ -3002,10 +3000,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdSetCardArtParams(const obj["zoom"] = zoom; const QString json = QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Compact)); - QSqlQuery *query = sqlInterface->prepareQuery("update {prefix}_users set card_art_params=:params where id=:id"); - query->bindValue(":params", json); - query->bindValue(":id", userInfo->id()); - if (!sqlInterface->execSqlQuery(query)) { + if (!databaseInterface->setCardArtParams(userInfo->id(), json)) { return Response::RespInternalError; } @@ -3038,20 +3033,8 @@ Response::ResponseCode AbstractServerSocketInterface::cmdAddCardArtRule(const Co return Response::RespInvalidData; } - QSqlQuery *q = sqlInterface->prepareQuery("INSERT INTO {prefix}_card_art_name_rules " - "(card_name, card_provider_id, mode, reason, created_by) " - "VALUES (:name, :provider, :mode, :reason, :uid) " - "ON DUPLICATE KEY UPDATE mode=:mode2, reason=:reason2"); - - q->bindValue(":name", cardName); - q->bindValue(":provider", cardProviderId); - q->bindValue(":mode", mode); - q->bindValue(":mode2", mode); - q->bindValue(":reason", QString::fromStdString(cmd.reason())); - q->bindValue(":reason2", QString::fromStdString(cmd.reason())); - q->bindValue(":uid", userInfo->id()); - - if (!sqlInterface->execSqlQuery(q)) { + if (!databaseInterface->upsertCardArtRule(cardName, cardProviderId, mode, QString::fromStdString(cmd.reason()), + userInfo->id())) { return Response::RespInternalError; } @@ -3066,13 +3049,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdRemoveCardArtRule(const if (cardName.length() > MAX_NAME_LENGTH || cardProviderId.length() > MAX_NAME_LENGTH) { return Response::RespInvalidData; } - QSqlQuery *q = sqlInterface->prepareQuery( - "DELETE FROM {prefix}_card_art_name_rules WHERE card_name=:name AND card_provider_id=:provider"); - - q->bindValue(":name", cardName); - q->bindValue(":provider", cardProviderId); - - if (!sqlInterface->execSqlQuery(q)) { + if (!databaseInterface->removeCardArtRule(cardName, cardProviderId)) { return Response::RespInternalError; } @@ -3082,21 +3059,19 @@ Response::ResponseCode AbstractServerSocketInterface::cmdRemoveCardArtRule(const Response::ResponseCode AbstractServerSocketInterface::cmdListCardArtRules(const Command_ListCardArtRules &, ResponseContainer &rc) { - QSqlQuery *q = sqlInterface->prepareQuery( - "SELECT card_name, card_provider_id, mode, reason FROM {prefix}_card_art_name_rules"); - - if (!sqlInterface->execSqlQuery(q)) { + QList rules; + if (!databaseInterface->getCardArtRules(rules)) { return Response::RespInternalError; } auto *re = new Response_ListCardArtRules; - while (q->next()) { + for (const Server_DatabaseInterface::CardArtRuleRecord &rule : rules) { auto *entry = re->add_entries(); - entry->set_card_name(q->value(0).toString().toStdString()); - entry->set_card_provider_id(q->value(1).toString().toStdString()); - entry->set_mode(q->value(2).toString().toStdString()); - entry->set_reason(q->value(3).toString().toStdString()); + entry->set_card_name(rule.cardName.toStdString()); + entry->set_card_provider_id(rule.cardProviderId.toStdString()); + entry->set_mode(rule.mode.toStdString()); + entry->set_reason(rule.reason.toStdString()); } rc.setResponseExtension(re);