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 77dcbc63b..a012ec898 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/server_database_interface.h +++ b/libcockatrice_network/libcockatrice/network/server/remote/server_database_interface.h @@ -182,6 +182,33 @@ public: { return 0; } + /** @brief One folder row of a user's deck storage tree. */ + struct DeckListFolderRecord + { + int id = 0; + QString name; + bool isPublic = false; + }; + /** @brief One deck file row of a user's deck storage tree. */ + struct DeckListFileRecord + { + int id = 0; + QString name; + qint64 uploadTime = 0; + bool isPublic = false; + QString bannerCardName; + QString bannerCardProvider; + QString colorIdentity; + QStringList tags; + }; + virtual bool getDeckListFolders(int /* folderId */, int /* userId */, QList & /* folders */) + { + return false; + } + virtual bool getDeckListFiles(int /* folderId */, int /* userId */, QList & /* files */) + { + return false; + } /** @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 */) { diff --git a/servatrice/src/servatrice_database_interface.cpp b/servatrice/src/servatrice_database_interface.cpp index d187910d4..502429a2b 100644 --- a/servatrice/src/servatrice_database_interface.cpp +++ b/servatrice/src/servatrice_database_interface.cpp @@ -2062,6 +2062,58 @@ bool Servatrice_DatabaseInterface::getDeckFilesInFolder(int folderId, int userId return true; } +bool Servatrice_DatabaseInterface::getDeckListFolders(int folderId, int userId, QList &folders) +{ + checkSql(); + + QSqlQuery *query = prepareQuery("select id, name, is_public from {prefix}_decklist_folders where " + "id_parent = :id_parent and id_user = :id_user"); + query->bindValue(":id_parent", folderId); + query->bindValue(":id_user", userId); + if (!execSqlQuery(query)) { + return false; + } + + while (query->next()) { + DeckListFolderRecord folder; + folder.id = query->value(0).toInt(); + folder.name = query->value(1).toString(); + folder.isPublic = query->value(2).toBool(); + folders.append(folder); + } + + return true; +} + +bool Servatrice_DatabaseInterface::getDeckListFiles(int folderId, int userId, QList &files) +{ + checkSql(); + + QSqlQuery *query = prepareQuery("select id, name, upload_time, is_public, banner_card_name, " + "banner_card_provider, color_identity, tags from {prefix}_decklist_files where " + "id_folder = :id_folder and id_user = :id_user"); + query->bindValue(":id_folder", folderId); + query->bindValue(":id_user", userId); + if (!execSqlQuery(query)) { + return false; + } + + while (query->next()) { + DeckListFileRecord file; + file.id = query->value(0).toInt(); + file.name = query->value(1).toString(); + file.uploadTime = query->value(2).toDateTime().toSecsSinceEpoch(); + file.isPublic = query->value(3).toBool(); + file.bannerCardName = query->value(4).toString(); + file.bannerCardProvider = query->value(5).toString(); + file.colorIdentity = query->value(6).toString(); + file.tags = deserializeDeckTags(query->value(7).toString()); + files.append(file); + } + + return true; +} + bool Servatrice_DatabaseInterface::getDeckSharesForUser(int userId, QList &shares) { checkSql(); diff --git a/servatrice/src/servatrice_database_interface.h b/servatrice/src/servatrice_database_interface.h index e394ccbe9..ccdf92847 100644 --- a/servatrice/src/servatrice_database_interface.h +++ b/servatrice/src/servatrice_database_interface.h @@ -124,6 +124,8 @@ public: const QSet &allSpectatorsEver, const QList &replayList) override; DeckList *getDeckFromDatabase(int deckId, int userId) override; + bool getDeckListFolders(int folderId, int userId, QList &folders) override; + bool getDeckListFiles(int folderId, int userId, QList &files) override; /** * @brief Creates a new temporary deck share bundle. diff --git a/servatrice/src/serversocketinterface.cpp b/servatrice/src/serversocketinterface.cpp index d180ce34d..beb941c17 100644 --- a/servatrice/src/serversocketinterface.cpp +++ b/servatrice/src/serversocketinterface.cpp @@ -68,7 +68,6 @@ #include #include #include -#include #include #include #include @@ -195,7 +194,7 @@ static const int MAX_TCP_MESSAGE_SIZE = 1500000; AbstractServerSocketInterface::AbstractServerSocketInterface(Servatrice *_server, Servatrice_DatabaseInterface *_databaseInterface, QObject *parent) - : Server_ProtocolHandler(_server, _databaseInterface, parent), servatrice(_server), sqlInterface(_databaseInterface) + : Server_ProtocolHandler(_server, _databaseInterface, parent), servatrice(_server) { // Never call flushOutputQueue directly from outputQueueChanged. In case of a socket error, // it could lead to this object being destroyed while another function is still on the call stack. -> mutex @@ -640,28 +639,20 @@ bool AbstractServerSocketInterface::deckListHelper(int folderId, bool inheritedPublic, bool publicOnly) { - QSqlQuery *query = sqlInterface->prepareQuery("select id, name, is_public from {prefix}_decklist_folders where " - "id_parent = :id_parent and id_user = :id_user"); - query->bindValue(":id_parent", folderId); - query->bindValue(":id_user", userId); - if (!sqlInterface->execSqlQuery(query)) { + QList folders; + if (!databaseInterface->getDeckListFolders(folderId, userId, folders)) { return false; } - QList>> folderRows; - while (query->next()) { - folderRows.append({query->value(0).toInt(), {query->value(1).toString(), query->value(2).toBool()}}); - } - std::sort(folderRows.begin(), folderRows.end(), [](const auto &a, const auto &b) { return a.first < b.first; }); + std::sort(folders.begin(), folders.end(), [](const auto &a, const auto &b) { return a.id < b.id; }); - for (const auto &[folderIdValue, folderInfo] : folderRows) { - const QString name = folderInfo.first; - const bool ownPublic = folderInfo.second; + for (const Server_DatabaseInterface::DeckListFolderRecord &folderRecord : folders) { + const bool ownPublic = folderRecord.isPublic; const bool effectivePublic = inheritedPublic || ownPublic; ServerInfo_DeckStorage_TreeItem *newItem = folder->add_items(); - newItem->set_id(folderIdValue); - newItem->set_name(name.toStdString()); + newItem->set_id(folderRecord.id); + newItem->set_name(folderRecord.name.toStdString()); newItem->mutable_folder()->set_is_public(ownPublic); if (!deckListHelper(newItem->id(), newItem->mutable_folder(), userId, effectivePublic, publicOnly)) { @@ -673,32 +664,28 @@ bool AbstractServerSocketInterface::deckListHelper(int folderId, } } - query = sqlInterface->prepareQuery("select id, name, upload_time, is_public, banner_card_name, " - "banner_card_provider, color_identity, tags from {prefix}_decklist_files where " - "id_folder = :id_folder and id_user = :id_user"); - query->bindValue(":id_folder", folderId); - query->bindValue(":id_user", userId); - if (!sqlInterface->execSqlQuery(query)) { + QList files; + if (!databaseInterface->getDeckListFiles(folderId, userId, files)) { return false; } - while (query->next()) { - const bool ownPublic = query->value(3).toBool(); + for (const Server_DatabaseInterface::DeckListFileRecord &file : files) { + const bool ownPublic = file.isPublic; if (publicOnly && !(inheritedPublic || ownPublic)) { continue; } ServerInfo_DeckStorage_TreeItem *newItem = folder->add_items(); - newItem->set_id(query->value(0).toInt()); - newItem->set_name(query->value(1).toString().toStdString()); + newItem->set_id(file.id); + newItem->set_name(file.name.toStdString()); ServerInfo_DeckStorage_File *newFile = newItem->mutable_file(); - newFile->set_creation_time(query->value(2).toDateTime().toSecsSinceEpoch()); + newFile->set_creation_time(file.uploadTime); newFile->set_is_public(ownPublic); - newFile->set_banner_card_name(query->value(4).toString().toStdString()); - newFile->set_banner_card_provider(query->value(5).toString().toStdString()); - newFile->set_color_identity(query->value(6).toString().toStdString()); - for (const QString &tag : deserializeDeckTags(query->value(7).toString())) { + newFile->set_banner_card_name(file.bannerCardName.toStdString()); + newFile->set_banner_card_provider(file.bannerCardProvider.toStdString()); + newFile->set_color_identity(file.colorIdentity.toStdString()); + for (const QString &tag : file.tags) { newFile->add_tags(tag.toStdString()); } } @@ -716,7 +703,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdDeckList(const Command_ return Response::RespFunctionNotAllowed; } - sqlInterface->checkSql(); + databaseInterface->checkSql(); Response_DeckList *re = new Response_DeckList; ServerInfo_DeckStorage_Folder *root = re->mutable_root(); @@ -736,10 +723,10 @@ Response::ResponseCode AbstractServerSocketInterface::cmdDeckListOtherUser(const return Response::RespFunctionNotAllowed; } - sqlInterface->checkSql(); + databaseInterface->checkSql(); const QString userName = nameFromStdString(cmd.user_name()); - const int userId = sqlInterface->getUserIdInDB(userName); + const int userId = databaseInterface->getUserId(userName); if (userId == -1) { return Response::RespNameNotFound; } @@ -795,7 +782,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdDeckDownloadPublic(cons return Response::RespFunctionNotAllowed; } - sqlInterface->checkSql(); + databaseInterface->checkSql(); const int deckId = cmd.deck_id(); const int ownerId = databaseInterface->getDeckOwnerId(deckId); @@ -805,7 +792,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdDeckDownloadPublic(cons DeckList *deck; try { - deck = sqlInterface->getDeckFromDatabase(deckId, ownerId); + deck = databaseInterface->getDeckFromDatabase(deckId, ownerId); } catch (Response::ResponseCode &r) { return r; } @@ -1000,7 +987,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdDeckDownload(const Comm DeckList *deck; try { - deck = sqlInterface->getDeckFromDatabase(cmd.deck_id(), userInfo->id()); + deck = databaseInterface->getDeckFromDatabase(cmd.deck_id(), userInfo->id()); } catch (Response::ResponseCode &r) { return r; } diff --git a/servatrice/src/serversocketinterface.h b/servatrice/src/serversocketinterface.h index a3c71d15b..5cb314dbc 100644 --- a/servatrice/src/serversocketinterface.h +++ b/servatrice/src/serversocketinterface.h @@ -139,8 +139,6 @@ protected: QMutex outputQueueMutex; private: - Servatrice_DatabaseInterface *sqlInterface; - 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);