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 5ae9529d6..4d4f42de0 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/server_database_interface.h +++ b/libcockatrice_network/libcockatrice/network/server/remote/server_database_interface.h @@ -750,6 +750,36 @@ public: { } + /** @brief One channel row of a bootstrap room, with the access keys exactly as stored. */ + struct BootstrapRoomChannelRecord + { + QString id; + QString displayName; + QString accessKey; + bool hasWriteAccess = false; + QString writeAccessKey; + QString bannerMessage; + }; + /** @brief One room row of the SQL room bootstrap, with its game types and channels. */ + struct BootstrapRoomRecord + { + int id = 0; + QString name; + QString description; + QString permissionLevel; + QString privateLevel; + bool autoJoin = false; + QString joinMessage; + int chatHistorySize = 0; + QStringList gameTypes; + QList channels; + }; + /** @brief Every SQL-configured room for one server, in id order; empty when the query fails. */ + virtual QList getBootstrapRooms(int /* serverId */) + { + return {}; + } + virtual void clearSessionTables() { } diff --git a/servatrice/src/servatrice.cpp b/servatrice/src/servatrice.cpp index aa272fb53..30d2619ad 100644 --- a/servatrice/src/servatrice.cpp +++ b/servatrice/src/servatrice.cpp @@ -400,33 +400,12 @@ bool Servatrice::initServer() connect(smtpClient, &SmtpClient::mailPermanentlyFailed, this, &Servatrice::onEmailPermanentlyFailed); if (getRoomsMethodString() == "sql") { - QSqlQuery *query = servatriceDatabaseInterface->prepareQuery( - "select id, name, descr, permissionlevel, privlevel, auto_join, join_message, chat_history_size from " - "{prefix}_rooms where id_server = :id_server order by id asc"); - query->bindValue(":id_server", serverId); - servatriceDatabaseInterface->execSqlQuery(query); - while (query->next()) { - QSqlQuery *query2 = servatriceDatabaseInterface->prepareQuery( - "select name from {prefix}_rooms_gametypes where id_room = :id_room AND id_server = :id_server"); - query2->bindValue(":id_server", serverId); - query2->bindValue(":id_room", query->value(0).toInt()); - servatriceDatabaseInterface->execSqlQuery(query2); - QStringList gameTypes; - while (query2->next()) { - gameTypes.append(query2->value(0).toString()); - } - - QSqlQuery *query3 = servatriceDatabaseInterface->prepareQuery( - "select channel_id, display_name, access_level, write_access_level, banner_message from " - "{prefix}_rooms_channels where id_room = :id_room " - "AND id_server = :id_server order by channel_id asc"); - query3->bindValue(":id_server", serverId); - query3->bindValue(":id_room", query->value(0).toInt()); - servatriceDatabaseInterface->execSqlQuery(query3); + const auto bootstrapRooms = servatriceDatabaseInterface->getBootstrapRooms(serverId); + for (const auto &roomRecord : bootstrapRooms) { QList channels; QSet seenChannelIds; - while (query3->next()) { - const QString channelId = query3->value(0).toString(); + for (const auto &channelRecord : roomRecord.channels) { + const QString channelId = channelRecord.id; if (channelId.isEmpty()) { qWarning() << "Skipping room channel with empty id"; continue; @@ -440,7 +419,7 @@ bool Servatrice::initServer() continue; } seenChannelIds.insert(channelId); - const QString accessKey = query3->value(2).toString(); + const QString accessKey = channelRecord.accessKey; auto accessLevel = accessKey.trimmed().isEmpty() ? std::optional(ServerInfo_RoomChannel::Public) @@ -452,10 +431,10 @@ bool Servatrice::initServer() } ServerInfo_RoomChannel channel; channel.set_id(channelId.toStdString()); - channel.set_display_name(query3->value(1).toString().toStdString()); + channel.set_display_name(channelRecord.displayName.toStdString()); channel.set_access_level(accessLevel.value()); - if (!query3->isNull(3)) { - const QString writeKey = query3->value(3).toString(); + if (channelRecord.hasWriteAccess) { + const QString writeKey = channelRecord.writeAccessKey; if (!writeKey.trimmed().isEmpty()) { auto writeLevel = roomChannelAccessFromKey(writeKey); if (!writeLevel.has_value()) { @@ -466,14 +445,13 @@ bool Servatrice::initServer() channel.set_write_access_level(writeLevel.value()); } } - channel.set_banner_message(query3->value(4).toString().toStdString()); + channel.set_banner_message(channelRecord.bannerMessage.toStdString()); channels.append(channel); } - addRoom(new Server_Room(query->value(0).toInt(), query->value(7).toInt(), query->value(1).toString(), - query->value(2).toString(), query->value(3).toString().toLower(), - query->value(4).toString().toLower(), static_cast(query->value(5).toInt()), - query->value(6).toString(), gameTypes, this, channels)); + addRoom(new Server_Room(roomRecord.id, roomRecord.chatHistorySize, roomRecord.name, roomRecord.description, + roomRecord.permissionLevel.toLower(), roomRecord.privateLevel.toLower(), + roomRecord.autoJoin, roomRecord.joinMessage, roomRecord.gameTypes, this, channels)); } } else { int size = settingsCache->beginReadArray("rooms/roomlist"); diff --git a/servatrice/src/servatrice_database_interface.cpp b/servatrice/src/servatrice_database_interface.cpp index a2558f11b..50c51cfdd 100644 --- a/servatrice/src/servatrice_database_interface.cpp +++ b/servatrice/src/servatrice_database_interface.cpp @@ -3358,6 +3358,69 @@ void Servatrice_DatabaseInterface::recordUptime(const UptimeRecord &record) execSqlQuery(query); } +QList Servatrice_DatabaseInterface::getBootstrapRooms(int serverId) +{ + QList rooms; + if (!checkSql()) { + return rooms; + } + + QSqlQuery *query = prepareQuery( + "select id, name, descr, permissionlevel, privlevel, auto_join, join_message, chat_history_size from " + "{prefix}_rooms where id_server = :id_server order by id asc"); + query->bindValue(":id_server", serverId); + if (!execSqlQuery(query)) { + return rooms; + } + + while (query->next()) { + BootstrapRoomRecord room; + room.id = query->value(0).toInt(); + room.name = query->value(1).toString(); + room.description = query->value(2).toString(); + room.permissionLevel = query->value(3).toString(); + room.privateLevel = query->value(4).toString(); + room.autoJoin = query->value(5).toInt() != 0; + room.joinMessage = query->value(6).toString(); + room.chatHistorySize = query->value(7).toInt(); + + QSqlQuery *gameTypesQuery = prepareQuery( + "select name from {prefix}_rooms_gametypes where id_room = :id_room AND id_server = :id_server"); + gameTypesQuery->bindValue(":id_server", serverId); + gameTypesQuery->bindValue(":id_room", room.id); + if (execSqlQuery(gameTypesQuery)) { + while (gameTypesQuery->next()) { + room.gameTypes.append(gameTypesQuery->value(0).toString()); + } + } + + QSqlQuery *channelsQuery = + prepareQuery("select channel_id, display_name, access_level, write_access_level, banner_message from " + "{prefix}_rooms_channels where id_room = :id_room " + "AND id_server = :id_server order by channel_id asc"); + channelsQuery->bindValue(":id_server", serverId); + channelsQuery->bindValue(":id_room", room.id); + if (execSqlQuery(channelsQuery)) { + while (channelsQuery->next()) { + BootstrapRoomChannelRecord channel; + channel.id = channelsQuery->value(0).toString(); + channel.displayName = channelsQuery->value(1).toString(); + channel.accessKey = channelsQuery->value(2).toString(); + channel.hasWriteAccess = !channelsQuery->isNull(3); + if (channel.hasWriteAccess) { + channel.writeAccessKey = channelsQuery->value(3).toString(); + } + channel.bannerMessage = channelsQuery->value(4).toString(); + room.channels.append(channel); + } + } + + rooms.append(room); + } + + return rooms; +} + bool Servatrice_DatabaseInterface::removeUserAvatar(const QString &userName) { if (!checkSql()) { diff --git a/servatrice/src/servatrice_database_interface.h b/servatrice/src/servatrice_database_interface.h index 6a01b57ce..38a8e7e9f 100644 --- a/servatrice/src/servatrice_database_interface.h +++ b/servatrice/src/servatrice_database_interface.h @@ -281,6 +281,7 @@ public: bool getLatestServerMessage(int serverId, QString &message) override; QList getServerListEntries() override; void recordUptime(const UptimeRecord &record) override; + QList getBootstrapRooms(int serverId) override; bool removeUserAvatar(const QString &userName) override; // Outcome of removeUserBanner(), so the caller can tell a missing user apart // from a user who simply has no banner card set.