Allow Moderators/Admins to Grant Replay Access

- Only to themselves, at this time
- Automatically refreshes feed, no need to re-login
This commit is contained in:
ZeldaZach
2024-12-27 17:00:33 -05:00
parent 17893d9747
commit 3524231500
7 changed files with 129 additions and 6 deletions

View File

@@ -1,19 +1,20 @@
#include "tab_admin.h"
#include "../../server/pending_command.h"
#include "../game_logic/abstract_client.h"
#include "pb/admin_commands.pb.h"
#include "pb/event_replay_added.pb.h"
#include "pb/moderator_commands.pb.h"
#include "trice_limits.h"
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QMessageBox>
#include <QPushButton>
#include <QSpinBox>
#include <QVBoxLayout>
ShutdownDialog::ShutdownDialog(QWidget *parent) : QDialog(parent)
{
@@ -63,10 +64,23 @@ TabAdmin::TabAdmin(TabSupervisor *_tabSupervisor, AbstractClient *_client, bool
reloadConfigButton = new QPushButton;
connect(reloadConfigButton, &QPushButton::clicked, this, &TabAdmin::actReloadConfig);
grantReplayAccessButton = new QPushButton;
grantReplayAccessButton->setEnabled(false);
connect(grantReplayAccessButton, &QPushButton::clicked, this, &TabAdmin::actGrantReplayAccess);
replayIdToGrant = new QLineEdit;
replayIdToGrant->setMaximumWidth(500);
replayIdToGrant->setValidator(new QIntValidator(0, INT_MAX, this));
connect(replayIdToGrant, &QLineEdit::textChanged, this,
[=, this]() { grantReplayAccessButton->setEnabled(!replayIdToGrant->text().isEmpty()); });
auto *grandReplayAccessLayout = new QGridLayout(this);
grandReplayAccessLayout->addWidget(replayIdToGrant, 0, 0);
grandReplayAccessLayout->addWidget(grantReplayAccessButton, 0, 1);
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(updateServerMessageButton);
vbox->addWidget(shutdownServerButton);
vbox->addWidget(reloadConfigButton);
vbox->addLayout(grandReplayAccessLayout);
vbox->addStretch();
adminGroupBox = new QGroupBox;
@@ -100,6 +114,9 @@ void TabAdmin::retranslateUi()
reloadConfigButton->setText(tr("&Reload configuration"));
adminGroupBox->setTitle(tr("Server administration functions"));
replayIdToGrant->setPlaceholderText(tr("Replay ID"));
grantReplayAccessButton->setText(tr("Grant Replay Access"));
unlockButton->setText(tr("&Unlock functions"));
lockButton->setText(tr("&Lock functions"));
}
@@ -127,6 +144,41 @@ void TabAdmin::actReloadConfig()
client->sendCommand(client->prepareAdminCommand(cmd));
}
void TabAdmin::actGrantReplayAccess()
{
if (!replayIdToGrant) {
return;
}
Command_GrantReplayAccess cmd;
cmd.set_replay_id(replayIdToGrant->text().toUInt());
cmd.set_moderator_name(client->getUserName().toStdString());
auto *pend = client->prepareModeratorCommand(cmd);
connect(pend,
QOverload<const Response &, const CommandContainer &, const QVariant &>::of(&PendingCommand::finished),
this, &TabAdmin::grantReplayAccessProcessResponse);
client->sendCommand(pend);
}
void TabAdmin::grantReplayAccessProcessResponse(const Response &response, const CommandContainer &, const QVariant &)
{
auto *event = new Event_ReplayAdded();
switch (response.response_code()) {
case Response::RespOk:
client->replayAddedEventReceived(*event);
QMessageBox::information(this, tr("Success"), tr("Replay access granted"));
break;
case Response::RespContextError:
QMessageBox::critical(this, tr("Error"), tr("Unable to grant replay access. Replay ID invalid"));
break;
default:
QMessageBox::critical(this, tr("Error"), tr("Unable to grant replay access: Internal error"));
break;
}
}
void TabAdmin::actUnlock()
{
if (fullAdmin)

View File

@@ -1,6 +1,8 @@
#ifndef TAB_ADMIN_H
#define TAB_ADMIN_H
#include "pb/commands.pb.h"
#include "pb/response.pb.h"
#include "tab.h"
#include <QDialog>
@@ -32,15 +34,18 @@ private:
bool locked;
AbstractClient *client;
bool fullAdmin;
QPushButton *updateServerMessageButton, *shutdownServerButton, *reloadConfigButton;
QPushButton *updateServerMessageButton, *shutdownServerButton, *reloadConfigButton, *grantReplayAccessButton;
QGroupBox *adminGroupBox;
QPushButton *unlockButton, *lockButton;
QLineEdit *replayIdToGrant;
signals:
void adminLockChanged(bool lock);
private slots:
void actUpdateServerMessage();
void actShutdownServer();
void actReloadConfig();
void actGrantReplayAccess();
void grantReplayAccessProcessResponse(const Response &resp, const CommandContainer &, const QVariant &);
void actUnlock();
void actLock();

View File

@@ -401,5 +401,11 @@ void TabReplays::deleteRemoteReplayFinished(const Response &r, const CommandCont
void TabReplays::replayAddedEventReceived(const Event_ReplayAdded &event)
{
serverDirView->addMatchInfo(event.match_info());
if (event.has_match_info()) {
// 99.9% of events will have match info (Normal Workflow)
serverDirView->addMatchInfo(event.match_info());
} else {
// When a Moderator force adds a replay, we need to refresh their view
serverDirView->refreshTree();
}
}

View File

@@ -27,7 +27,7 @@ private:
Node(const QString &_name) : name(_name)
{
}
virtual ~Node(){};
virtual ~Node() {};
QString getName() const
{
return name;
@@ -115,7 +115,9 @@ public:
ServerInfo_ReplayMatch const *getReplayMatch(const QModelIndex &ind) const;
QList<ServerInfo_Replay const *> getSelectedReplays() const;
QSet<ServerInfo_ReplayMatch const *> getSelectedReplayMatches() const;
void refreshTree();
void refreshTree() {
treeModel->refreshTree();
}
void addMatchInfo(const ServerInfo_ReplayMatch &matchInfo)
{
treeModel->addMatchInfo(matchInfo);

View File

@@ -7,6 +7,7 @@ message ModeratorCommand {
WARN_HISTORY = 1003;
WARN_LIST = 1004;
VIEWLOG_HISTORY = 1005;
GRANT_REPLAY_ACCESS = 1006;
}
extensions 100 to max;
}
@@ -71,3 +72,11 @@ message Command_ViewLogHistory {
required uint32 date_range = 7; // the length of time (in minutes) to look back for
optional uint32 maximum_results = 8; // the maximum number of query results
}
message Command_GrantReplayAccess {
extend ModeratorCommand {
optional Command_GrantReplayAccess ext = 1006;
}
optional uint32 replay_id = 1;
optional string moderator_name = 2;
}

View File

@@ -224,6 +224,8 @@ Response::ResponseCode AbstractServerSocketInterface::processExtendedModeratorCo
return cmdGetWarnList(cmd.GetExtension(Command_GetWarnList::ext), rc);
case ModeratorCommand::VIEWLOG_HISTORY:
return cmdGetLogHistory(cmd.GetExtension(Command_ViewLogHistory::ext), rc);
case ModeratorCommand::GRANT_REPLAY_ACCESS:
return cmdGrantReplayAccess(cmd.GetExtension(Command_GrantReplayAccess::ext), rc);
default:
return Response::RespFunctionNotAllowed;
}
@@ -1656,6 +1658,52 @@ Response::ResponseCode AbstractServerSocketInterface::cmdAdjustMod(const Command
return Response::RespOk;
}
Response::ResponseCode AbstractServerSocketInterface::cmdGrantReplayAccess(const Command_GrantReplayAccess &cmd,
ResponseContainer & /*rc*/)
{
// Determine if the replay actually exists already
auto *replayExistsQuery =
sqlInterface->prepareQuery("select count(*) from {prefix}_replays_access where id_game = :idgame");
replayExistsQuery->bindValue(":idgame", cmd.replay_id());
if (!sqlInterface->execSqlQuery(replayExistsQuery)) {
return Response::RespInternalError;
}
if (!replayExistsQuery->next()) {
return Response::RespInternalError;
}
const auto &replayExists = replayExistsQuery->value(0).toInt() > 0;
if (!replayExists) {
return Response::RespContextError;
}
// Determine the Moderator's User ID (As it's not apart of client, only username is)
auto *getModeratorUserIdQuery = sqlInterface->prepareQuery("select id from {prefix}_users WHERE name = :name");
getModeratorUserIdQuery->bindValue(":name", QString::fromStdString(cmd.moderator_name()));
if (!sqlInterface->execSqlQuery(getModeratorUserIdQuery)) {
return Response::RespInternalError;
}
if (!getModeratorUserIdQuery->next()) {
return Response::RespInternalError;
}
const auto &moderator_id = getModeratorUserIdQuery->value(0).toString();
// Grant the Moderator access to the replay
auto *grantReplayAccessQuery =
sqlInterface->prepareQuery("insert into {prefix}_replays_access (id_game, id_player, replay_name, do_not_hide) "
"values(:idgame, :idplayer, :replayname, 0)");
grantReplayAccessQuery->bindValue(":idgame", cmd.replay_id());
grantReplayAccessQuery->bindValue(":idplayer", moderator_id);
grantReplayAccessQuery->bindValue(":replayname", "Moderator Access Replay Grant");
if (!sqlInterface->execSqlQuery(grantReplayAccessQuery)) {
return Response::RespInternalError;
}
return Response::RespOk;
}
TcpServerSocketInterface::TcpServerSocketInterface(Servatrice *_server,
Servatrice_DatabaseInterface *_databaseInterface,
QObject *parent)

View File

@@ -126,6 +126,7 @@ private:
Response::ResponseCode cmdAccountEdit(const Command_AccountEdit &cmd, ResponseContainer &rc);
Response::ResponseCode cmdAccountImage(const Command_AccountImage &cmd, ResponseContainer &rc);
Response::ResponseCode cmdAccountPassword(const Command_AccountPassword &cmd, ResponseContainer &rc);
Response::ResponseCode cmdGrantReplayAccess(const Command_GrantReplayAccess &cmd, ResponseContainer &rc);
bool addAdminFlagToUser(const QString &user, int flag);
bool removeAdminFlagFromUser(const QString &user, int flag);