From 8c0e796b0d44b59e22f8841549d30b5c7fd67d4d Mon Sep 17 00:00:00 2001 From: BruebachL <44814898+BruebachL@users.noreply.github.com> Date: Tue, 10 Nov 2026 12:16:22 +0100 Subject: [PATCH] [Server] Move deck-path and visibility lookups into the database interface (#7832) Resolving a deck folder path, reading a deck's owner, and walking its folder chain for public visibility were SQL queries living in the socket handler, keyed to the logged-in user through userInfo. Declare the three lookups on Server_DatabaseInterface, implement them in Servatrice_DatabaseInterface with the user id as an explicit parameter, and let the deck commands ask the injected interface. --- .../server/remote/server_database_interface.h | 15 +++ .../src/servatrice_database_interface.cpp | 80 ++++++++++++++++ .../src/servatrice_database_interface.h | 4 + servatrice/src/serversocketinterface.cpp | 96 ++----------------- servatrice/src/serversocketinterface.h | 4 - 5 files changed, 106 insertions(+), 93 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 802b9d3b7..506620bc8 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/server_database_interface.h +++ b/libcockatrice_network/libcockatrice/network/server/remote/server_database_interface.h @@ -180,6 +180,21 @@ public: { return 0; } + /** @brief Id of the folder at a "/"-separated path for one user, 0 for the root, -1 when absent. */ + virtual int getDeckPathId(const QString & /* path */, int /* userId */) + { + return -1; + } + /** @brief Owner of a deck file, or -1 when the deck does not exist. */ + virtual int getDeckOwnerId(int /* deckId */) + { + return -1; + } + /** @brief Whether a deck is public itself or sits in a public folder. */ + virtual bool isDeckEffectivelyPublic(int /* deckId */) + { + return false; + } virtual bool removeForgotPassword(const QString & /* user */) { return false; diff --git a/servatrice/src/servatrice_database_interface.cpp b/servatrice/src/servatrice_database_interface.cpp index 9c67713c0..14b66ddcb 100644 --- a/servatrice/src/servatrice_database_interface.cpp +++ b/servatrice/src/servatrice_database_interface.cpp @@ -991,6 +991,86 @@ bool Servatrice_DatabaseInterface::isInIgnoreList(const QString &whoseList, cons return query->next(); } +int Servatrice_DatabaseInterface::getDeckPathIdAt(int basePathId, QStringList path, int userId) +{ + if (path.isEmpty()) { + return 0; + } + if (path[0].isEmpty()) { + return 0; + } + + QSqlQuery *query = prepareQuery("select id from {prefix}_decklist_folders where id_parent = " + ":id_parent and name = :name and id_user = :id_user"); + query->bindValue(":id_parent", basePathId); + query->bindValue(":name", path.takeFirst()); + query->bindValue(":id_user", userId); + if (!execSqlQuery(query)) { + return -1; + } + if (!query->next()) { + return -1; + } + int id = query->value(0).toInt(); + if (path.isEmpty()) { + return id; + } + return getDeckPathIdAt(id, path, userId); +} + +int Servatrice_DatabaseInterface::getDeckPathId(const QString &path, int userId) +{ + return getDeckPathIdAt(0, path.split("/"), userId); +} + +int Servatrice_DatabaseInterface::getDeckOwnerId(int deckId) +{ + QSqlQuery *query = prepareQuery("select id_user from {prefix}_decklist_files where id = :id"); + query->bindValue(":id", deckId); + if (!execSqlQuery(query)) { + return -1; + } + if (!query->next()) { + return -1; + } + return query->value(0).toInt(); +} + +bool Servatrice_DatabaseInterface::isDeckEffectivelyPublic(int deckId) +{ + QSqlQuery *query = prepareQuery("select is_public, id_folder from {prefix}_decklist_files where id = :id"); + query->bindValue(":id", deckId); + if (!execSqlQuery(query)) { + return false; + } + if (!query->next()) { + return false; + } + if (query->value(0).toBool()) { + return true; + } + + int folderId = query->value(1).toInt(); + int guard = 0; + while (folderId != 0 && guard < 100) { + QSqlQuery *folderQuery = + prepareQuery("select is_public, id_parent from {prefix}_decklist_folders where id = :id"); + folderQuery->bindValue(":id", folderId); + if (!execSqlQuery(folderQuery)) { + return false; + } + if (!folderQuery->next()) { + return false; + } + if (folderQuery->value(0).toBool()) { + return true; + } + folderId = folderQuery->value(1).toInt(); + ++guard; + } + return false; +} + int Servatrice_DatabaseInterface::getUserId(const QString &name) { return getUserIdInDB(name); diff --git a/servatrice/src/servatrice_database_interface.h b/servatrice/src/servatrice_database_interface.h index f00a432a7..e463c520e 100644 --- a/servatrice/src/servatrice_database_interface.h +++ b/servatrice/src/servatrice_database_interface.h @@ -67,6 +67,7 @@ private: * backup key is unset or the sealed value does not fit the column. */ QString sealLegacyBackup(const QString &storedName, const QString &credential); bool isStrictModeEnabled(bool &ok) const; + int getDeckPathIdAt(int basePathId, QStringList path, int userId); bool addToList(const QString &table, int userId, int targetId); bool removeFromList(const QString &table, int userId, int targetId); @@ -120,6 +121,9 @@ public: bool removeFromBuddyList(int userId, int targetId) override; bool addToIgnoreList(int userId, int targetId) override; bool removeFromIgnoreList(int userId, int targetId) override; + int getDeckPathId(const QString &path, int userId) override; + int getDeckOwnerId(int deckId) override; + bool isDeckEffectivelyPublic(int deckId) override; QMap getBuddyList(const QString &name) override; QMap getIgnoreList(const QString &name) override; bool isInBuddyList(const QString &whoseList, const QString &who) override; diff --git a/servatrice/src/serversocketinterface.cpp b/servatrice/src/serversocketinterface.cpp index 9a6f0eebf..abecab545 100644 --- a/servatrice/src/serversocketinterface.cpp +++ b/servatrice/src/serversocketinterface.cpp @@ -634,39 +634,6 @@ Response::ResponseCode AbstractServerSocketInterface::cmdRemoveFromList(const Co return Response::RespOk; } -int AbstractServerSocketInterface::getDeckPathId(int basePathId, QStringList path) -{ - if (path.isEmpty()) { - return 0; - } - if (path[0].isEmpty()) { - return 0; - } - - QSqlQuery *query = sqlInterface->prepareQuery("select id from {prefix}_decklist_folders where id_parent = " - ":id_parent and name = :name and id_user = :id_user"); - query->bindValue(":id_parent", basePathId); - query->bindValue(":name", path.takeFirst()); - query->bindValue(":id_user", userInfo->id()); - if (!sqlInterface->execSqlQuery(query)) { - return -1; - } - if (!query->next()) { - return -1; - } - int id = query->value(0).toInt(); - if (path.isEmpty()) { - return id; - } else { - return getDeckPathId(id, path); - } -} - -int AbstractServerSocketInterface::getDeckPathId(const QString &path) -{ - return getDeckPathId(0, path.split("/")); -} - bool AbstractServerSocketInterface::deckListHelper(int folderId, ServerInfo_DeckStorage_Folder *folder, int userId, @@ -788,55 +755,6 @@ Response::ResponseCode AbstractServerSocketInterface::cmdDeckListOtherUser(const return Response::RespOk; } -int AbstractServerSocketInterface::getDeckOwnerId(int deckId) -{ - QSqlQuery *query = sqlInterface->prepareQuery("select id_user from {prefix}_decklist_files where id = :id"); - query->bindValue(":id", deckId); - if (!sqlInterface->execSqlQuery(query)) { - return -1; - } - if (!query->next()) { - return -1; - } - return query->value(0).toInt(); -} - -bool AbstractServerSocketInterface::isDeckEffectivelyPublic(int deckId) -{ - QSqlQuery *query = - sqlInterface->prepareQuery("select is_public, id_folder from {prefix}_decklist_files where id = :id"); - query->bindValue(":id", deckId); - if (!sqlInterface->execSqlQuery(query)) { - return false; - } - if (!query->next()) { - return false; - } - if (query->value(0).toBool()) { - return true; - } - - int folderId = query->value(1).toInt(); - int guard = 0; - while (folderId != 0 && guard < 100) { - QSqlQuery *folderQuery = - sqlInterface->prepareQuery("select is_public, id_parent from {prefix}_decklist_folders where id = :id"); - folderQuery->bindValue(":id", folderId); - if (!sqlInterface->execSqlQuery(folderQuery)) { - return false; - } - if (!folderQuery->next()) { - return false; - } - if (folderQuery->value(0).toBool()) { - return true; - } - folderId = folderQuery->value(1).toInt(); - ++guard; - } - return false; -} - Response::ResponseCode AbstractServerSocketInterface::cmdDeckSetVisibility(const Command_DeckSetVisibility &cmd, ResponseContainer & /*rc*/) { @@ -865,7 +783,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdDeckSetVisibility(const return Response::RespContextError; } } else if (cmd.has_folder_path()) { - const int folderId = getDeckPathId(nameFromStdString(cmd.folder_path())); + const int folderId = databaseInterface->getDeckPathId(nameFromStdString(cmd.folder_path()), userInfo->id()); if (folderId == -1 || folderId == 0) { return Response::RespNameNotFound; } @@ -896,8 +814,8 @@ Response::ResponseCode AbstractServerSocketInterface::cmdDeckDownloadPublic(cons sqlInterface->checkSql(); const int deckId = cmd.deck_id(); - const int ownerId = getDeckOwnerId(deckId); - if (ownerId == -1 || !isDeckEffectivelyPublic(deckId)) { + const int ownerId = databaseInterface->getDeckOwnerId(deckId); + if (ownerId == -1 || !databaseInterface->isDeckEffectivelyPublic(deckId)) { return Response::RespNameNotFound; } @@ -926,7 +844,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdDeckNewDir(const Comman sqlInterface->checkSql(); QString path = nameFromStdString(cmd.path()); - int folderId = getDeckPathId(path); + int folderId = databaseInterface->getDeckPathId(path, userInfo->id()); if (folderId == -1) { return Response::RespNameNotFound; } @@ -993,7 +911,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdDeckDelDir(const Comman sqlInterface->checkSql(); - int basePathId = getDeckPathId(nameFromStdString(cmd.path())); + int basePathId = databaseInterface->getDeckPathId(nameFromStdString(cmd.path()), userInfo->id()); if ((basePathId == -1) || (basePathId == 0)) { return Response::RespNameNotFound; } @@ -1077,7 +995,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdDeckUpload(const Comman const QString colorIdentity = sanitizeColorIdentity(nameFromStdString(cmd.color_identity())); if (cmd.has_path()) { - int folderId = getDeckPathId(nameFromStdString(cmd.path())); + int folderId = databaseInterface->getDeckPathId(nameFromStdString(cmd.path()), userInfo->id()); if (folderId == -1) { return Response::RespNameNotFound; } @@ -1262,7 +1180,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdDeckShareCreate(const C } } } else if (cmd.has_folder_path()) { - const int folderId = getDeckPathId(nameFromStdString(cmd.folder_path())); + const int folderId = databaseInterface->getDeckPathId(nameFromStdString(cmd.folder_path()), userInfo->id()); if (folderId == -1) { return Response::RespNameNotFound; } diff --git a/servatrice/src/serversocketinterface.h b/servatrice/src/serversocketinterface.h index 0e77d7458..63f799e36 100644 --- a/servatrice/src/serversocketinterface.h +++ b/servatrice/src/serversocketinterface.h @@ -144,15 +144,11 @@ private: Response::ResponseCode cmdAddToList(const Command_AddToList &cmd, ResponseContainer &rc); Response::ResponseCode cmdRemoveFromList(const Command_RemoveFromList &cmd, ResponseContainer &rc); Response::ResponseCode cmdGetPrivateChatHistory(const Command_GetPrivateChatHistory &cmd, ResponseContainer &rc); - int getDeckPathId(int basePathId, QStringList path); - int getDeckPathId(const QString &path); bool deckListHelper(int folderId, ServerInfo_DeckStorage_Folder *folder, int userId, bool inheritedPublic, bool publicOnly); - int getDeckOwnerId(int deckId); - bool isDeckEffectivelyPublic(int deckId); Response::ResponseCode cmdDeckList(const Command_DeckList &cmd, ResponseContainer &rc); Response::ResponseCode cmdDeckListOtherUser(const Command_DeckListOtherUser &cmd, ResponseContainer &rc); Response::ResponseCode cmdDeckSetVisibility(const Command_DeckSetVisibility &cmd, ResponseContainer &rc);