This commit is contained in:
BruebachL 2026-11-04 10:30:37 -07:00 • committed by GitHub
commit cd6f73888f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 286 additions and 46 deletions

View file

@ -710,7 +710,8 @@ bool AbstractServerSocketInterface::deckListHelper(int folderId,
query = sqlInterface->prepareQuery("select id, name, upload_time, is_public, banner_card_name, "
"banner_card_provider, color_identity, tags, guid, hash, last_modified from "
"{prefix}_decklist_files where id_folder = :id_folder and id_user = :id_user");
"{prefix}_decklist_files where id_folder = :id_folder and id_user = :id_user "
"and deleted = 0");
query->bindValue(":id_folder", folderId);
query->bindValue(":id_user", userId);
if (!sqlInterface->execSqlQuery(query)) {
@ -855,8 +856,8 @@ Response::ResponseCode AbstractServerSocketInterface::cmdDeckSetVisibility(const
sqlInterface->checkSql();
if (cmd.has_deck_id()) {
QSqlQuery *query =
sqlInterface->prepareQuery("select 1 from {prefix}_decklist_files where id = :id and id_user = :id_user");
QSqlQuery *query = sqlInterface->prepareQuery(
"select 1 from {prefix}_decklist_files where id = :id and id_user = :id_user and deleted = 0");
query->bindValue(":id", cmd.deck_id());
query->bindValue(":id_user", userInfo->id());
sqlInterface->execSqlQuery(query);
@ -966,7 +967,8 @@ void AbstractServerSocketInterface::deckDelDirHelper(int basePathId)
deckDelDirHelper(query->value(0).toInt());
}
query = sqlInterface->prepareQuery("delete from {prefix}_decklist_files where id_folder = :id_folder");
query = sqlInterface->prepareQuery("update {prefix}_decklist_files set deleted = 1, last_modified = NOW() "
"where id_folder = :id_folder and deleted = 0");
query->bindValue(":id_folder", basePathId);
sqlInterface->execSqlQuery(query);
@ -1017,18 +1019,17 @@ Response::ResponseCode AbstractServerSocketInterface::cmdDeckDel(const Command_D
sqlInterface->checkSql();
QSqlQuery *query =
sqlInterface->prepareQuery("select id from {prefix}_decklist_files where id = :id and id_user = :id_user");
sqlInterface->prepareQuery("update {prefix}_decklist_files set deleted = 1, last_modified = NOW() where id = "
":id and id_user = :id_user and deleted = 0");
query->bindValue(":id", cmd.deck_id());
query->bindValue(":id_user", userInfo->id());
sqlInterface->execSqlQuery(query);
if (!query->next()) {
if (!sqlInterface->execSqlQuery(query)) {
return Response::RespContextError;
}
if (query->numRowsAffected() == 0) {
return Response::RespNameNotFound;
}
query = sqlInterface->prepareQuery("delete from {prefix}_decklist_files where id = :id");
query->bindValue(":id", cmd.deck_id());
sqlInterface->execSqlQuery(query);
return Response::RespOk;
}
@ -1129,31 +1130,71 @@ Response::ResponseCode AbstractServerSocketInterface::cmdDeckUpload(const Comman
return Response::RespNameNotFound;
}
QSqlQuery *query =
sqlInterface->prepareQuery("insert into {prefix}_decklist_files (id_folder, id_user, name, upload_time, "
"content, is_public, banner_card_name, banner_card_provider, color_identity, "
"tags, guid, hash, last_modified) values(:id_folder, :id_user, :name, NOW(), "
":content, :is_public, :banner_card_name, :banner_card_provider, "
":color_identity, :tags, :guid, :hash, NOW())");
query->bindValue(":id_folder", folderId);
query->bindValue(":id_user", userInfo->id());
query->bindValue(":name", deckName);
query->bindValue(":content", deckStr);
query->bindValue(":is_public", cmd.has_is_public() && cmd.is_public() ? 1 : 0);
query->bindValue(":banner_card_name", bannerCardName);
query->bindValue(":banner_card_provider", bannerCardProvider);
query->bindValue(":color_identity", colorIdentity);
query->bindValue(":tags", tagsJson);
query->bindValue(":guid", guid);
query->bindValue(":hash", deckHash);
if (!sqlInterface->execSqlQuery(query)) {
// A deck that was deleted elsewhere leaves a tombstone behind. Revive it
// instead of inserting a second row with the same guid, which would split
// the deck's version history and leave the tombstone to be purged.
int deckId = -1;
bool inserted = false;
QSqlQuery *tombstoneQuery =
sqlInterface->prepareQuery("select id from {prefix}_decklist_files where id_user = :id_user and guid = "
":guid and deleted = 1 order by last_modified desc limit 1");
tombstoneQuery->bindValue(":id_user", userInfo->id());
tombstoneQuery->bindValue(":guid", guid);
if (!sqlInterface->execSqlQuery(tombstoneQuery)) {
return Response::RespContextError;
}
const int deckId = query->lastInsertId().toInt();
if (tombstoneQuery->next()) {
deckId = tombstoneQuery->value(0).toInt();
QSqlQuery *reviveQuery = sqlInterface->prepareQuery(
"update {prefix}_decklist_files set id_folder=:id_folder, name=:name, upload_time=NOW(), "
"content=:content, is_public=:is_public, banner_card_name=:banner_card_name, "
"banner_card_provider=:banner_card_provider, color_identity=:color_identity, tags=:tags, "
"hash=:hash, last_modified=NOW(), deleted=0 where id=:id and id_user=:id_user");
reviveQuery->bindValue(":id_folder", folderId);
reviveQuery->bindValue(":id_user", userInfo->id());
reviveQuery->bindValue(":id", deckId);
reviveQuery->bindValue(":name", deckName);
reviveQuery->bindValue(":content", deckStr);
reviveQuery->bindValue(":is_public", cmd.has_is_public() && cmd.is_public() ? 1 : 0);
reviveQuery->bindValue(":banner_card_name", bannerCardName);
reviveQuery->bindValue(":banner_card_provider", bannerCardProvider);
reviveQuery->bindValue(":color_identity", colorIdentity);
reviveQuery->bindValue(":tags", tagsJson);
reviveQuery->bindValue(":hash", deckHash);
if (!sqlInterface->execSqlQuery(reviveQuery)) {
return Response::RespContextError;
}
} else {
QSqlQuery *query = sqlInterface->prepareQuery(
"insert into {prefix}_decklist_files (id_folder, id_user, name, upload_time, "
"content, is_public, banner_card_name, banner_card_provider, color_identity, "
"tags, guid, hash, last_modified) values(:id_folder, :id_user, :name, NOW(), "
":content, :is_public, :banner_card_name, :banner_card_provider, "
":color_identity, :tags, :guid, :hash, NOW())");
query->bindValue(":id_folder", folderId);
query->bindValue(":id_user", userInfo->id());
query->bindValue(":name", deckName);
query->bindValue(":content", deckStr);
query->bindValue(":is_public", cmd.has_is_public() && cmd.is_public() ? 1 : 0);
query->bindValue(":banner_card_name", bannerCardName);
query->bindValue(":banner_card_provider", bannerCardProvider);
query->bindValue(":color_identity", colorIdentity);
query->bindValue(":tags", tagsJson);
query->bindValue(":guid", guid);
query->bindValue(":hash", deckHash);
if (!sqlInterface->execSqlQuery(query)) {
return Response::RespContextError;
}
deckId = query->lastInsertId().toInt();
inserted = true;
}
if (!storeDeckVersion(deckId, deckStr, deckHash)) {
QSqlQuery *cleanupQuery = sqlInterface->prepareQuery("delete from {prefix}_decklist_files where id = :id");
cleanupQuery->bindValue(":id", deckId);
sqlInterface->execSqlQuery(cleanupQuery);
if (inserted) {
QSqlQuery *cleanupQuery =
sqlInterface->prepareQuery("delete from {prefix}_decklist_files where id = :id");
cleanupQuery->bindValue(":id", deckId);
sqlInterface->execSqlQuery(cleanupQuery);
}
return Response::RespContextError;
}
@ -1163,9 +1204,12 @@ Response::ResponseCode AbstractServerSocketInterface::cmdDeckUpload(const Comman
stampQuery->bindValue(":id", deckId);
stampQuery->bindValue(":id_user", userInfo->id());
if (!sqlInterface->execSqlQuery(stampQuery) || !stampQuery->next()) {
QSqlQuery *cleanupQuery = sqlInterface->prepareQuery("delete from {prefix}_decklist_files where id = :id");
cleanupQuery->bindValue(":id", deckId);
sqlInterface->execSqlQuery(cleanupQuery);
if (inserted) {
QSqlQuery *cleanupQuery =
sqlInterface->prepareQuery("delete from {prefix}_decklist_files where id = :id");
cleanupQuery->bindValue(":id", deckId);
sqlInterface->execSqlQuery(cleanupQuery);
}
return Response::RespContextError;
}
@ -1198,9 +1242,11 @@ Response::ResponseCode AbstractServerSocketInterface::cmdDeckUpload(const Comman
}
const QString oldHash = currentQuery->value(1).toString();
QString updateQuery = "update {prefix}_decklist_files set name=:name, upload_time=NOW(), content=:content, "
"banner_card_name=:banner_card_name, banner_card_provider=:banner_card_provider, "
"color_identity=:color_identity, tags=:tags, guid=:guid, hash=:hash, last_modified=NOW()";
QString updateQuery =
"update {prefix}_decklist_files set name=:name, upload_time=NOW(), content=:content, "
"banner_card_name=:banner_card_name, banner_card_provider=:banner_card_provider, "
"color_identity=:color_identity, tags=:tags, guid=:guid, hash=:hash, last_modified=NOW(), "
"deleted=0";
if (cmd.has_is_public()) {
updateQuery += ", is_public=:is_public";
}
@ -1402,7 +1448,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdDeckShareCreate(const C
// issues its own query on the same cached statement set.
QSqlQuery *query =
sqlInterface->prepareQuery("select id, color_identity from {prefix}_decklist_files where id_folder = "
":id_folder and id_user = :id_user");
":id_folder and id_user = :id_user and deleted = 0");
query->bindValue(":id_folder", folderId);
query->bindValue(":id_user", userInfo->id());
if (!sqlInterface->execSqlQuery(query)) {