diff --git a/cockatrice/src/tab_supervisor.cpp b/cockatrice/src/tab_supervisor.cpp index c9ef1577..2dcbb49b 100644 --- a/cockatrice/src/tab_supervisor.cpp +++ b/cockatrice/src/tab_supervisor.cpp @@ -25,6 +25,7 @@ #include "pb/event_game_joined.pb.h" #include "pb/serverinfo_user.pb.h" #include "pb/serverinfo_room.pb.h" +#include "pb/moderator_commands.pb.h" CloseButton::CloseButton(QWidget *parent) : QAbstractButton(parent) @@ -557,8 +558,14 @@ bool TabSupervisor::getAdminLocked() const void TabSupervisor::processNotifyUserEvent(const Event_NotifyUser &event) { + switch ((Event_NotifyUser::NotificationType) event.type()) { case Event_NotifyUser::PROMOTED: QMessageBox::information(this, tr("Promotion"), tr("You have been promoted to moderator. Please log out and back in for changes to take effect.")); break; + case Event_NotifyUser::WARNING: { + if (!QString::fromStdString(event.warning_reason()).simplified().isEmpty()) + QMessageBox::warning(this, tr("Warned"), tr("You have received a warning due to %1.\nPlease refrain from engaging in this activity or further actions may be taken against you. If you have any questions, please private message a moderator.").arg(QString::fromStdString(event.warning_reason()).simplified())); + break; + } default: ; } diff --git a/cockatrice/src/user_context_menu.cpp b/cockatrice/src/user_context_menu.cpp index d6983449..95761929 100644 --- a/cockatrice/src/user_context_menu.cpp +++ b/cockatrice/src/user_context_menu.cpp @@ -14,6 +14,7 @@ #include #if QT_VERSION >= 0x050000 #include +#include #endif #include "pb/commands.pb.h" @@ -23,6 +24,8 @@ #include "pb/response_get_games_of_user.pb.h" #include "pb/response_get_user_info.pb.h" #include "pb/response_ban_history.pb.h" +#include "pb/response_warn_history.pb.h" +#include "pb/response_warn_list.pb.h" UserContextMenu::UserContextMenu(const TabSupervisor *_tabSupervisor, QWidget *parent, TabGame *_game) : QObject(parent), client(_tabSupervisor->getClient()), tabSupervisor(_tabSupervisor), game(_game) @@ -37,6 +40,8 @@ UserContextMenu::UserContextMenu(const TabSupervisor *_tabSupervisor, QWidget *p aAddToIgnoreList = new QAction(QString(), this); aRemoveFromIgnoreList = new QAction(QString(), this); aKick = new QAction(QString(), this); + aWarnUser = new QAction(QString(), this); + aWarnHistory = new QAction(QString(), this); aBan = new QAction(QString(), this); aBanHistory = new QAction(QString(), this); aPromoteToMod = new QAction(QString(), this); @@ -55,6 +60,8 @@ void UserContextMenu::retranslateUi() aAddToIgnoreList->setText(tr("Add to &ignore list")); aRemoveFromIgnoreList->setText(tr("Remove from &ignore list")); aKick->setText(tr("Kick from &game")); + aWarnUser->setText(tr("Warn user")); + aWarnHistory->setText(tr("View user's war&n history")); aBan->setText(tr("Ban from &server")); aBanHistory->setText(tr("View user's &ban history")); aPromoteToMod->setText(tr("&Promote user to moderator")); @@ -102,6 +109,39 @@ void UserContextMenu::banUser_processUserInfoResponse(const Response &r) dlg->show(); } +void UserContextMenu::warnUser_processGetWarningsListResponse(const Response &r) +{ + const Response_WarnList &response = r.GetExtension(Response_WarnList::ext); + + QString user = QString::fromStdString(response.user_name()).simplified(); + QString clientid = QString::fromStdString(response.user_clientid()).simplified(); + + // The dialog needs to be non-modal in order to not block the event queue of the client. + WarningDialog *dlg = new WarningDialog(user, clientid, static_cast(parent())); + connect(dlg, SIGNAL(accepted()), this, SLOT(warnUser_dialogFinished())); + + if (response.warning_size() > 0) { + for (int i = 0; i < response.warning_size(); ++i) { + dlg->addWarningOption(QString::fromStdString(response.warning(i)).simplified()); + } + } + dlg->show(); +} + +void UserContextMenu::warnUser_processUserInfoResponse(const Response &resp) +{ + const Response_GetUserInfo &response = resp.GetExtension(Response_GetUserInfo::ext); + ServerInfo_User userInfo = response.user_info(); + + Command_GetWarnList cmd; + cmd.set_user_name(userInfo.name()); + cmd.set_user_clientid(userInfo.clientid()); + PendingCommand *pend = client->prepareModeratorCommand(cmd); + connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this, SLOT(warnUser_processGetWarningsListResponse(Response))); + client->sendCommand(pend); + +} + void UserContextMenu::banUserHistory_processResponse(const Response &resp) { const Response_BanHistory &response = resp.GetExtension(Response_BanHistory::ext); if (resp.response_code() == Response::RespOk) { @@ -135,6 +175,38 @@ void UserContextMenu::banUserHistory_processResponse(const Response &resp) { QMessageBox::critical(static_cast(parent()), tr("Ban History"), tr("Failed to collecting ban information.")); } +void UserContextMenu::warnUserHistory_processResponse(const Response &resp) { + const Response_WarnHistory &response = resp.GetExtension(Response_WarnHistory::ext); + if (resp.response_code() == Response::RespOk) { + + if (response.warn_list_size() > 0) { + QTableWidget *table = new QTableWidget(); + table->setWindowTitle(tr("Warning History")); + table->setRowCount(response.warn_list_size()); + table->setColumnCount(4); + table->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + table->setHorizontalHeaderLabels( + QString(tr("Warning Time;Moderator;User Name;Reason")).split(";")); + + ServerInfo_Warning warn; for (int i = 0; i < response.warn_list_size(); ++i) { + warn = response.warn_list(i); + table->setItem(i, 0, new QTableWidgetItem(QString::fromStdString(warn.time_of()))); + table->setItem(i, 1, new QTableWidgetItem(QString::fromStdString(warn.admin_name()))); + table->setItem(i, 2, new QTableWidgetItem(QString::fromStdString(warn.user_name()))); + table->setItem(i, 3, new QTableWidgetItem(QString::fromStdString(warn.reason()))); + } + + table->resizeColumnsToContents(); + table->setMinimumSize(table->horizontalHeader()->length() + (table->columnCount() * 5), table->verticalHeader()->length() + (table->rowCount() * 3)); + table->show(); + } else + QMessageBox::information(static_cast(parent()), tr("Warning History"), tr("User has never been warned.")); + + } else + QMessageBox::critical(static_cast(parent()), tr("Warning History"), tr("Failed to collecting warning information.")); +} + void UserContextMenu::adjustMod_processUserResponse(const Response &resp, const CommandContainer &commandContainer) { @@ -171,6 +243,22 @@ void UserContextMenu::banUser_dialogFinished() client->sendCommand(client->prepareModeratorCommand(cmd)); } +void UserContextMenu::warnUser_dialogFinished() +{ + WarningDialog *dlg = static_cast(sender()); + + if (dlg->getName().isEmpty() || QString::fromStdString(tabSupervisor->getUserInfo()->name()).simplified().isEmpty()) + return; + + Command_WarnUser cmd; + cmd.set_user_name(dlg->getName().toStdString()); + cmd.set_reason(dlg->getReason().toStdString()); + cmd.set_clientid(dlg->getWarnID().toStdString()); + + client->sendCommand(client->prepareModeratorCommand(cmd)); + +} + void UserContextMenu::showContextMenu(const QPoint &pos, const QString &userName, UserLevelFlags userLevel, bool online, int playerId) { aUserName->setText(userName); @@ -197,6 +285,9 @@ void UserContextMenu::showContextMenu(const QPoint &pos, const QString &userName menu->addAction(aKick); } if (!tabSupervisor->getAdminLocked()) { + menu->addSeparator(); + menu->addAction(aWarnUser); + menu->addAction(aWarnHistory); menu->addSeparator(); menu->addAction(aBan); menu->addAction(aBanHistory); @@ -218,6 +309,8 @@ void UserContextMenu::showContextMenu(const QPoint &pos, const QString &userName aAddToIgnoreList->setEnabled(anotherUser); aRemoveFromIgnoreList->setEnabled(anotherUser); aKick->setEnabled(anotherUser); + aWarnUser->setEnabled(anotherUser); + aWarnHistory->setEnabled(anotherUser); aBan->setEnabled(anotherUser); aBanHistory->setEnabled(anotherUser); aPromoteToMod->setEnabled(anotherUser); @@ -288,6 +381,18 @@ void UserContextMenu::showContextMenu(const QPoint &pos, const QString &userName PendingCommand *pend = client->prepareModeratorCommand(cmd); connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this, SLOT(banUserHistory_processResponse(Response))); client->sendCommand(pend); + } else if (actionClicked == aWarnUser) { + Command_GetUserInfo cmd; + cmd.set_user_name(userName.toStdString()); + PendingCommand *pend = client->prepareSessionCommand(cmd); + connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this, SLOT(warnUser_processUserInfoResponse(Response))); + client->sendCommand(pend); + } else if (actionClicked == aWarnHistory) { + Command_GetWarnHistory cmd; + cmd.set_user_name(userName.toStdString()); + PendingCommand *pend = client->prepareModeratorCommand(cmd); + connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this, SLOT(warnUserHistory_processResponse(Response))); + client->sendCommand(pend); } delete menu; diff --git a/cockatrice/src/user_context_menu.h b/cockatrice/src/user_context_menu.h index 2093616a..442fd067 100644 --- a/cockatrice/src/user_context_menu.h +++ b/cockatrice/src/user_context_menu.h @@ -11,6 +11,7 @@ class QPoint; class CommandContainer; class Response; class AbstractClient; +class ServerInfo_User; class UserContextMenu : public QObject { Q_OBJECT @@ -28,13 +29,18 @@ private: QAction *aKick; QAction *aBan, *aBanHistory; QAction *aPromoteToMod, *aDemoteFromMod; + QAction *aWarnUser, *aWarnHistory; signals: void openMessageDialog(const QString &userName, bool focus); private slots: void banUser_processUserInfoResponse(const Response &resp); + void warnUser_processGetWarningsListResponse(const Response &r); + void warnUser_processUserInfoResponse(const Response &resp); void banUserHistory_processResponse(const Response &resp); + void warnUserHistory_processResponse(const Response &resp); void adjustMod_processUserResponse(const Response &resp, const CommandContainer &commandContainer); void banUser_dialogFinished(); + void warnUser_dialogFinished(); void gamesOfUserReceived(const Response &resp, const CommandContainer &commandContainer); public: UserContextMenu(const TabSupervisor *_tabSupervisor, QWidget *_parent, TabGame *_game = 0); diff --git a/cockatrice/src/userlist.cpp b/cockatrice/src/userlist.cpp index 87a282e9..25868505 100644 --- a/cockatrice/src/userlist.cpp +++ b/cockatrice/src/userlist.cpp @@ -18,7 +18,6 @@ #include #include #include - #include "pending_command.h" #include "pb/session_commands.pb.h" #include "pb/moderator_commands.pb.h" @@ -116,6 +115,71 @@ BanDialog::BanDialog(const ServerInfo_User &info, QWidget *parent) setWindowTitle(tr("Ban user from server")); } +WarningDialog::WarningDialog(const QString userName, const QString clientID, QWidget *parent) + : QDialog(parent) +{ + setAttribute(Qt::WA_DeleteOnClose); + descriptionLabel = new QLabel(tr("Which warning would you like to send?")); + nameWarning = new QLineEdit(userName); + warnClientID = new QLineEdit(clientID); + warningOption = new QComboBox(); + warningOption->addItem(""); + + QPushButton *okButton = new QPushButton(tr("&OK")); + okButton->setAutoDefault(true); + connect(okButton, SIGNAL(clicked()), this, SLOT(okClicked())); + QPushButton *cancelButton = new QPushButton(tr("&Cancel")); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); + + QHBoxLayout *buttonLayout = new QHBoxLayout; + buttonLayout->addStretch(); + buttonLayout->addWidget(okButton); + buttonLayout->addWidget(cancelButton); + + QVBoxLayout *vbox = new QVBoxLayout; + vbox->addWidget(descriptionLabel); + vbox->addWidget(nameWarning); + vbox->addWidget(warningOption); + vbox->addLayout(buttonLayout); + setLayout(vbox); + setWindowTitle(tr("Warn user for misconduct")); +} + +void WarningDialog::okClicked() +{ + if (nameWarning->text().simplified().isEmpty()) { + QMessageBox::critical(this, tr("Error"), tr("User name to send a warning to can not be blank, please specify a user to warn.")); + return; + } + + if (warningOption->currentText().simplified().isEmpty()) { + QMessageBox::critical(this, tr("Error"), tr("Warning to use can not be blank, please select a valid warning to send.")); + return; + } + + accept(); +} + +QString WarningDialog::getName() const +{ + return nameWarning->text().simplified(); +} + +QString WarningDialog::getWarnID() const +{ + return warnClientID->text().simplified(); +} + +QString WarningDialog::getReason() const +{ + return warningOption->currentText().simplified(); +} + +void WarningDialog::addWarningOption(const QString warning) +{ + warningOption->addItem(warning); +} + void BanDialog::okClicked() { if (!nameBanCheckBox->isChecked() && !ipBanCheckBox->isChecked() && !idBanCheckBox->isChecked()) { diff --git a/cockatrice/src/userlist.h b/cockatrice/src/userlist.h index 3ac47a08..ab9146dc 100644 --- a/cockatrice/src/userlist.h +++ b/cockatrice/src/userlist.h @@ -3,9 +3,11 @@ #include #include +#include #include #include #include "user_level.h" +#include "pb/moderator_commands.pb.h" class QTreeWidget; class ServerInfo_User; @@ -42,6 +44,23 @@ public: QString getVisibleReason() const; }; +class WarningDialog : public QDialog { + Q_OBJECT +private: + QLabel *descriptionLabel; + QLineEdit *nameWarning; + QComboBox *warningOption; + QLineEdit * warnClientID; +private slots: + void okClicked(); +public: + WarningDialog(const QString userName, const QString clientID, QWidget *parent = 0); + QString getName() const; + QString getWarnID() const; + QString getReason() const; + void addWarningOption(const QString warning); +}; + class UserListItemDelegate : public QStyledItemDelegate { public: UserListItemDelegate(QObject *const parent); diff --git a/common/featureset.cpp b/common/featureset.cpp index a1d44511..59135bfa 100644 --- a/common/featureset.cpp +++ b/common/featureset.cpp @@ -12,12 +12,13 @@ QMap FeatureSet::getDefaultFeatureList() { return featureList; } -void FeatureSet::initalizeFeatureList(QMap &featureList){ +void FeatureSet::initalizeFeatureList(QMap &featureList) { featureList.insert("client_id", false); featureList.insert("client_ver", false); featureList.insert("feature_set", false); featureList.insert("user_ban_history", false); featureList.insert("room_chat_history", false); + featureList.insert("client_warnings", false); } void FeatureSet::enableRequiredFeature(QMap &featureList, QString featureName){ diff --git a/common/pb/CMakeLists.txt b/common/pb/CMakeLists.txt index 32063204..875b067a 100644 --- a/common/pb/CMakeLists.txt +++ b/common/pb/CMakeLists.txt @@ -130,6 +130,8 @@ SET(PROTO_FILES response_replay_download.proto response_replay_list.proto response_adjust_mod.proto + response_warn_history.proto + response_warn_list.proto response.proto room_commands.proto room_event.proto @@ -149,6 +151,7 @@ SET(PROTO_FILES serverinfo_replay_match.proto serverinfo_room.proto serverinfo_user.proto + serverinfo_warning.proto serverinfo_zone.proto server_message.proto session_commands.proto diff --git a/common/pb/event_notify_user.proto b/common/pb/event_notify_user.proto index dadc5b99..d909259e 100644 --- a/common/pb/event_notify_user.proto +++ b/common/pb/event_notify_user.proto @@ -5,11 +5,13 @@ message Event_NotifyUser { enum NotificationType { PROMOTED = 1; + WARNING = 2; } extend SessionEvent { optional Event_NotifyUser ext = 1010; } optional NotificationType type = 1; + optional string warning_reason = 2; } diff --git a/common/pb/moderator_commands.proto b/common/pb/moderator_commands.proto index 86e4e67f..0c6b473b 100644 --- a/common/pb/moderator_commands.proto +++ b/common/pb/moderator_commands.proto @@ -3,6 +3,9 @@ message ModeratorCommand { enum ModeratorCommandType { BAN_FROM_SERVER = 1000; BAN_HISTORY = 1001; + WARN_USER = 1002; + WARN_HISTORY = 1003; + WARN_LIST = 1004; } extensions 100 to max; } @@ -24,4 +27,30 @@ message Command_GetBanHistory { optional Command_GetBanHistory ext = 1001; } optional string user_name = 1; +} + +message Command_WarnUser { + extend ModeratorCommand { + optional Command_WarnUser ext = 1002; + } + + optional string user_name = 1; + optional string reason = 2; + optional string clientid = 3; +} + +message Command_GetWarnHistory { + extend ModeratorCommand { + optional Command_GetWarnHistory ext = 1003; + } + optional string user_name = 1; +} + +message Command_GetWarnList { + extend ModeratorCommand { + optional Command_GetWarnList ext = 1004; + } + optional string mod_name = 1; + optional string user_name = 2; + optional string user_clientid = 3; } \ No newline at end of file diff --git a/common/pb/response.proto b/common/pb/response.proto index 7004ba50..a2947a0e 100644 --- a/common/pb/response.proto +++ b/common/pb/response.proto @@ -53,6 +53,8 @@ message Response { ACTIVATE = 1010; ADJUST_MOD = 1011; BAN_HISTORY = 1012; + WARN_HISTORY = 1013; + WARN_LIST = 1014; REPLAY_LIST = 1100; REPLAY_DOWNLOAD = 1101; } diff --git a/common/pb/response_warn_history.proto b/common/pb/response_warn_history.proto new file mode 100644 index 00000000..a43180f3 --- /dev/null +++ b/common/pb/response_warn_history.proto @@ -0,0 +1,10 @@ +syntax = "proto2"; +import "response.proto"; +import "serverinfo_warning.proto"; + +message Response_WarnHistory{ + extend Response { + optional Response_WarnHistory ext = 1013; + } + repeated ServerInfo_Warning warn_list = 1; +} diff --git a/common/pb/response_warn_list.proto b/common/pb/response_warn_list.proto new file mode 100644 index 00000000..8d893103 --- /dev/null +++ b/common/pb/response_warn_list.proto @@ -0,0 +1,11 @@ +syntax = "proto2"; +import "response.proto"; + +message Response_WarnList{ + extend Response { + optional Response_WarnList ext = 1014; + } + repeated string warning = 1; + optional string user_name = 2; + optional string user_clientid = 3; +} diff --git a/common/pb/serverinfo_warning.proto b/common/pb/serverinfo_warning.proto new file mode 100644 index 00000000..f2efed57 --- /dev/null +++ b/common/pb/serverinfo_warning.proto @@ -0,0 +1,10 @@ +syntax = "proto2"; +/* + * Historical warning information stored in the warnings table + */ +message ServerInfo_Warning { + optional string user_name = 1; // name of user being warned + optional string admin_name = 2; // name of the moderator making the warning + optional string reason = 3; // type of warning being placed + optional string time_of = 4; // time of warning +} diff --git a/common/server.cpp b/common/server.cpp index 33313ab2..8b93a815 100644 --- a/common/server.cpp +++ b/common/server.cpp @@ -629,4 +629,4 @@ void Server::sendIsl_RoomCommand(const CommandContainer &item, int serverId, qin cont->set_room_id(roomId); emit sigSendIslMessage(msg, serverId); -} \ No newline at end of file +} diff --git a/common/server.h b/common/server.h index 6baebc8f..490d8b95 100644 --- a/common/server.h +++ b/common/server.h @@ -10,6 +10,7 @@ #include "pb/commands.pb.h" #include "pb/serverinfo_user.pb.h" #include "pb/serverinfo_ban.pb.h" +#include "pb/serverinfo_warning.pb.h" #include "server_player_reference.h" class Server_DatabaseInterface; diff --git a/servatrice/migrations/servatrice_0009_to_0010.sql b/servatrice/migrations/servatrice_0009_to_0010.sql new file mode 100644 index 00000000..3502d1b8 --- /dev/null +++ b/servatrice/migrations/servatrice_0009_to_0010.sql @@ -0,0 +1,13 @@ +-- Servatrice db migration from version 9 to version 10 + +CREATE TABLE IF NOT EXISTS `cockatrice_warnings` ( + `id` int(7) unsigned NOT NULL, + `user_name` varchar(255) NOT NULL, + `mod_name` varchar(255) NOT NULL, + `reason` text NOT NULL, + `time_of` datetime NOT NULL, + `clientid` varchar(15) NOT NULL, + PRIMARY KEY (`user_name`,`time_of`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +UPDATE cockatrice_schema_version SET version=10 WHERE version=9; diff --git a/servatrice/servatrice.ini.example b/servatrice/servatrice.ini.example index a300c44a..06d00497 100644 --- a/servatrice/servatrice.ini.example +++ b/servatrice/servatrice.ini.example @@ -56,6 +56,11 @@ requireclientid=false ; attempting to log in. Example: "client_id,client_ver" requiredfeatures="" +; You can define custom warnings that users are sent when the moderation staff uses the right client warn user +; menu option. This list is comma seperated that each item will appear in the drop down list for staff members +; to choose from. Example: "Flaming,Foul Language" +officialwarnings="Flamming,Spamming,Causing Drama,Abusive Language" + [authentication] ; Servatrice can authenticate users connecting. It currently supports 3 different authentication methods: diff --git a/servatrice/servatrice.sql b/servatrice/servatrice.sql index 50161676..09ecb6f9 100644 --- a/servatrice/servatrice.sql +++ b/servatrice/servatrice.sql @@ -20,7 +20,7 @@ CREATE TABLE IF NOT EXISTS `cockatrice_schema_version` ( PRIMARY KEY (`version`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -INSERT INTO cockatrice_schema_version VALUES(8); +INSERT INTO cockatrice_schema_version VALUES(10); CREATE TABLE IF NOT EXISTS `cockatrice_decklist_files` ( `id` int(7) unsigned zerofill NOT NULL auto_increment, @@ -138,6 +138,16 @@ CREATE TABLE IF NOT EXISTS `cockatrice_bans` ( KEY `ip_address` (`ip_address`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `cockatrice_warnings` ( + `id` int(7) unsigned NOT NULL, + `user_name` varchar(255) NOT NULL, + `mod_name` varchar(255) NOT NULL + `reason` text NOT NULL, + `time_of` datetime NOT NULL, + `clientid` varchar(15) NOT NULL, + PRIMARY KEY (`user_name`,`time_of`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + CREATE TABLE IF NOT EXISTS `cockatrice_sessions` ( `id` int(9) NOT NULL AUTO_INCREMENT, `user_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, diff --git a/servatrice/src/servatrice.h b/servatrice/src/servatrice.h index ad42497b..e89cfdef 100644 --- a/servatrice/src/servatrice.h +++ b/servatrice/src/servatrice.h @@ -113,6 +113,7 @@ private: QString dbPrefix; QString requiredFeatures; QMap serverRequiredFeatureList; + QString officialWarnings; Servatrice_DatabaseInterface *servatriceDatabaseInterface; int serverId; int uptime; @@ -139,6 +140,7 @@ public: ~Servatrice(); bool initServer(); QMap getServerRequiredFeatureList() const { return serverRequiredFeatureList; } + QString getOfficialWarningsList() const { return officialWarnings; } QString getServerName() const { return serverName; } QString getLoginMessage() const { QMutexLocker locker(&loginMessageMutex); return loginMessage; } QString getRequiredFeatures() const { return requiredFeatures; } diff --git a/servatrice/src/servatrice_database_interface.cpp b/servatrice/src/servatrice_database_interface.cpp index f88af904..d4845be1 100644 --- a/servatrice/src/servatrice_database_interface.cpp +++ b/servatrice/src/servatrice_database_interface.cpp @@ -940,7 +940,7 @@ QList Servatrice_DatabaseInterface::getUserBanHistory(const QStr return results; } - QString adminID,adminName,banTime,banLength,banReason,visibleReason; + //QString adminID,adminName,banTime,banLength,banReason,visibleReason; while (query->next()){ banDetails.set_admin_id(QString(query->value(0).toString()).toStdString()); banDetails.set_admin_name(QString(query->value(5).toString()).toStdString()); @@ -953,3 +953,51 @@ QList Servatrice_DatabaseInterface::getUserBanHistory(const QStr return results; } + +bool Servatrice_DatabaseInterface::addWarning(const QString userName, const QString adminName, const QString warningReason, const QString clientID) +{ + if (!checkSql()) + return false; + + int userID = getUserIdInDB(userName); + QSqlQuery *query = prepareQuery("insert into {prefix}_warnings (id,user_name,mod_name,reason,time_of,clientid) values (:user_id,:user_name,:mod_name,:warn_reason,NOW(),:client_id)"); + query->bindValue(":user_id", userID); + query->bindValue(":user_name", userName); + query->bindValue(":mod_name", adminName); + query->bindValue(":warn_reason", warningReason); + query->bindValue(":client_id", clientID); + if (!execSqlQuery(query)) { + qDebug("Failed to collect create warning history information: SQL Error"); + return false; + } + + return true; +} + +QList Servatrice_DatabaseInterface::getUserWarnHistory(const QString userName) +{ + QList results; + ServerInfo_Warning warnDetails; + + if (!checkSql()) + return results; + + int userID = getUserIdInDB(userName); + QSqlQuery *query = prepareQuery("SELECT user_name, mod_name, reason, time_of FROM {prefix}_warnings WHERE id = :user_id"); + query->bindValue(":user_id", userID); + + if (!execSqlQuery(query)) { + qDebug("Failed to collect warning history information: SQL Error"); + return results; + } + + while (query->next()){ + warnDetails.set_user_name(QString(query->value(0).toString()).toStdString()); + warnDetails.set_admin_name(QString(query->value(1).toString()).toStdString()); + warnDetails.set_reason(QString(query->value(2).toString()).toStdString()); + warnDetails.set_time_of(QString(query->value(3).toString()).toStdString()); + results << warnDetails; + } + + return results; +} \ No newline at end of file diff --git a/servatrice/src/servatrice_database_interface.h b/servatrice/src/servatrice_database_interface.h index 2319cd6f..23bdf3e4 100644 --- a/servatrice/src/servatrice_database_interface.h +++ b/servatrice/src/servatrice_database_interface.h @@ -9,7 +9,7 @@ #include "server.h" #include "server_database_interface.h" -#define DATABASE_SCHEMA_VERSION 9 +#define DATABASE_SCHEMA_VERSION 10 class Servatrice; @@ -79,6 +79,8 @@ public: bool changeUserPassword(const QString &user, const QString &oldPassword, const QString &newPassword); QChar getGenderChar(ServerInfo_User_Gender const &gender); QList getUserBanHistory(const QString userName); + bool addWarning(const QString userName, const QString adminName, const QString warningReason, const QString clientID); + QList getUserWarnHistory(const QString userName); }; #endif diff --git a/servatrice/src/serversocketinterface.cpp b/servatrice/src/serversocketinterface.cpp index 624dbc15..0ab23783 100644 --- a/servatrice/src/serversocketinterface.cpp +++ b/servatrice/src/serversocketinterface.cpp @@ -59,6 +59,8 @@ #include "pb/response_register.pb.h" #include "pb/response_replay_list.pb.h" #include "pb/response_replay_download.pb.h" +#include "pb/response_warn_history.pb.h" +#include "pb/response_warn_list.pb.h" #include "pb/serverinfo_replay.pb.h" #include "pb/serverinfo_user.pb.h" #include "pb/serverinfo_deckstorage.pb.h" @@ -305,6 +307,9 @@ Response::ResponseCode ServerSocketInterface::processExtendedModeratorCommand(in switch ((ModeratorCommand::ModeratorCommandType) cmdType) { case ModeratorCommand::BAN_FROM_SERVER: return cmdBanFromServer(cmd.GetExtension(Command_BanFromServer::ext), rc); case ModeratorCommand::BAN_HISTORY: return cmdGetBanHistory(cmd.GetExtension(Command_GetBanHistory::ext), rc); + case ModeratorCommand::WARN_USER: return cmdWarnUser(cmd.GetExtension(Command_WarnUser::ext), rc); + case ModeratorCommand::WARN_HISTORY: return cmdGetWarnHistory(cmd.GetExtension(Command_GetWarnHistory::ext), rc); + case ModeratorCommand::WARN_LIST: return cmdGetWarnList(cmd.GetExtension(Command_GetWarnList::ext), rc); default: return Response::RespFunctionNotAllowed; } } @@ -779,6 +784,70 @@ Response::ResponseCode ServerSocketInterface::cmdGetBanHistory(const Command_Get return Response::RespOk; } +Response::ResponseCode ServerSocketInterface::cmdGetWarnList(const Command_GetWarnList &cmd, ResponseContainer &rc) +{ + Response_WarnList *re = new Response_WarnList; + + QString officialWarnings = settingsCache->value("server/officialwarnings").toString(); + QStringList warningsList = officialWarnings.split(",", QString::SkipEmptyParts); + foreach(QString warning, warningsList){ + re->add_warning(warning.toStdString()); + } + re->set_user_name(cmd.user_name()); + re->set_user_clientid(cmd.user_clientid()); + rc.setResponseExtension(re); + return Response::RespOk; +} + +Response::ResponseCode ServerSocketInterface::cmdGetWarnHistory(const Command_GetWarnHistory &cmd, ResponseContainer &rc) +{ + QList warnList; + QString userName = QString::fromStdString(cmd.user_name()); + + Response_WarnHistory *re = new Response_WarnHistory; + QListIterator warnIterator(sqlInterface->getUserWarnHistory(userName)); + while (warnIterator.hasNext()) + re->add_warn_list()->CopyFrom(warnIterator.next()); + rc.setResponseExtension(re); + return Response::RespOk; +} + +Response::ResponseCode ServerSocketInterface::cmdWarnUser(const Command_WarnUser &cmd, ResponseContainer & /*rc*/) +{ + if (!sqlInterface->checkSql()) + return Response::RespInternalError; + + QString userName = QString::fromStdString(cmd.user_name()).simplified(); + QString warningReason = QString::fromStdString(cmd.reason()).simplified(); + QString clientID = QString::fromStdString(cmd.clientid()).simplified(); + QString sendingModerator = QString::fromStdString(userInfo->name()).simplified(); + + if (sqlInterface->addWarning(userName, sendingModerator, warningReason, clientID)) { + ServerSocketInterface *user = static_cast(server->getUsers().value(userName)); + if (user) { + Event_NotifyUser event; + event.set_type(Event_NotifyUser::WARNING); + event.set_warning_reason(cmd.reason()); + SessionEvent *se = user->prepareSessionEvent(event); + user->sendProtocolItem(*se); + delete se; + } + + QList moderatorList = server->getOnlineModeratorList(); + QListIterator modIterator(moderatorList); + foreach(QString moderator, moderatorList) { + QString notificationMessage = sendingModerator + " has sent a warning with the following information"; + notificationMessage.append("\n Username: " + userName); + notificationMessage.append("\n Reason: " + warningReason); + sendServerMessage(moderator.simplified(), notificationMessage); + } + + return Response::RespOk; + } else { + return Response::RespInternalError; + } +} + Response::ResponseCode ServerSocketInterface::cmdBanFromServer(const Command_BanFromServer &cmd, ResponseContainer & /*rc*/) { if (!sqlInterface->checkSql()) @@ -850,7 +919,7 @@ Response::ResponseCode ServerSocketInterface::cmdBanFromServer(const Command_Ban QList moderatorList = server->getOnlineModeratorList(); QListIterator modIterator(moderatorList); foreach(QString moderator, moderatorList) { - QString notificationMessage = "A ban has been added:"; + QString notificationMessage = QString::fromStdString(userInfo->name()).simplified() + " has placed a ban with the following information"; if (!userName.isEmpty()) notificationMessage.append("\n Username: " + userName); if (!address.isEmpty()) diff --git a/servatrice/src/serversocketinterface.h b/servatrice/src/serversocketinterface.h index a8bf48c9..0ba2f60b 100644 --- a/servatrice/src/serversocketinterface.h +++ b/servatrice/src/serversocketinterface.h @@ -97,7 +97,10 @@ private: Response::ResponseCode cmdReplayModifyMatch(const Command_ReplayModifyMatch &cmd, ResponseContainer &rc); Response::ResponseCode cmdReplayDeleteMatch(const Command_ReplayDeleteMatch &cmd, ResponseContainer &rc); Response::ResponseCode cmdBanFromServer(const Command_BanFromServer &cmd, ResponseContainer &rc); + Response::ResponseCode cmdWarnUser(const Command_WarnUser &cmd, ResponseContainer &rc); Response::ResponseCode cmdGetBanHistory(const Command_GetBanHistory &cmd, ResponseContainer &rc); + Response::ResponseCode cmdGetWarnList(const Command_GetWarnList &cmd, ResponseContainer &rc); + Response::ResponseCode cmdGetWarnHistory(const Command_GetWarnHistory &cmd, ResponseContainer &rc); Response::ResponseCode cmdShutdownServer(const Command_ShutdownServer &cmd, ResponseContainer &rc); Response::ResponseCode cmdUpdateServerMessage(const Command_UpdateServerMessage &cmd, ResponseContainer &rc); Response::ResponseCode cmdRegisterAccount(const Command_Register &cmd, ResponseContainer &rc);