mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-10 03:53:26 -08:00
[Server] Serve deck storage listings through the database interface (#7851)
deckListHelper still prepared the folder and deck-file statements inline through Servatrice_DatabaseInterface, and the four deck commands reached checkSql, getUserIdInDB and getDeckFromDatabase through a concrete pointer. Add DeckListFolderRecord, DeckListFileRecord, getDeckListFolders and getDeckListFiles to Server_DatabaseInterface with fail-closed defaults, serve all four commands from the injected interface, and drop the sqlInterface member so the handler no longer holds a database implementation at all. Folder ordering, recursion order, public-only pruning and every response code are unchanged.
This commit is contained in:
parent
1822d16a72
commit
99bdcebf2e
5 changed files with 106 additions and 40 deletions
|
|
@ -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<DeckListFolderRecord> & /* folders */)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual bool getDeckListFiles(int /* folderId */, int /* userId */, QList<DeckListFileRecord> & /* 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 */)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2062,6 +2062,58 @@ bool Servatrice_DatabaseInterface::getDeckFilesInFolder(int folderId, int userId
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Servatrice_DatabaseInterface::getDeckListFolders(int folderId, int userId, QList<DeckListFolderRecord> &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<DeckListFileRecord> &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<DeckShareSummaryRecord> &shares)
|
||||
{
|
||||
checkSql();
|
||||
|
|
|
|||
|
|
@ -124,6 +124,8 @@ public:
|
|||
const QSet<QString> &allSpectatorsEver,
|
||||
const QList<GameReplay *> &replayList) override;
|
||||
DeckList *getDeckFromDatabase(int deckId, int userId) override;
|
||||
bool getDeckListFolders(int folderId, int userId, QList<DeckListFolderRecord> &folders) override;
|
||||
bool getDeckListFiles(int folderId, int userId, QList<DeckListFileRecord> &files) override;
|
||||
|
||||
/**
|
||||
* @brief Creates a new temporary deck share bundle.
|
||||
|
|
|
|||
|
|
@ -68,7 +68,6 @@
|
|||
#include <QReadWriteLock>
|
||||
#include <QSharedPointer>
|
||||
#include <QSqlError>
|
||||
#include <QSqlQuery>
|
||||
#include <QString>
|
||||
#include <QStringLiteral>
|
||||
#include <QTextStream>
|
||||
|
|
@ -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<Server_DatabaseInterface::DeckListFolderRecord> folders;
|
||||
if (!databaseInterface->getDeckListFolders(folderId, userId, folders)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QList<std::pair<int, std::pair<QString, bool>>> 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<Server_DatabaseInterface::DeckListFileRecord> 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue