mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-07 18:43:26 -08:00
[Client] Moderation and alts dashboards
Turn the two staff tables into dashboards without behavior changes: TabModeration gets an identity header (display-size name, status, registered/last-login subline), Reports/Warnings/Bans/Alts count cards with an Open-graph deep link, full-width admin notes, and Alts/Sessions/Staff tabbed sections with tab memory. TabAlts gets toggle chips with match counts, bold usernames, palette-token dimming of shared-IP rows, and a resizable side card for the selected-user timeline with selection restore. Row activation works via Enter as well as double-click; async responses are guarded against stale investigations and retranslation re-applies cached dashboard data.
This commit is contained in:
parent
8e03e295cd
commit
bf1857f28a
4 changed files with 281 additions and 125 deletions
|
|
@ -6,17 +6,19 @@
|
||||||
#include "libcockatrice/protocol/pb/response_user_alts.pb.h"
|
#include "libcockatrice/protocol/pb/response_user_alts.pb.h"
|
||||||
|
|
||||||
#include <QAbstractItemView>
|
#include <QAbstractItemView>
|
||||||
#include <QCheckBox>
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
#include <QGroupBox>
|
#include <QGroupBox>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
|
#include <QItemSelectionModel>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
#include <QSignalBlocker>
|
||||||
#include <QSpinBox>
|
#include <QSpinBox>
|
||||||
|
#include <QSplitter>
|
||||||
#include <QTableWidget>
|
#include <QTableWidget>
|
||||||
#include <QTableWidgetItem>
|
#include <QTableWidgetItem>
|
||||||
#include <QTextEdit>
|
#include <QTextEdit>
|
||||||
|
|
@ -47,6 +49,17 @@ constexpr int COL_ALTS_BANS = 9;
|
||||||
constexpr int COL_ALTS_ACTIVE = 10;
|
constexpr int COL_ALTS_ACTIVE = 10;
|
||||||
constexpr int COL_ALTS_COUNT = 11;
|
constexpr int COL_ALTS_COUNT = 11;
|
||||||
|
|
||||||
|
constexpr int COL_WARNS_TIME = 0;
|
||||||
|
constexpr int COL_WARNS_MODERATOR = 1;
|
||||||
|
constexpr int COL_WARNS_REASON = 2;
|
||||||
|
constexpr int COL_WARNS_COUNT = 3;
|
||||||
|
|
||||||
|
constexpr int COL_BANS_TIME = 0;
|
||||||
|
constexpr int COL_BANS_MODERATOR = 1;
|
||||||
|
constexpr int COL_BANS_LENGTH = 2;
|
||||||
|
constexpr int COL_BANS_REASON = 3;
|
||||||
|
constexpr int COL_BANS_COUNT = 4;
|
||||||
|
|
||||||
constexpr int MAX_ALT_DEPTH = 3;
|
constexpr int MAX_ALT_DEPTH = 3;
|
||||||
// Starting default only (adjustable 1-100000): shared VPN exits routinely
|
// Starting default only (adjustable 1-100000): shared VPN exits routinely
|
||||||
// cover dozens of users, so 10 hides the obvious VPN noise but keeps
|
// cover dozens of users, so 10 hides the obvious VPN noise but keeps
|
||||||
|
|
@ -95,15 +108,16 @@ TabAlts::TabAlts(TabSupervisor *_tabSupervisor, AbstractClient *_client, const Q
|
||||||
topBar->addWidget(depthSpin);
|
topBar->addWidget(depthSpin);
|
||||||
topBar->addWidget(investigateButton);
|
topBar->addWidget(investigateButton);
|
||||||
|
|
||||||
emailCheck = new QCheckBox;
|
auto makeChip = [this](const QString &text) {
|
||||||
emailCheck->setChecked(true);
|
auto *chip = new QPushButton(text);
|
||||||
connect(emailCheck, &QCheckBox::toggled, this, &TabAlts::onFilterChanged);
|
chip->setCheckable(true);
|
||||||
clientIdCheck = new QCheckBox;
|
chip->setChecked(true);
|
||||||
clientIdCheck->setChecked(true);
|
connect(chip, &QPushButton::toggled, this, &TabAlts::onFilterChanged);
|
||||||
connect(clientIdCheck, &QCheckBox::toggled, this, &TabAlts::onFilterChanged);
|
return chip;
|
||||||
ipCheck = new QCheckBox;
|
};
|
||||||
ipCheck->setChecked(true);
|
emailChip = makeChip(QString());
|
||||||
connect(ipCheck, &QCheckBox::toggled, this, &TabAlts::onFilterChanged);
|
clientIdChip = makeChip(QString());
|
||||||
|
ipChip = makeChip(QString());
|
||||||
vpnLabel = new QLabel;
|
vpnLabel = new QLabel;
|
||||||
vpnSpin = new QSpinBox;
|
vpnSpin = new QSpinBox;
|
||||||
vpnSpin->setMinimum(1);
|
vpnSpin->setMinimum(1);
|
||||||
|
|
@ -112,17 +126,20 @@ TabAlts::TabAlts(TabSupervisor *_tabSupervisor, AbstractClient *_client, const Q
|
||||||
connect(vpnSpin, &QSpinBox::valueChanged, this, &TabAlts::onFilterChanged);
|
connect(vpnSpin, &QSpinBox::valueChanged, this, &TabAlts::onFilterChanged);
|
||||||
|
|
||||||
auto *filterBar = new QHBoxLayout;
|
auto *filterBar = new QHBoxLayout;
|
||||||
filterBar->addWidget(emailCheck);
|
filterBar->addWidget(emailChip);
|
||||||
filterBar->addWidget(clientIdCheck);
|
filterBar->addWidget(clientIdChip);
|
||||||
filterBar->addWidget(ipCheck);
|
filterBar->addWidget(ipChip);
|
||||||
filterBar->addWidget(vpnLabel);
|
filterBar->addWidget(vpnLabel);
|
||||||
filterBar->addWidget(vpnSpin);
|
filterBar->addWidget(vpnSpin);
|
||||||
filterBar->addStretch();
|
filterBar->addStretch();
|
||||||
|
|
||||||
altsTable = new QTableWidget(0, COL_ALTS_COUNT);
|
altsTable = new QTableWidget(0, COL_ALTS_COUNT);
|
||||||
configureAltTable(altsTable);
|
configureAltTable(altsTable);
|
||||||
connect(altsTable, &QTableWidget::cellDoubleClicked, this, [this](int row, int) {
|
connect(altsTable, &QTableWidget::activated, this, [this](const QModelIndex &index) {
|
||||||
auto *userItem = altsTable->item(row, COL_ALTS_USER);
|
if (!index.isValid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto *userItem = altsTable->item(index.row(), COL_ALTS_USER);
|
||||||
if (userItem != nullptr && !userItem->text().isEmpty() && userItem->text() != currentUser) {
|
if (userItem != nullptr && !userItem->text().isEmpty() && userItem->text() != currentUser) {
|
||||||
investigate(userItem->text());
|
investigate(userItem->text());
|
||||||
}
|
}
|
||||||
|
|
@ -135,9 +152,9 @@ TabAlts::TabAlts(TabSupervisor *_tabSupervisor, AbstractClient *_client, const Q
|
||||||
detailNotesEdit->setReadOnly(true);
|
detailNotesEdit->setReadOnly(true);
|
||||||
// Compact cap so the warn/ban tables stay visible without scrolling the tab.
|
// Compact cap so the warn/ban tables stay visible without scrolling the tab.
|
||||||
detailNotesEdit->setMaximumHeight(60);
|
detailNotesEdit->setMaximumHeight(60);
|
||||||
warnsTable = new QTableWidget(0, 3);
|
warnsTable = new QTableWidget(0, COL_WARNS_COUNT);
|
||||||
configureAltTable(warnsTable);
|
configureAltTable(warnsTable);
|
||||||
bansTable = new QTableWidget(0, 4);
|
bansTable = new QTableWidget(0, COL_BANS_COUNT);
|
||||||
configureAltTable(bansTable);
|
configureAltTable(bansTable);
|
||||||
|
|
||||||
auto *detailGrid = new QGridLayout;
|
auto *detailGrid = new QGridLayout;
|
||||||
|
|
@ -151,21 +168,24 @@ TabAlts::TabAlts(TabSupervisor *_tabSupervisor, AbstractClient *_client, const Q
|
||||||
detailGrid->addWidget(detailNotesLabel, 1, 0);
|
detailGrid->addWidget(detailNotesLabel, 1, 0);
|
||||||
detailGrid->addWidget(detailNotesEdit, 1, 1, 1, 3);
|
detailGrid->addWidget(detailNotesEdit, 1, 1, 1, 3);
|
||||||
|
|
||||||
auto *detailTables = new QHBoxLayout;
|
|
||||||
detailTables->addWidget(warnsTable);
|
|
||||||
detailTables->addWidget(bansTable);
|
|
||||||
|
|
||||||
detailsGroup = new QGroupBox;
|
detailsGroup = new QGroupBox;
|
||||||
auto *detailsLayout = new QVBoxLayout(detailsGroup);
|
auto *detailsLayout = new QVBoxLayout(detailsGroup);
|
||||||
detailsLayout->addLayout(detailGrid);
|
detailsLayout->addLayout(detailGrid);
|
||||||
detailsLayout->addLayout(detailTables);
|
detailsLayout->addWidget(warnsTable, 1);
|
||||||
|
detailsLayout->addWidget(bansTable, 1);
|
||||||
|
|
||||||
|
auto *contentSplitter = new QSplitter(Qt::Horizontal);
|
||||||
|
contentSplitter->addWidget(altsTable);
|
||||||
|
contentSplitter->addWidget(detailsGroup);
|
||||||
|
contentSplitter->setStretchFactor(0, 3);
|
||||||
|
contentSplitter->setStretchFactor(1, 2);
|
||||||
|
detailsGroup->setMinimumWidth(260);
|
||||||
|
|
||||||
auto *mainLayout = new QVBoxLayout(centralWidget);
|
auto *mainLayout = new QVBoxLayout(centralWidget);
|
||||||
mainLayout->addLayout(topBar);
|
mainLayout->addLayout(topBar);
|
||||||
mainLayout->addLayout(filterBar);
|
mainLayout->addLayout(filterBar);
|
||||||
mainLayout->addWidget(statusLabel);
|
mainLayout->addWidget(statusLabel);
|
||||||
mainLayout->addWidget(altsTable, 3);
|
mainLayout->addWidget(contentSplitter, 1);
|
||||||
mainLayout->addWidget(detailsGroup, 2);
|
|
||||||
|
|
||||||
retranslateUi();
|
retranslateUi();
|
||||||
clearDetails();
|
clearDetails();
|
||||||
|
|
@ -184,15 +204,19 @@ void TabAlts::retranslateUi()
|
||||||
statusLabel->setText(tr("Enter a user name to investigate."));
|
statusLabel->setText(tr("Enter a user name to investigate."));
|
||||||
}
|
}
|
||||||
|
|
||||||
emailCheck->setText(tr("Email"));
|
emailChip->setText(tr("Email"));
|
||||||
clientIdCheck->setText(tr("Client ID"));
|
emailChip->setToolTip(tr("Show or hide email matches"));
|
||||||
ipCheck->setText(tr("IP"));
|
clientIdChip->setText(tr("Client ID"));
|
||||||
|
clientIdChip->setToolTip(tr("Show or hide client ID matches"));
|
||||||
|
ipChip->setText(tr("IP"));
|
||||||
|
ipChip->setToolTip(tr("Show or hide IP address matches"));
|
||||||
vpnLabel->setText(tr("Hide IPs shared by more than"));
|
vpnLabel->setText(tr("Hide IPs shared by more than"));
|
||||||
vpnSpin->setSuffix(tr(" users"));
|
vpnSpin->setSuffix(tr(" users"));
|
||||||
|
|
||||||
altsTable->setHorizontalHeaderLabels({tr("User"), tr("Via"), tr("Depth"), tr("Shared"), tr("eMail"),
|
altsTable->setHorizontalHeaderLabels({tr("User"), tr("Via"), tr("Depth"), tr("Shared"), tr("eMail"),
|
||||||
tr("Client ID"), tr("Registered"), tr("Last login"), tr("Warns"), tr("Bans"),
|
tr("Client ID"), tr("Registered"), tr("Last login"), tr("Warns"), tr("Bans"),
|
||||||
tr("Active")});
|
tr("Active")});
|
||||||
|
altsTable->setToolTip(tr("Double-click or press Enter on a row to investigate that account"));
|
||||||
warnsTable->setHorizontalHeaderLabels({tr("Warning time"), tr("Moderator"), tr("Reason")});
|
warnsTable->setHorizontalHeaderLabels({tr("Warning time"), tr("Moderator"), tr("Reason")});
|
||||||
bansTable->setHorizontalHeaderLabels({tr("Ban time"), tr("Moderator"), tr("Length"), tr("Reason")});
|
bansTable->setHorizontalHeaderLabels({tr("Ban time"), tr("Moderator"), tr("Length"), tr("Reason")});
|
||||||
|
|
||||||
|
|
@ -200,6 +224,10 @@ void TabAlts::retranslateUi()
|
||||||
detailNameLabel->setText(tr("Name:"));
|
detailNameLabel->setText(tr("Name:"));
|
||||||
detailCountsLabel->setText(tr("Counts:"));
|
detailCountsLabel->setText(tr("Counts:"));
|
||||||
detailNotesLabel->setText(tr("Admin notes:"));
|
detailNotesLabel->setText(tr("Admin notes:"));
|
||||||
|
|
||||||
|
if (!lastAlts.isEmpty()) {
|
||||||
|
renderTable();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TabAlts::formatEpoch(quint64 ts) const
|
QString TabAlts::formatEpoch(quint64 ts) const
|
||||||
|
|
@ -297,13 +325,13 @@ bool TabAlts::rowVisible(const ServerInfo_UserAlt &alt) const
|
||||||
}
|
}
|
||||||
const QString reason = QString::fromStdString(alt.match_reason());
|
const QString reason = QString::fromStdString(alt.match_reason());
|
||||||
if (reason == QStringLiteral("email")) {
|
if (reason == QStringLiteral("email")) {
|
||||||
return emailCheck->isChecked();
|
return emailChip->isChecked();
|
||||||
}
|
}
|
||||||
if (reason.startsWith(QStringLiteral("clientid:"))) {
|
if (reason.startsWith(QStringLiteral("clientid:"))) {
|
||||||
return clientIdCheck->isChecked();
|
return clientIdChip->isChecked();
|
||||||
}
|
}
|
||||||
if (reason.startsWith(QStringLiteral("ip:"))) {
|
if (reason.startsWith(QStringLiteral("ip:"))) {
|
||||||
return ipCheck->isChecked() &&
|
return ipChip->isChecked() &&
|
||||||
(!alt.has_shared_count() || alt.shared_count() <= static_cast<unsigned>(vpnSpin->value()));
|
(!alt.has_shared_count() || alt.shared_count() <= static_cast<unsigned>(vpnSpin->value()));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -311,7 +339,32 @@ bool TabAlts::rowVisible(const ServerInfo_UserAlt &alt) const
|
||||||
|
|
||||||
void TabAlts::renderTable()
|
void TabAlts::renderTable()
|
||||||
{
|
{
|
||||||
|
// Blocked so the programmatic refill neither wipes the details panel
|
||||||
|
// (via the selection-cleared path) nor refetches them on restore.
|
||||||
|
const QSignalBlocker blocker(altsTable);
|
||||||
altsTable->setRowCount(0);
|
altsTable->setRowCount(0);
|
||||||
|
|
||||||
|
int emailCount = 0;
|
||||||
|
int clientIdCount = 0;
|
||||||
|
int ipCount = 0;
|
||||||
|
for (const ServerInfo_UserAlt &alt : lastAlts) {
|
||||||
|
const QString reason = QString::fromStdString(alt.match_reason());
|
||||||
|
if (reason == QStringLiteral("email")) {
|
||||||
|
++emailCount;
|
||||||
|
} else if (reason.startsWith(QStringLiteral("clientid:"))) {
|
||||||
|
++clientIdCount;
|
||||||
|
} else if (reason.startsWith(QStringLiteral("ip:"))) {
|
||||||
|
++ipCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emailChip->setText(tr("Email (%1)").arg(emailCount));
|
||||||
|
clientIdChip->setText(tr("Client ID (%1)").arg(clientIdCount));
|
||||||
|
ipChip->setText(tr("IP (%1)").arg(ipCount));
|
||||||
|
|
||||||
|
QFont userFont = altsTable->font();
|
||||||
|
userFont.setBold(true);
|
||||||
|
const QColor dimColor = palette().color(QPalette::Disabled, QPalette::Text);
|
||||||
|
|
||||||
int hidden = 0;
|
int hidden = 0;
|
||||||
int row = 0;
|
int row = 0;
|
||||||
for (const ServerInfo_UserAlt &alt : lastAlts) {
|
for (const ServerInfo_UserAlt &alt : lastAlts) {
|
||||||
|
|
@ -320,7 +373,9 @@ void TabAlts::renderTable()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
altsTable->insertRow(row);
|
altsTable->insertRow(row);
|
||||||
altsTable->setItem(row, COL_ALTS_USER, new QTableWidgetItem(QString::fromStdString(alt.user_name())));
|
auto *userItem = new QTableWidgetItem(QString::fromStdString(alt.user_name()));
|
||||||
|
userItem->setFont(userFont);
|
||||||
|
altsTable->setItem(row, COL_ALTS_USER, userItem);
|
||||||
altsTable->setItem(row, COL_ALTS_VIA,
|
altsTable->setItem(row, COL_ALTS_VIA,
|
||||||
new QTableWidgetItem(alt.has_match_reason() && !alt.match_reason().empty()
|
new QTableWidgetItem(alt.has_match_reason() && !alt.match_reason().empty()
|
||||||
? QString::fromStdString(alt.match_reason())
|
? QString::fromStdString(alt.match_reason())
|
||||||
|
|
@ -337,6 +392,14 @@ void TabAlts::renderTable()
|
||||||
altsTable->setItem(row, COL_ALTS_WARNS, new QTableWidgetItem(QString::number(alt.warn_count())));
|
altsTable->setItem(row, COL_ALTS_WARNS, new QTableWidgetItem(QString::number(alt.warn_count())));
|
||||||
altsTable->setItem(row, COL_ALTS_BANS, new QTableWidgetItem(QString::number(alt.ban_count())));
|
altsTable->setItem(row, COL_ALTS_BANS, new QTableWidgetItem(QString::number(alt.ban_count())));
|
||||||
altsTable->setItem(row, COL_ALTS_ACTIVE, new QTableWidgetItem(alt.is_active() ? tr("yes") : tr("no")));
|
altsTable->setItem(row, COL_ALTS_ACTIVE, new QTableWidgetItem(alt.is_active() ? tr("yes") : tr("no")));
|
||||||
|
if (QString::fromStdString(alt.match_reason()).startsWith(QStringLiteral("ip:")) && alt.has_shared_count() &&
|
||||||
|
alt.shared_count() > 1) {
|
||||||
|
for (int col = 0; col < COL_ALTS_COUNT; ++col) {
|
||||||
|
if (auto *item = altsTable->item(row, col)) {
|
||||||
|
item->setForeground(dimColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
++row;
|
++row;
|
||||||
}
|
}
|
||||||
// The server appends the frontier user as a depth-0 seed row; it is the
|
// The server appends the frontier user as a depth-0 seed row; it is the
|
||||||
|
|
@ -356,6 +419,22 @@ void TabAlts::renderTable()
|
||||||
.arg(relatedCount)
|
.arg(relatedCount)
|
||||||
.arg(currentUser));
|
.arg(currentUser));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!selectedUser.isEmpty()) {
|
||||||
|
bool restored = false;
|
||||||
|
for (int restoreRow = 0; restoreRow < altsTable->rowCount(); ++restoreRow) {
|
||||||
|
auto *userItem = altsTable->item(restoreRow, COL_ALTS_USER);
|
||||||
|
if (userItem != nullptr && userItem->text() == selectedUser) {
|
||||||
|
altsTable->setCurrentItem(userItem, QItemSelectionModel::Select | QItemSelectionModel::Rows);
|
||||||
|
restored = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!restored) {
|
||||||
|
selectedUser.clear();
|
||||||
|
clearDetails();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabAlts::onFilterChanged()
|
void TabAlts::onFilterChanged()
|
||||||
|
|
@ -424,7 +503,7 @@ void TabAlts::requestDetails(const QString &userName)
|
||||||
void TabAlts::clearDetails()
|
void TabAlts::clearDetails()
|
||||||
{
|
{
|
||||||
detailNameValue->clear();
|
detailNameValue->clear();
|
||||||
detailCountsValue->clear();
|
detailCountsValue->setText(tr("Select a row to inspect its history."));
|
||||||
detailNotesEdit->clear();
|
detailNotesEdit->clear();
|
||||||
warnsTable->setRowCount(0);
|
warnsTable->setRowCount(0);
|
||||||
bansTable->setRowCount(0);
|
bansTable->setRowCount(0);
|
||||||
|
|
@ -461,9 +540,9 @@ void TabAlts::warnHistoryResponse(const Response &response)
|
||||||
warnsTable->setRowCount(resp.warn_list_size());
|
warnsTable->setRowCount(resp.warn_list_size());
|
||||||
for (int i = 0; i < resp.warn_list_size(); ++i) {
|
for (int i = 0; i < resp.warn_list_size(); ++i) {
|
||||||
const ServerInfo_Warning &warn = resp.warn_list(i);
|
const ServerInfo_Warning &warn = resp.warn_list(i);
|
||||||
warnsTable->setItem(i, 0, new QTableWidgetItem(QString::fromStdString(warn.time_of())));
|
warnsTable->setItem(i, COL_WARNS_TIME, new QTableWidgetItem(QString::fromStdString(warn.time_of())));
|
||||||
warnsTable->setItem(i, 1, new QTableWidgetItem(QString::fromStdString(warn.admin_name())));
|
warnsTable->setItem(i, COL_WARNS_MODERATOR, new QTableWidgetItem(QString::fromStdString(warn.admin_name())));
|
||||||
warnsTable->setItem(i, 2, new QTableWidgetItem(QString::fromStdString(warn.reason())));
|
warnsTable->setItem(i, COL_WARNS_REASON, new QTableWidgetItem(QString::fromStdString(warn.reason())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -478,9 +557,9 @@ void TabAlts::banHistoryResponse(const Response &response)
|
||||||
bansTable->setRowCount(resp.ban_list_size());
|
bansTable->setRowCount(resp.ban_list_size());
|
||||||
for (int i = 0; i < resp.ban_list_size(); ++i) {
|
for (int i = 0; i < resp.ban_list_size(); ++i) {
|
||||||
const ServerInfo_Ban &ban = resp.ban_list(i);
|
const ServerInfo_Ban &ban = resp.ban_list(i);
|
||||||
bansTable->setItem(i, 0, new QTableWidgetItem(QString::fromStdString(ban.ban_time())));
|
bansTable->setItem(i, COL_BANS_TIME, new QTableWidgetItem(QString::fromStdString(ban.ban_time())));
|
||||||
bansTable->setItem(i, 1, new QTableWidgetItem(QString::fromStdString(ban.admin_name())));
|
bansTable->setItem(i, COL_BANS_MODERATOR, new QTableWidgetItem(QString::fromStdString(ban.admin_name())));
|
||||||
bansTable->setItem(i, 2, new QTableWidgetItem(QString::fromStdString(ban.ban_length())));
|
bansTable->setItem(i, COL_BANS_LENGTH, new QTableWidgetItem(QString::fromStdString(ban.ban_length())));
|
||||||
bansTable->setItem(i, 3, new QTableWidgetItem(QString::fromStdString(ban.ban_reason())));
|
bansTable->setItem(i, COL_BANS_REASON, new QTableWidgetItem(QString::fromStdString(ban.ban_reason())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
#include <qtmetamacros.h>
|
#include <qtmetamacros.h>
|
||||||
|
|
||||||
class AbstractClient;
|
class AbstractClient;
|
||||||
class QCheckBox;
|
class QGroupBox;
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class QLineEdit;
|
class QLineEdit;
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
|
|
@ -70,9 +70,9 @@ private:
|
||||||
QLabel *statusLabel;
|
QLabel *statusLabel;
|
||||||
QTableWidget *altsTable;
|
QTableWidget *altsTable;
|
||||||
|
|
||||||
QCheckBox *emailCheck;
|
QPushButton *emailChip;
|
||||||
QCheckBox *clientIdCheck;
|
QPushButton *clientIdChip;
|
||||||
QCheckBox *ipCheck;
|
QPushButton *ipChip;
|
||||||
QLabel *vpnLabel;
|
QLabel *vpnLabel;
|
||||||
QSpinBox *vpnSpin;
|
QSpinBox *vpnSpin;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <QSplitter>
|
#include <QSplitter>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
#include <QTabWidget>
|
||||||
#include <QTableWidget>
|
#include <QTableWidget>
|
||||||
#include <QTableWidgetItem>
|
#include <QTableWidgetItem>
|
||||||
#include <QTextEdit>
|
#include <QTextEdit>
|
||||||
|
|
@ -101,38 +102,67 @@ TabModeration::TabModeration(TabSupervisor *_tabSupervisor, AbstractClient *_cli
|
||||||
topBar->addWidget(removeBannerButton);
|
topBar->addWidget(removeBannerButton);
|
||||||
|
|
||||||
userInfoGroup = new QGroupBox;
|
userInfoGroup = new QGroupBox;
|
||||||
userInfoNameLabel = new QLabel;
|
|
||||||
userInfoNameValue = new QLabel;
|
userInfoNameValue = new QLabel;
|
||||||
userInfoRegisteredLabel = new QLabel;
|
QFont displayFont = userInfoNameValue->font();
|
||||||
userInfoRegisteredValue = new QLabel;
|
displayFont.setPointSize(displayFont.pointSize() + 6);
|
||||||
userInfoLastLoginLabel = new QLabel;
|
displayFont.setBold(true);
|
||||||
userInfoLastLoginValue = new QLabel;
|
userInfoNameValue->setFont(displayFont);
|
||||||
userInfoStatusLabel = new QLabel;
|
|
||||||
userInfoStatusValue = new QLabel;
|
userInfoStatusValue = new QLabel;
|
||||||
userInfoCountsLabel = new QLabel;
|
QFont statusFont = userInfoStatusValue->font();
|
||||||
userInfoCountsValue = new QLabel;
|
statusFont.setBold(true);
|
||||||
|
userInfoStatusValue->setFont(statusFont);
|
||||||
|
sublineLabel = new QLabel;
|
||||||
|
|
||||||
|
auto makeCountCard = [](const QString &title, QLabel *&value) {
|
||||||
|
auto *card = new QGroupBox(title);
|
||||||
|
value = new QLabel(QStringLiteral("–"), card);
|
||||||
|
QFont cardFont = value->font();
|
||||||
|
cardFont.setPointSize(cardFont.pointSize() + 6);
|
||||||
|
cardFont.setBold(true);
|
||||||
|
value->setFont(cardFont);
|
||||||
|
value->setAlignment(Qt::AlignCenter);
|
||||||
|
auto *cardLayout = new QVBoxLayout(card);
|
||||||
|
cardLayout->addWidget(value);
|
||||||
|
return card;
|
||||||
|
};
|
||||||
|
cardReports = makeCountCard(QString(), cardReportsValue);
|
||||||
|
cardWarns = makeCountCard(QString(), cardWarnsValue);
|
||||||
|
cardBans = makeCountCard(QString(), cardBansValue);
|
||||||
|
|
||||||
|
altsCard = new QGroupBox;
|
||||||
|
altsCountValue = new QLabel(QStringLiteral("–"), altsCard);
|
||||||
|
QFont altsFont = altsCountValue->font();
|
||||||
|
altsFont.setPointSize(altsFont.pointSize() + 6);
|
||||||
|
altsFont.setBold(true);
|
||||||
|
altsCountValue->setFont(altsFont);
|
||||||
|
altsCountValue->setAlignment(Qt::AlignCenter);
|
||||||
|
openAltsButton = new QPushButton;
|
||||||
|
connect(openAltsButton, &QPushButton::clicked, this, &TabModeration::openAltsGraph);
|
||||||
|
auto *altsCardLayout = new QVBoxLayout(altsCard);
|
||||||
|
altsCardLayout->addWidget(altsCountValue);
|
||||||
|
altsCardLayout->addWidget(openAltsButton);
|
||||||
|
|
||||||
|
auto *cardsRow = new QHBoxLayout;
|
||||||
|
cardsRow->addWidget(cardReports);
|
||||||
|
cardsRow->addWidget(cardWarns);
|
||||||
|
cardsRow->addWidget(cardBans);
|
||||||
|
cardsRow->addWidget(altsCard);
|
||||||
|
|
||||||
userInfoNotesLabel = new QLabel;
|
userInfoNotesLabel = new QLabel;
|
||||||
userInfoNotesEdit = new QTextEdit;
|
userInfoNotesEdit = new QTextEdit;
|
||||||
userInfoNotesEdit->setReadOnly(true);
|
userInfoNotesEdit->setReadOnly(true);
|
||||||
|
|
||||||
auto *infoGrid = new QGridLayout;
|
auto *identityRow = new QHBoxLayout;
|
||||||
infoGrid->addWidget(userInfoNameLabel, 0, 0);
|
identityRow->addWidget(userInfoNameValue);
|
||||||
infoGrid->addWidget(userInfoNameValue, 0, 1);
|
identityRow->addStretch();
|
||||||
infoGrid->addWidget(userInfoRegisteredLabel, 0, 2);
|
identityRow->addWidget(userInfoStatusValue);
|
||||||
infoGrid->addWidget(userInfoRegisteredValue, 0, 3);
|
|
||||||
infoGrid->addWidget(userInfoLastLoginLabel, 1, 0);
|
|
||||||
infoGrid->addWidget(userInfoLastLoginValue, 1, 1);
|
|
||||||
infoGrid->addWidget(userInfoStatusLabel, 1, 2);
|
|
||||||
infoGrid->addWidget(userInfoStatusValue, 1, 3);
|
|
||||||
infoGrid->addWidget(userInfoCountsLabel, 2, 0);
|
|
||||||
infoGrid->addWidget(userInfoCountsValue, 2, 1, 1, 3);
|
|
||||||
infoGrid->addWidget(userInfoNotesLabel, 3, 0, Qt::AlignTop);
|
|
||||||
infoGrid->addWidget(userInfoNotesEdit, 3, 1, 1, 3);
|
|
||||||
infoGrid->setColumnStretch(1, 1);
|
|
||||||
infoGrid->setColumnStretch(3, 1);
|
|
||||||
|
|
||||||
auto *infoLayout = new QVBoxLayout(userInfoGroup);
|
auto *infoLayout = new QVBoxLayout(userInfoGroup);
|
||||||
infoLayout->addLayout(infoGrid);
|
infoLayout->addLayout(identityRow);
|
||||||
|
infoLayout->addWidget(sublineLabel);
|
||||||
|
infoLayout->addLayout(cardsRow);
|
||||||
|
infoLayout->addWidget(userInfoNotesLabel);
|
||||||
|
infoLayout->addWidget(userInfoNotesEdit);
|
||||||
|
|
||||||
auto configureTable = [](QTableWidget *table) {
|
auto configureTable = [](QTableWidget *table) {
|
||||||
table->setSelectionBehavior(QAbstractItemView::SelectRows);
|
table->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
|
|
@ -144,31 +174,27 @@ TabModeration::TabModeration(TabSupervisor *_tabSupervisor, AbstractClient *_cli
|
||||||
table->horizontalHeader()->setStretchLastSection(true);
|
table->horizontalHeader()->setStretchLastSection(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
altsGroup = new QGroupBox;
|
|
||||||
altsTable = new QTableWidget(0, COL_ALTS_COUNT);
|
altsTable = new QTableWidget(0, COL_ALTS_COUNT);
|
||||||
configureTable(altsTable);
|
configureTable(altsTable);
|
||||||
connect(altsTable, &QTableWidget::cellDoubleClicked, this, [this](int row, int) {
|
connect(altsTable, &QTableWidget::activated, this, [this](const QModelIndex &index) {
|
||||||
auto *userItem = altsTable->item(row, COL_ALTS_USER);
|
if (!index.isValid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto *userItem = altsTable->item(index.row(), COL_ALTS_USER);
|
||||||
if (userItem != nullptr && !userItem->text().isEmpty()) {
|
if (userItem != nullptr && !userItem->text().isEmpty()) {
|
||||||
getTabSupervisor()->openTabAlts(userItem->text());
|
getTabSupervisor()->openTabAlts(userItem->text());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
openAltsButton = new QPushButton;
|
auto *altsPage = new QWidget;
|
||||||
connect(openAltsButton, &QPushButton::clicked, this, &TabModeration::openAltsGraph);
|
auto *altsLayout = new QVBoxLayout(altsPage);
|
||||||
auto *altsHeader = new QHBoxLayout;
|
|
||||||
altsHeader->addStretch();
|
|
||||||
altsHeader->addWidget(openAltsButton);
|
|
||||||
auto *altsLayout = new QVBoxLayout(altsGroup);
|
|
||||||
altsLayout->addLayout(altsHeader);
|
|
||||||
altsLayout->addWidget(altsTable);
|
altsLayout->addWidget(altsTable);
|
||||||
|
|
||||||
sessionsGroup = new QGroupBox;
|
|
||||||
sessionsTable = new QTableWidget(0, COL_SESSIONS_COUNT);
|
sessionsTable = new QTableWidget(0, COL_SESSIONS_COUNT);
|
||||||
configureTable(sessionsTable);
|
configureTable(sessionsTable);
|
||||||
auto *sessionsLayout = new QVBoxLayout(sessionsGroup);
|
auto *sessionsPage = new QWidget;
|
||||||
|
auto *sessionsLayout = new QVBoxLayout(sessionsPage);
|
||||||
sessionsLayout->addWidget(sessionsTable);
|
sessionsLayout->addWidget(sessionsTable);
|
||||||
|
|
||||||
staffGroup = new QGroupBox;
|
|
||||||
staffTable = new QTableWidget(0, COL_STAFF_COUNT);
|
staffTable = new QTableWidget(0, COL_STAFF_COUNT);
|
||||||
configureTable(staffTable);
|
configureTable(staffTable);
|
||||||
refreshStaffButton = new QPushButton;
|
refreshStaffButton = new QPushButton;
|
||||||
|
|
@ -176,19 +202,21 @@ TabModeration::TabModeration(TabSupervisor *_tabSupervisor, AbstractClient *_cli
|
||||||
auto *staffHeader = new QHBoxLayout;
|
auto *staffHeader = new QHBoxLayout;
|
||||||
staffHeader->addStretch();
|
staffHeader->addStretch();
|
||||||
staffHeader->addWidget(refreshStaffButton);
|
staffHeader->addWidget(refreshStaffButton);
|
||||||
auto *staffLayout = new QVBoxLayout(staffGroup);
|
auto *staffPage = new QWidget;
|
||||||
|
auto *staffLayout = new QVBoxLayout(staffPage);
|
||||||
staffLayout->addWidget(staffTable);
|
staffLayout->addWidget(staffTable);
|
||||||
staffLayout->addLayout(staffHeader);
|
staffLayout->addLayout(staffHeader);
|
||||||
|
|
||||||
|
sectionTabs = new QTabWidget;
|
||||||
|
sectionTabs->addTab(altsPage, QString());
|
||||||
|
sectionTabs->addTab(sessionsPage, QString());
|
||||||
|
sectionTabs->addTab(staffPage, QString());
|
||||||
|
|
||||||
auto *splitter = new QSplitter(Qt::Vertical);
|
auto *splitter = new QSplitter(Qt::Vertical);
|
||||||
splitter->addWidget(userInfoGroup);
|
splitter->addWidget(userInfoGroup);
|
||||||
splitter->addWidget(altsGroup);
|
splitter->addWidget(sectionTabs);
|
||||||
splitter->addWidget(sessionsGroup);
|
|
||||||
splitter->addWidget(staffGroup);
|
|
||||||
splitter->setStretchFactor(0, 1);
|
splitter->setStretchFactor(0, 1);
|
||||||
splitter->setStretchFactor(1, 2);
|
splitter->setStretchFactor(1, 2);
|
||||||
splitter->setStretchFactor(2, 2);
|
|
||||||
splitter->setStretchFactor(3, 1);
|
|
||||||
|
|
||||||
auto *mainLayout = new QVBoxLayout(centralWidget);
|
auto *mainLayout = new QVBoxLayout(centralWidget);
|
||||||
mainLayout->addLayout(topBar);
|
mainLayout->addLayout(topBar);
|
||||||
|
|
@ -210,21 +238,28 @@ void TabModeration::retranslateUi()
|
||||||
refreshStaffButton->setText(tr("Refresh"));
|
refreshStaffButton->setText(tr("Refresh"));
|
||||||
|
|
||||||
userInfoGroup->setTitle(tr("User Info"));
|
userInfoGroup->setTitle(tr("User Info"));
|
||||||
userInfoNameLabel->setText(tr("Name:"));
|
|
||||||
userInfoRegisteredLabel->setText(tr("Registered:"));
|
|
||||||
userInfoLastLoginLabel->setText(tr("Last login:"));
|
|
||||||
userInfoStatusLabel->setText(tr("Status:"));
|
|
||||||
userInfoCountsLabel->setText(tr("Counts:"));
|
|
||||||
userInfoNotesLabel->setText(tr("Admin notes:"));
|
userInfoNotesLabel->setText(tr("Admin notes:"));
|
||||||
|
cardReports->setTitle(tr("Reports"));
|
||||||
altsGroup->setTitle(tr("Alts"));
|
cardWarns->setTitle(tr("Warnings"));
|
||||||
openAltsButton->setText(tr("Open alt graph"));
|
cardBans->setTitle(tr("Bans"));
|
||||||
|
altsCard->setTitle(tr("Alts"));
|
||||||
|
openAltsButton->setText(tr("Open graph"));
|
||||||
openAltsButton->setToolTip(tr("Open this user in the User Alts tab"));
|
openAltsButton->setToolTip(tr("Open this user in the User Alts tab"));
|
||||||
sessionsGroup->setTitle(tr("Sessions"));
|
|
||||||
staffGroup->setTitle(tr("Staff Last Logins"));
|
sectionTabs->setTabText(0, tr("Alts"));
|
||||||
|
sectionTabs->setTabText(1, tr("Sessions"));
|
||||||
|
sectionTabs->setTabText(2, tr("Staff Last Logins"));
|
||||||
|
|
||||||
|
if (cachedUserInfoValid) {
|
||||||
|
applyUserInfo();
|
||||||
|
}
|
||||||
|
if (cachedAltsCount >= 0) {
|
||||||
|
applyAltsCount();
|
||||||
|
}
|
||||||
|
|
||||||
altsTable->setHorizontalHeaderLabels({tr("User"), tr("eMail"), tr("Client ID"), tr("Registered"), tr("Last login"),
|
altsTable->setHorizontalHeaderLabels({tr("User"), tr("eMail"), tr("Client ID"), tr("Registered"), tr("Last login"),
|
||||||
tr("Warns"), tr("Bans"), tr("Active")});
|
tr("Warns"), tr("Bans"), tr("Active")});
|
||||||
|
altsTable->setToolTip(tr("Double-click or press Enter on a row to open it in the User Alts tab"));
|
||||||
sessionsTable->setHorizontalHeaderLabels({tr("IP"), tr("Client ID"), tr("Start"), tr("End"), tr("Type")});
|
sessionsTable->setHorizontalHeaderLabels({tr("IP"), tr("Client ID"), tr("Start"), tr("End"), tr("Type")});
|
||||||
staffTable->setHorizontalHeaderLabels({tr("User"), tr("Level"), tr("Last login")});
|
staffTable->setHorizontalHeaderLabels({tr("User"), tr("Level"), tr("Last login")});
|
||||||
}
|
}
|
||||||
|
|
@ -237,11 +272,15 @@ QString TabModeration::formatEpoch(quint64 ts) const
|
||||||
void TabModeration::clearUserData()
|
void TabModeration::clearUserData()
|
||||||
{
|
{
|
||||||
currentUser.clear();
|
currentUser.clear();
|
||||||
|
cachedUserInfoValid = false;
|
||||||
|
cachedAltsCount = -1;
|
||||||
userInfoNameValue->clear();
|
userInfoNameValue->clear();
|
||||||
userInfoRegisteredValue->clear();
|
|
||||||
userInfoLastLoginValue->clear();
|
|
||||||
userInfoStatusValue->clear();
|
userInfoStatusValue->clear();
|
||||||
userInfoCountsValue->clear();
|
sublineLabel->clear();
|
||||||
|
cardReportsValue->setText(QStringLiteral("–"));
|
||||||
|
cardWarnsValue->setText(QStringLiteral("–"));
|
||||||
|
cardBansValue->setText(QStringLiteral("–"));
|
||||||
|
altsCountValue->setText(QStringLiteral("–"));
|
||||||
userInfoNotesEdit->clear();
|
userInfoNotesEdit->clear();
|
||||||
altsTable->setRowCount(0);
|
altsTable->setRowCount(0);
|
||||||
sessionsTable->setRowCount(0);
|
sessionsTable->setRowCount(0);
|
||||||
|
|
@ -267,10 +306,13 @@ void TabModeration::investigateUser()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
currentUser = userName;
|
currentUser = userName;
|
||||||
|
cachedUserInfoValid = false;
|
||||||
|
cachedAltsCount = -1;
|
||||||
resetPasswordButton->setEnabled(true);
|
resetPasswordButton->setEnabled(true);
|
||||||
removeAvatarButton->setEnabled(true);
|
removeAvatarButton->setEnabled(true);
|
||||||
removeBannerButton->setEnabled(true);
|
removeBannerButton->setEnabled(true);
|
||||||
openAltsButton->setEnabled(true);
|
openAltsButton->setEnabled(true);
|
||||||
|
altsCountValue->setText(QStringLiteral("…"));
|
||||||
altsTable->setRowCount(0);
|
altsTable->setRowCount(0);
|
||||||
sessionsTable->setRowCount(0);
|
sessionsTable->setRowCount(0);
|
||||||
requestUserInfo(userName);
|
requestUserInfo(userName);
|
||||||
|
|
@ -289,10 +331,11 @@ void TabModeration::openAltsGraph()
|
||||||
void TabModeration::requestUserInfo(const QString &userName)
|
void TabModeration::requestUserInfo(const QString &userName)
|
||||||
{
|
{
|
||||||
userInfoNameValue->setText(userName);
|
userInfoNameValue->setText(userName);
|
||||||
userInfoRegisteredValue->setText(tr("Loading..."));
|
sublineLabel->setText(tr("Loading..."));
|
||||||
userInfoLastLoginValue->setText(tr("Loading..."));
|
|
||||||
userInfoStatusValue->clear();
|
userInfoStatusValue->clear();
|
||||||
userInfoCountsValue->clear();
|
cardReportsValue->setText(QStringLiteral("…"));
|
||||||
|
cardWarnsValue->setText(QStringLiteral("…"));
|
||||||
|
cardBansValue->setText(QStringLiteral("…"));
|
||||||
userInfoNotesEdit->clear();
|
userInfoNotesEdit->clear();
|
||||||
|
|
||||||
Command_ReportUserInfo cmd;
|
Command_ReportUserInfo cmd;
|
||||||
|
|
@ -305,9 +348,12 @@ void TabModeration::requestUserInfo(const QString &userName)
|
||||||
void TabModeration::userInfoResponse(const Response &response)
|
void TabModeration::userInfoResponse(const Response &response)
|
||||||
{
|
{
|
||||||
if (response.response_code() != Response::RespOk) {
|
if (response.response_code() != Response::RespOk) {
|
||||||
userInfoRegisteredValue->clear();
|
cachedUserInfoValid = false;
|
||||||
userInfoLastLoginValue->clear();
|
sublineLabel->clear();
|
||||||
userInfoStatusValue->setText(tr("Error loading user info."));
|
userInfoStatusValue->setText(tr("Error loading user info."));
|
||||||
|
cardReportsValue->setText(QStringLiteral("–"));
|
||||||
|
cardWarnsValue->setText(QStringLiteral("–"));
|
||||||
|
cardBansValue->setText(QStringLiteral("–"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -316,20 +362,28 @@ void TabModeration::userInfoResponse(const Response &response)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
userInfoRegisteredValue->setText(formatEpoch(resp.registration_time()));
|
cachedUserInfo.CopyFrom(resp);
|
||||||
userInfoLastLoginValue->setText(formatEpoch(resp.last_login()));
|
cachedUserInfoValid = true;
|
||||||
|
applyUserInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabModeration::applyUserInfo()
|
||||||
|
{
|
||||||
|
const Response_ReportUserInfo &resp = cachedUserInfo;
|
||||||
|
sublineLabel->setText(tr("Registered %1 · Last login %2")
|
||||||
|
.arg(formatEpoch(resp.registration_time()))
|
||||||
|
.arg(formatEpoch(resp.last_login())));
|
||||||
|
|
||||||
QStringList statusParts;
|
QStringList statusParts;
|
||||||
statusParts << (resp.is_active() ? tr("active") : tr("inactive"));
|
statusParts << (resp.is_active() ? tr("active") : tr("inactive"));
|
||||||
if (resp.has_is_admin() && resp.is_admin()) {
|
if (resp.has_is_admin() && resp.is_admin()) {
|
||||||
statusParts << tr("admin");
|
statusParts << tr("admin");
|
||||||
}
|
}
|
||||||
userInfoStatusValue->setText(statusParts.join(", "));
|
userInfoStatusValue->setText(statusParts.join(QStringLiteral(", ")));
|
||||||
|
|
||||||
userInfoCountsValue->setText(tr("Reports: %1 Bans: %2 Warnings: %3")
|
cardReportsValue->setText(QString::number(resp.total_reports()));
|
||||||
.arg(resp.total_reports())
|
cardWarnsValue->setText(QString::number(resp.total_warns()));
|
||||||
.arg(resp.total_bans())
|
cardBansValue->setText(QString::number(resp.total_bans()));
|
||||||
.arg(resp.total_warns()));
|
|
||||||
|
|
||||||
if (resp.has_admin_notes() && !resp.admin_notes().empty()) {
|
if (resp.has_admin_notes() && !resp.admin_notes().empty()) {
|
||||||
userInfoNotesEdit->setPlainText(QString::fromStdString(resp.admin_notes()));
|
userInfoNotesEdit->setPlainText(QString::fromStdString(resp.admin_notes()));
|
||||||
|
|
@ -338,12 +392,21 @@ void TabModeration::userInfoResponse(const Response &response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TabModeration::applyAltsCount()
|
||||||
|
{
|
||||||
|
altsCountValue->setText(tr("%1 related").arg(cachedAltsCount));
|
||||||
|
}
|
||||||
|
|
||||||
void TabModeration::requestSessions(const QString &userName)
|
void TabModeration::requestSessions(const QString &userName)
|
||||||
{
|
{
|
||||||
Command_GetUserSessions cmd;
|
Command_GetUserSessions cmd;
|
||||||
cmd.set_user_name(userName.toStdString());
|
cmd.set_user_name(userName.toStdString());
|
||||||
PendingCommand *pend = client->prepareModeratorCommand(cmd);
|
PendingCommand *pend = client->prepareModeratorCommand(cmd);
|
||||||
connect(pend, &PendingCommand::finished, this, &TabModeration::sessionsResponse);
|
connect(pend, &PendingCommand::finished, this, [this, userName](const Response &response) {
|
||||||
|
if (userName == currentUser) {
|
||||||
|
sessionsResponse(response);
|
||||||
|
}
|
||||||
|
});
|
||||||
client->sendCommand(pend);
|
client->sendCommand(pend);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -375,7 +438,11 @@ void TabModeration::requestAlts(const QString &userName)
|
||||||
Command_GetUserAlts cmd;
|
Command_GetUserAlts cmd;
|
||||||
cmd.set_user_name(userName.toStdString());
|
cmd.set_user_name(userName.toStdString());
|
||||||
PendingCommand *pend = client->prepareModeratorCommand(cmd);
|
PendingCommand *pend = client->prepareModeratorCommand(cmd);
|
||||||
connect(pend, &PendingCommand::finished, this, &TabModeration::altsResponse);
|
connect(pend, &PendingCommand::finished, this, [this, userName](const Response &response) {
|
||||||
|
if (userName == currentUser) {
|
||||||
|
altsResponse(response);
|
||||||
|
}
|
||||||
|
});
|
||||||
client->sendCommand(pend);
|
client->sendCommand(pend);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -383,10 +450,14 @@ void TabModeration::altsResponse(const Response &response)
|
||||||
{
|
{
|
||||||
altsTable->setRowCount(0);
|
altsTable->setRowCount(0);
|
||||||
if (response.response_code() != Response::RespOk) {
|
if (response.response_code() != Response::RespOk) {
|
||||||
|
cachedAltsCount = -1;
|
||||||
|
altsCountValue->setText(QStringLiteral("–"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Response_UserAlts &resp = response.GetExtension(Response_UserAlts::ext);
|
const Response_UserAlts &resp = response.GetExtension(Response_UserAlts::ext);
|
||||||
|
cachedAltsCount = resp.alts_size();
|
||||||
|
applyAltsCount();
|
||||||
altsTable->setRowCount(resp.alts_size());
|
altsTable->setRowCount(resp.alts_size());
|
||||||
for (int i = 0; i < resp.alts_size(); ++i) {
|
for (int i = 0; i < resp.alts_size(); ++i) {
|
||||||
const ServerInfo_UserAlt &alt = resp.alts(i);
|
const ServerInfo_UserAlt &alt = resp.alts(i);
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
#include <libcockatrice/protocol/pb/response_report_user_info.pb.h>
|
||||||
#include <qtmetamacros.h>
|
#include <qtmetamacros.h>
|
||||||
|
|
||||||
class AbstractClient;
|
class AbstractClient;
|
||||||
|
|
@ -13,6 +14,7 @@ class QLabel;
|
||||||
class QLineEdit;
|
class QLineEdit;
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
class QTableWidget;
|
class QTableWidget;
|
||||||
|
class QTabWidget;
|
||||||
class QTextEdit;
|
class QTextEdit;
|
||||||
class Response;
|
class Response;
|
||||||
class TabSupervisor;
|
class TabSupervisor;
|
||||||
|
|
@ -54,10 +56,15 @@ private:
|
||||||
void requestAlts(const QString &userName);
|
void requestAlts(const QString &userName);
|
||||||
void requestModeratorLogins();
|
void requestModeratorLogins();
|
||||||
void clearUserData();
|
void clearUserData();
|
||||||
|
void applyUserInfo();
|
||||||
|
void applyAltsCount();
|
||||||
[[nodiscard]] QString formatEpoch(quint64 ts) const;
|
[[nodiscard]] QString formatEpoch(quint64 ts) const;
|
||||||
|
|
||||||
AbstractClient *client;
|
AbstractClient *client;
|
||||||
QString currentUser;
|
QString currentUser;
|
||||||
|
Response_ReportUserInfo cachedUserInfo;
|
||||||
|
bool cachedUserInfoValid = false;
|
||||||
|
int cachedAltsCount = -1;
|
||||||
|
|
||||||
QLineEdit *searchEdit;
|
QLineEdit *searchEdit;
|
||||||
QPushButton *investigateButton;
|
QPushButton *investigateButton;
|
||||||
|
|
@ -66,26 +73,25 @@ private:
|
||||||
QPushButton *removeBannerButton;
|
QPushButton *removeBannerButton;
|
||||||
|
|
||||||
QGroupBox *userInfoGroup;
|
QGroupBox *userInfoGroup;
|
||||||
QLabel *userInfoNameLabel;
|
|
||||||
QLabel *userInfoNameValue;
|
QLabel *userInfoNameValue;
|
||||||
QLabel *userInfoRegisteredLabel;
|
|
||||||
QLabel *userInfoRegisteredValue;
|
|
||||||
QLabel *userInfoLastLoginLabel;
|
|
||||||
QLabel *userInfoLastLoginValue;
|
|
||||||
QLabel *userInfoStatusLabel;
|
|
||||||
QLabel *userInfoStatusValue;
|
QLabel *userInfoStatusValue;
|
||||||
QLabel *userInfoCountsLabel;
|
QLabel *sublineLabel;
|
||||||
QLabel *userInfoCountsValue;
|
QGroupBox *cardReports;
|
||||||
|
QGroupBox *cardWarns;
|
||||||
|
QGroupBox *cardBans;
|
||||||
|
QGroupBox *altsCard;
|
||||||
|
QLabel *cardReportsValue;
|
||||||
|
QLabel *cardWarnsValue;
|
||||||
|
QLabel *cardBansValue;
|
||||||
|
QLabel *altsCountValue;
|
||||||
QLabel *userInfoNotesLabel;
|
QLabel *userInfoNotesLabel;
|
||||||
QTextEdit *userInfoNotesEdit;
|
QTextEdit *userInfoNotesEdit;
|
||||||
|
|
||||||
QGroupBox *altsGroup;
|
QTabWidget *sectionTabs;
|
||||||
QTableWidget *altsTable;
|
QTableWidget *altsTable;
|
||||||
QPushButton *openAltsButton;
|
|
||||||
QGroupBox *sessionsGroup;
|
|
||||||
QTableWidget *sessionsTable;
|
QTableWidget *sessionsTable;
|
||||||
QGroupBox *staffGroup;
|
|
||||||
QTableWidget *staffTable;
|
QTableWidget *staffTable;
|
||||||
|
QPushButton *openAltsButton;
|
||||||
QPushButton *refreshStaffButton;
|
QPushButton *refreshStaffButton;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue