From ff6c0402a86e22ca7e56f16d3dfb1a4136e294a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Sun, 1 Nov 2026 05:57:17 +0100 Subject: [PATCH] Fix remaining review threads on the user alts tab - Switch to the User Alts tab when it is created, so the first investigate click does not open it in the background. - Treat an empty RespOk as "user not found" and use a generic message for error codes, matching what the server actually returns. - Exclude the depth-0 seed row from the related-account count. - Guard the reply with the requested user name so a stale response cannot overwrite a newer one. - Move the duplicated formatEpoch body into widgets/utility/epoch_format.h. --- cockatrice/CMakeLists.txt | 1 + .../src/interface/widgets/tabs/tab_alts.cpp | 27 ++++++++++++++----- .../interface/widgets/tabs/tab_moderation.cpp | 6 ++--- .../interface/widgets/tabs/tab_supervisor.cpp | 1 + .../interface/widgets/utility/epoch_format.h | 27 +++++++++++++++++++ 5 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 cockatrice/src/interface/widgets/utility/epoch_format.h diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt index f744ac846..57131e8b6 100644 --- a/cockatrice/CMakeLists.txt +++ b/cockatrice/CMakeLists.txt @@ -285,6 +285,7 @@ set(cockatrice_SOURCES src/interface/widgets/settings_page/storage_settings_page.cpp src/interface/widgets/settings_page/user_interface_settings_page.cpp src/interface/widgets/utility/custom_line_edit.cpp + src/interface/widgets/utility/epoch_format.h src/interface/widgets/utility/get_text_with_max.cpp src/interface/widgets/utility/report_utils.cpp src/interface/widgets/utility/report_utils.h diff --git a/cockatrice/src/interface/widgets/tabs/tab_alts.cpp b/cockatrice/src/interface/widgets/tabs/tab_alts.cpp index d43f5cfc6..b3b31b8da 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_alts.cpp +++ b/cockatrice/src/interface/widgets/tabs/tab_alts.cpp @@ -1,5 +1,6 @@ #include "tab_alts.h" +#include "../utility/epoch_format.h" #include "abstract_client.h" #include "libcockatrice/protocol/pb/response.pb.h" #include "libcockatrice/protocol/pb/response_user_alts.pb.h" @@ -99,10 +100,7 @@ void TabAlts::retranslateUi() QString TabAlts::formatEpoch(quint64 ts) const { - if (ts == 0) { - return tr("Unknown"); - } - return QDateTime::fromSecsSinceEpoch(ts).toLocalTime().toString("yyyy-MM-dd HH:mm"); + return formatEpochTimestamp(ts, tr("Unknown")); } void TabAlts::investigate(const QString &userName) @@ -132,7 +130,11 @@ void TabAlts::requestAlts(const QString &userName, int depth) cmd.set_user_name(userName.toStdString()); cmd.set_depth(static_cast(depth)); PendingCommand *pend = client->prepareModeratorCommand(cmd); - connect(pend, &PendingCommand::finished, this, &TabAlts::altsResponse); + connect(pend, &PendingCommand::finished, this, [this, userName](const Response &response) { + if (userName == currentUser) { + altsResponse(response); + } + }); client->sendCommand(pend); } @@ -140,14 +142,25 @@ void TabAlts::altsResponse(const Response &response) { altsTable->setRowCount(0); if (response.response_code() != Response::RespOk) { - statusLabel->setText(tr("User %1 not found.").arg(currentUser)); + statusLabel->setText(tr("Could not load alts for %1.").arg(currentUser)); return; } const Response_UserAlts &resp = response.GetExtension(Response_UserAlts::ext); + // The server answers RespOk with no rows when the user does not exist. + if (resp.alts_size() == 0) { + statusLabel->setText(tr("User %1 not found.").arg(currentUser)); + return; + } + altsTable->setRowCount(resp.alts_size()); + int relatedCount = 0; for (int i = 0; i < resp.alts_size(); ++i) { const ServerInfo_UserAlt &alt = resp.alts(i); + // The server appends the frontier user as a depth-0 seed row. + if (!alt.has_depth() || alt.depth() > 0) { + ++relatedCount; + } altsTable->setItem(i, COL_ALTS_USER, new QTableWidgetItem(QString::fromStdString(alt.user_name()))); altsTable->setItem(i, COL_ALTS_VIA, new QTableWidgetItem(alt.has_match_reason() && !alt.match_reason().empty() @@ -166,5 +179,5 @@ void TabAlts::altsResponse(const Response &response) altsTable->setItem(i, COL_ALTS_BANS, new QTableWidgetItem(QString::number(alt.ban_count()))); altsTable->setItem(i, COL_ALTS_ACTIVE, new QTableWidgetItem(alt.is_active() ? tr("yes") : tr("no"))); } - statusLabel->setText(tr("%1 account(s) related to %2.").arg(resp.alts_size()).arg(currentUser)); + statusLabel->setText(tr("%1 account(s) related to %2.").arg(relatedCount).arg(currentUser)); } diff --git a/cockatrice/src/interface/widgets/tabs/tab_moderation.cpp b/cockatrice/src/interface/widgets/tabs/tab_moderation.cpp index be1adeef8..c28217f25 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_moderation.cpp +++ b/cockatrice/src/interface/widgets/tabs/tab_moderation.cpp @@ -1,5 +1,6 @@ #include "tab_moderation.h" +#include "../utility/epoch_format.h" #include "abstract_client.h" #include "libcockatrice/protocol/pb/admin_commands.pb.h" #include "libcockatrice/protocol/pb/response.pb.h" @@ -215,10 +216,7 @@ void TabModeration::retranslateUi() QString TabModeration::formatEpoch(quint64 ts) const { - if (ts == 0) { - return tr("Unknown"); - } - return QDateTime::fromSecsSinceEpoch(ts).toLocalTime().toString("yyyy-MM-dd HH:mm"); + return formatEpochTimestamp(ts, tr("Unknown")); } void TabModeration::clearUserData() diff --git a/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp b/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp index b607e6f30..ea4c09a09 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp +++ b/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp @@ -933,6 +933,7 @@ void TabSupervisor::openTabAlts(const QString &userName) } tabAlts = new TabAlts(this, client, userName); myAddTab(tabAlts); + setCurrentWidget(tabAlts); connect(tabAlts, &QObject::destroyed, this, [this] { tabAlts = nullptr; }); } diff --git a/cockatrice/src/interface/widgets/utility/epoch_format.h b/cockatrice/src/interface/widgets/utility/epoch_format.h new file mode 100644 index 000000000..977053997 --- /dev/null +++ b/cockatrice/src/interface/widgets/utility/epoch_format.h @@ -0,0 +1,27 @@ +/** + * @file epoch_format.h + * @brief Shared timestamp formatting for the moderation tables. + */ + +#ifndef EPOCH_FORMAT_H +#define EPOCH_FORMAT_H + +#include +#include + +/** + * @brief Format a unix timestamp the way the moderation tabs show dates. + * + * @param ts Seconds since the epoch; 0 means "unknown". + * @param unknownText Label returned for 0, translated by the caller so the + * translation context stays with the tab. + */ +inline QString formatEpochTimestamp(quint64 ts, const QString &unknownText) +{ + if (ts == 0) { + return unknownText; + } + return QDateTime::fromSecsSinceEpoch(ts).toLocalTime().toString(QStringLiteral("yyyy-MM-dd HH:mm")); +} + +#endif // EPOCH_FORMAT_H