mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-22 01:25:10 -07:00
Two gaps made opening and confirming the banner dialog silently switch the banner to the default art of the first local printing. The caller dropped the card provider id when constructing the initial params, and the constructor left the printing combo wherever onCardNameChanged put it, which is always the first printing Pass the provider id through, restore it in the combo when it resolves locally, and keep it verbatim when it does not Took 2 minutes Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
434 lines
16 KiB
C++
434 lines
16 KiB
C++
#include "user_info_box.h"
|
|
|
|
#include "../../interface/pixel_map_generator.h"
|
|
#include "../../interface/widgets/dialogs/dlg_edit_avatar.h"
|
|
#include "../../interface/widgets/dialogs/dlg_edit_password.h"
|
|
#include "../../interface/widgets/dialogs/dlg_edit_user.h"
|
|
#include "../../interface/widgets/utility/get_text_with_max.h"
|
|
#include "user_card_settings_dialog.h"
|
|
|
|
#include <QDateTime>
|
|
#include <QGridLayout>
|
|
#include <QHBoxLayout>
|
|
#include <QInputDialog>
|
|
#include <QLabel>
|
|
#include <QMessageBox>
|
|
#include <libcockatrice/network/client/abstract/abstract_client.h>
|
|
#include <libcockatrice/protocol/pb/response_get_user_info.pb.h>
|
|
#include <libcockatrice/protocol/pb/serverinfo_user.pb.h>
|
|
#include <libcockatrice/protocol/pb/session_commands.pb.h>
|
|
#include <libcockatrice/protocol/pending_command.h>
|
|
#include <libcockatrice/utility/passwordhasher.h>
|
|
|
|
UserInfoBox::UserInfoBox(AbstractClient *_client, bool _editable, QWidget *parent, Qt::WindowFlags flags)
|
|
: QWidget(parent, flags), client(_client), editable(_editable)
|
|
{
|
|
QFont nameFont = nameLabel.font();
|
|
nameFont.setBold(true);
|
|
nameFont.setPointSizeF(nameFont.pointSizeF() * 1.5);
|
|
nameLabel.setFont(nameFont);
|
|
|
|
auto *userIconAndNameLayout = new QHBoxLayout;
|
|
userIconAndNameLayout->addWidget(&userLevelIcon, 0, Qt::AlignCenter);
|
|
userIconAndNameLayout->addWidget(&nameLabel, 1);
|
|
userIconAndNameLayout->addStretch();
|
|
|
|
avatarPic.setMinimumSize(200, 200);
|
|
avatarPic.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
avatarPic.setAlignment(Qt::AlignCenter);
|
|
|
|
auto *avatarLayout = new QHBoxLayout;
|
|
avatarLayout->setContentsMargins(0, 0, 0, 0);
|
|
avatarLayout->addStretch(1);
|
|
avatarLayout->addWidget(&avatarPic, 3);
|
|
avatarLayout->addStretch(1);
|
|
|
|
auto *mainLayout = new QGridLayout;
|
|
mainLayout->addLayout(avatarLayout, 0, 0, 1, 3);
|
|
mainLayout->addLayout(userIconAndNameLayout, 1, 0, 1, 3);
|
|
mainLayout->addWidget(&realNameLabel1, 2, 0, 1, 1);
|
|
mainLayout->addWidget(&realNameLabel2, 2, 1, 1, 2);
|
|
mainLayout->addWidget(&countryLabel1, 3, 0, 1, 1);
|
|
mainLayout->addWidget(&countryLabel2, 3, 1, 1, 1, Qt::AlignCenter);
|
|
mainLayout->addWidget(&countryLabel3, 3, 2, 1, 1);
|
|
mainLayout->addWidget(&userLevelLabel1, 4, 0, 1, 1);
|
|
mainLayout->addWidget(&userLevelLabel2, 4, 1, 1, 2);
|
|
mainLayout->addWidget(&accountAgeLabel1, 5, 0, 1, 1);
|
|
mainLayout->addWidget(&accountAgeLabel2, 5, 1, 1, 2);
|
|
mainLayout->setColumnStretch(2, 10);
|
|
|
|
if (editable) {
|
|
auto *buttonsLayout = new QHBoxLayout;
|
|
buttonsLayout->addWidget(&editButton);
|
|
buttonsLayout->addWidget(&passwordButton);
|
|
buttonsLayout->addWidget(&avatarButton);
|
|
buttonsLayout->addWidget(&bannerCardButton);
|
|
mainLayout->addLayout(buttonsLayout, 7, 0, 1, 3);
|
|
|
|
connect(&editButton, &QPushButton::clicked, this, &UserInfoBox::actEdit);
|
|
connect(&passwordButton, &QPushButton::clicked, this, &UserInfoBox::actPassword);
|
|
connect(&avatarButton, &QPushButton::clicked, this, &UserInfoBox::actAvatar);
|
|
connect(&bannerCardButton, &QPushButton::clicked, this, &UserInfoBox::actBannerCard);
|
|
}
|
|
|
|
setWindowTitle(tr("User Information"));
|
|
setLayout(mainLayout);
|
|
retranslateUi();
|
|
}
|
|
|
|
void UserInfoBox::retranslateUi()
|
|
{
|
|
realNameLabel1.setText(tr("Real Name:"));
|
|
countryLabel1.setText(tr("Location:"));
|
|
userLevelLabel1.setText(tr("User Level:"));
|
|
accountAgeLabel1.setText(tr("Account Age:"));
|
|
|
|
editButton.setText(tr("Edit"));
|
|
passwordButton.setText(tr("Change password"));
|
|
avatarButton.setText(tr("Change avatar"));
|
|
bannerCardButton.setText(tr("Edit Banner Card"));
|
|
}
|
|
|
|
void UserInfoBox::updateInfo(const ServerInfo_User &user)
|
|
{
|
|
currentUserInfo = user;
|
|
hasUserInfo = true;
|
|
|
|
const UserLevelFlags userLevel(user.user_level());
|
|
pawnColors = user.pawn_colors();
|
|
privLevel = QString::fromStdString(user.privlevel());
|
|
|
|
const std::string &bmp = user.avatar_bmp();
|
|
if (!avatarPixmap.loadFromData((const uchar *)bmp.data(), static_cast<uint>(bmp.size()))) {
|
|
avatarPixmap = UserLevelPixmapGenerator::generatePixmap(64, userLevel, pawnColors, false, privLevel);
|
|
hasAvatar = false;
|
|
} else {
|
|
hasAvatar = true;
|
|
}
|
|
|
|
nameLabel.setText(QString::fromStdString(user.name()));
|
|
realNameLabel2.setText(QString::fromStdString(user.real_name()));
|
|
QString country = QString::fromStdString(user.country());
|
|
|
|
if (country.length() != 0) {
|
|
countryLabel2.setPixmap(CountryPixmapGenerator::generatePixmap(13, country));
|
|
countryLabel3.setText(QString("%1").arg(country.toUpper()));
|
|
} else {
|
|
countryLabel2.setText("");
|
|
countryLabel3.setText("");
|
|
}
|
|
|
|
userLevelIcon.setPixmap(UserLevelPixmapGenerator::generatePixmap(15, userLevel, pawnColors, false, privLevel));
|
|
QString userLevelText;
|
|
if (userLevel.testFlag(ServerInfo_User::IsAdmin)) {
|
|
userLevelText = tr("Administrator");
|
|
} else if (userLevel.testFlag(ServerInfo_User::IsModerator)) {
|
|
userLevelText = tr("Moderator");
|
|
} else if (userLevel.testFlag(ServerInfo_User::IsRegistered)) {
|
|
userLevelText = tr("Registered user");
|
|
} else {
|
|
userLevelText = tr("Unregistered user");
|
|
}
|
|
|
|
if (userLevel.testFlag(ServerInfo_User::IsJudge)) {
|
|
userLevelText += " | " + tr("Judge");
|
|
}
|
|
|
|
if (user.has_privlevel() && user.privlevel() != "NONE") {
|
|
userLevelText += " | " + QString("%1").arg(user.privlevel().c_str());
|
|
}
|
|
|
|
userLevelLabel2.setText(userLevelText);
|
|
|
|
QString accountAgeString = tr("Unregistered user");
|
|
if (userLevel.testFlag(ServerInfo_User::IsAdmin) || userLevel.testFlag(ServerInfo_User::IsModerator) ||
|
|
userLevel.testFlag(ServerInfo_User::IsRegistered)) {
|
|
accountAgeString = getAgeString(user.accountage_secs());
|
|
}
|
|
accountAgeLabel2.setText(accountAgeString);
|
|
}
|
|
|
|
QString UserInfoBox::getAgeString(int ageSeconds)
|
|
{
|
|
QString accountAgeString = tr("Unknown");
|
|
if (ageSeconds <= 0) {
|
|
return accountAgeString;
|
|
}
|
|
|
|
// secsSinceEpoch is in utc
|
|
auto secsSinceEpoch = QDateTime::currentSecsSinceEpoch() - ageSeconds;
|
|
// the date is in local time, fromSecsSinceEpoch expects a timestamp from utc and converts it to local time
|
|
auto date = QDateTime::fromSecsSinceEpoch(secsSinceEpoch).date();
|
|
if (!date.isValid()) {
|
|
return accountAgeString;
|
|
}
|
|
|
|
// now can be local time as the date is also local time
|
|
auto now = QDate::currentDate();
|
|
auto daysAndYears = getDaysAndYearsBetween(date, now);
|
|
|
|
QString dateString = QLocale().toString(date, QLocale::ShortFormat);
|
|
QString yearString;
|
|
if (daysAndYears.second > 0) {
|
|
yearString = tr("%n Year(s), ", "amount of years (only shown if more than 0)", daysAndYears.second);
|
|
}
|
|
accountAgeString =
|
|
tr("%10%n Day(s) %20", "amount of years (if more than 0), amount of days, date in local short format",
|
|
daysAndYears.first)
|
|
.arg(yearString)
|
|
.arg(dateString);
|
|
return accountAgeString;
|
|
}
|
|
|
|
void UserInfoBox::updateInfo(const QString &userName)
|
|
{
|
|
Command_GetUserInfo cmd;
|
|
cmd.set_user_name(userName.toStdString());
|
|
|
|
PendingCommand *pend = client->prepareSessionCommand(cmd);
|
|
connect(pend, &PendingCommand::finished, this, &UserInfoBox::processResponse);
|
|
|
|
client->sendCommand(pend);
|
|
}
|
|
|
|
void UserInfoBox::processResponse(const Response &r)
|
|
{
|
|
const Response_GetUserInfo &response = r.GetExtension(Response_GetUserInfo::ext);
|
|
updateInfo(response.user_info());
|
|
resize(sizeHint());
|
|
show();
|
|
}
|
|
|
|
void UserInfoBox::actEdit()
|
|
{
|
|
Command_GetUserInfo cmd;
|
|
|
|
PendingCommand *pend = client->prepareSessionCommand(cmd);
|
|
connect(pend, &PendingCommand::finished, this, &UserInfoBox::actEditInternal);
|
|
|
|
client->sendCommand(pend);
|
|
}
|
|
|
|
void UserInfoBox::actEditInternal(const Response &r)
|
|
{
|
|
const Response_GetUserInfo &response = r.GetExtension(Response_GetUserInfo::ext);
|
|
const ServerInfo_User &user = response.user_info();
|
|
|
|
QString email = QString::fromStdString(user.email());
|
|
QString country = QString::fromStdString(user.country());
|
|
QString realName = QString::fromStdString(user.real_name());
|
|
|
|
DlgEditUser dlg(this, email, country, realName);
|
|
if (!dlg.exec()) {
|
|
return;
|
|
}
|
|
|
|
Command_AccountEdit cmd;
|
|
cmd.set_real_name(dlg.getRealName().toStdString());
|
|
if (client->getServerSupportsPasswordHash()) {
|
|
if (email != dlg.getEmail()) {
|
|
// real password is required to change email
|
|
bool ok = false;
|
|
QString password =
|
|
getTextWithMax(this, tr("Enter Password"),
|
|
tr("Password verification is required in order to change your email address"),
|
|
QLineEdit::Password, "", &ok);
|
|
if (!ok) {
|
|
return;
|
|
}
|
|
cmd.set_password_check(password.toStdString());
|
|
cmd.set_email(dlg.getEmail().toStdString());
|
|
} // servers that support password hash do not require all fields to be filled anymore
|
|
} else {
|
|
cmd.set_email(dlg.getEmail().toStdString());
|
|
}
|
|
cmd.set_country(dlg.getCountry().toStdString());
|
|
|
|
PendingCommand *pend = client->prepareSessionCommand(cmd);
|
|
connect(pend, &PendingCommand::finished, this, &UserInfoBox::processEditResponse);
|
|
|
|
client->sendCommand(pend);
|
|
}
|
|
|
|
void UserInfoBox::actPassword()
|
|
{
|
|
DlgEditPassword dlg(this);
|
|
if (!dlg.exec()) {
|
|
return;
|
|
}
|
|
|
|
auto oldPassword = dlg.getOldPassword();
|
|
auto newPassword = dlg.getNewPassword();
|
|
|
|
if (client->getServerSupportsPasswordHash()) {
|
|
Command_RequestPasswordSalt cmd;
|
|
cmd.set_user_name(client->getUserName().toStdString());
|
|
|
|
PendingCommand *pend = client->prepareSessionCommand(cmd);
|
|
connect(pend, &PendingCommand::finished, this, [=, this](const Response &response) {
|
|
if (response.response_code() == Response::RespOk) {
|
|
changePassword(oldPassword, newPassword);
|
|
} else {
|
|
QMessageBox::critical(this, tr("Error"),
|
|
tr("An error occurred while trying to update your user information."));
|
|
}
|
|
});
|
|
client->sendCommand(pend);
|
|
} else {
|
|
changePassword(oldPassword, newPassword);
|
|
}
|
|
}
|
|
|
|
void UserInfoBox::changePassword(const QString &oldPassword, const QString &newPassword)
|
|
{
|
|
Command_AccountPassword cmd;
|
|
cmd.set_old_password(oldPassword.toStdString());
|
|
if (client->getServerSupportsPasswordHash()) {
|
|
auto passwordSalt = PasswordHasher::generateRandomSalt();
|
|
QString hashedPassword = PasswordHasher::computeHash(newPassword, passwordSalt);
|
|
cmd.set_hashed_new_password(hashedPassword.toStdString());
|
|
} else {
|
|
cmd.set_new_password(newPassword.toStdString());
|
|
}
|
|
|
|
PendingCommand *pend = client->prepareSessionCommand(cmd);
|
|
connect(pend, &PendingCommand::finished, this, &UserInfoBox::processPasswordResponse);
|
|
|
|
client->sendCommand(pend);
|
|
}
|
|
|
|
void UserInfoBox::actAvatar()
|
|
{
|
|
DlgEditAvatar dlg(this);
|
|
if (!dlg.exec()) {
|
|
return;
|
|
}
|
|
|
|
Command_AccountImage cmd;
|
|
cmd.set_image(dlg.getImage().data(), dlg.getImage().size());
|
|
|
|
PendingCommand *pend = client->prepareSessionCommand(cmd);
|
|
connect(pend, &PendingCommand::finished, this, &UserInfoBox::processAvatarResponse);
|
|
|
|
client->sendCommand(pend);
|
|
}
|
|
|
|
void UserInfoBox::actBannerCard()
|
|
{
|
|
CardArtParams initial;
|
|
if (hasUserInfo && currentUserInfo.has_card_art_params()) {
|
|
const auto &cap = currentUserInfo.card_art_params();
|
|
initial.cardName = QString::fromStdString(cap.card_name());
|
|
initial.cardProviderId = QString::fromStdString(cap.card_provider_id());
|
|
initial.marginPctL = cap.margin_pct_l();
|
|
initial.marginPctR = cap.margin_pct_r();
|
|
initial.verticalOffset = cap.vertical_offset();
|
|
initial.zoom = cap.zoom();
|
|
}
|
|
|
|
UserCardArtSettingsDialog dlg(initial, this);
|
|
if (dlg.exec() != QDialog::Accepted) {
|
|
return;
|
|
}
|
|
|
|
const CardArtParams p = dlg.params();
|
|
|
|
Command_SetCardArtParams cmd;
|
|
cmd.set_card_name(p.cardName.toStdString());
|
|
if (!p.cardName.isEmpty()) {
|
|
cmd.set_card_provider_id(p.cardProviderId.toStdString());
|
|
cmd.set_margin_pct_l(p.marginPctL);
|
|
cmd.set_margin_pct_r(p.marginPctR);
|
|
cmd.set_vertical_offset(p.verticalOffset);
|
|
cmd.set_zoom(p.zoom);
|
|
}
|
|
|
|
PendingCommand *pend = client->prepareSessionCommand(cmd);
|
|
connect(pend, &PendingCommand::finished, this, [p, this](const Response &r) {
|
|
if (r.response_code() != Response::RespOk) {
|
|
QMessageBox::critical(this, tr("Error"),
|
|
tr("The selected card is blacklisted on this server or another error occurred."));
|
|
} else {
|
|
updateInfo(nameLabel.text()); // re-fetch so currentUserInfo reflects the change
|
|
QMessageBox::information(this, tr("Information"),
|
|
p.cardName.isEmpty() ? tr("Banner card removed.") : tr("Banner card updated."));
|
|
}
|
|
});
|
|
client->sendCommand(pend);
|
|
}
|
|
|
|
void UserInfoBox::processEditResponse(const Response &r)
|
|
{
|
|
switch (r.response_code()) {
|
|
case Response::RespOk:
|
|
updateInfo(nameLabel.text());
|
|
QMessageBox::information(this, tr("Information"), tr("User information updated."));
|
|
break;
|
|
case Response::RespFunctionNotAllowed:
|
|
QMessageBox::critical(this, tr("Error"),
|
|
tr("This server does not permit you to update your user informations."));
|
|
break;
|
|
case Response::RespWrongPassword:
|
|
QMessageBox::critical(this, tr("Error"), tr("The entered password does not match your account."));
|
|
break;
|
|
case Response::RespInternalError:
|
|
default:
|
|
QMessageBox::critical(this, tr("Error"),
|
|
tr("An error occurred while trying to update your user information."));
|
|
break;
|
|
}
|
|
}
|
|
|
|
void UserInfoBox::processPasswordResponse(const Response &r)
|
|
{
|
|
switch (r.response_code()) {
|
|
case Response::RespOk:
|
|
QMessageBox::information(this, tr("Information"), tr("Password changed."));
|
|
break;
|
|
case Response::RespFunctionNotAllowed:
|
|
QMessageBox::critical(this, tr("Error"), tr("This server does not permit you to change your password."));
|
|
break;
|
|
case Response::RespPasswordTooShort:
|
|
QMessageBox::critical(this, tr("Error"), tr("The new password is too short."));
|
|
break;
|
|
case Response::RespWrongPassword:
|
|
QMessageBox::critical(this, tr("Error"), tr("The old password is incorrect."));
|
|
break;
|
|
case Response::RespInternalError:
|
|
default:
|
|
QMessageBox::critical(this, tr("Error"),
|
|
tr("An error occurred while trying to update your user information."));
|
|
break;
|
|
}
|
|
}
|
|
|
|
void UserInfoBox::processAvatarResponse(const Response &r)
|
|
{
|
|
switch (r.response_code()) {
|
|
case Response::RespOk:
|
|
updateInfo(nameLabel.text());
|
|
QMessageBox::information(this, tr("Information"), tr("Avatar updated."));
|
|
break;
|
|
case Response::RespFunctionNotAllowed:
|
|
QMessageBox::critical(this, tr("Error"), tr("This server does not permit you to update your avatar."));
|
|
break;
|
|
case Response::RespInternalError:
|
|
default:
|
|
QMessageBox::critical(this, tr("Error"), tr("An error occured while trying to update your avatar."));
|
|
break;
|
|
}
|
|
}
|
|
|
|
void UserInfoBox::resizeEvent(QResizeEvent *event)
|
|
{
|
|
QPixmap resizedPixmap;
|
|
if (hasAvatar) {
|
|
resizedPixmap = avatarPixmap.scaled(avatarPic.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
|
} else {
|
|
int height = qMin(avatarPic.size().width(), avatarPic.size().height());
|
|
resizedPixmap = UserLevelPixmapGenerator::generatePixmap(height, userLevel, pawnColors, false, privLevel);
|
|
}
|
|
avatarPic.setPixmap(resizedPixmap);
|
|
|
|
QWidget::resizeEvent(event);
|
|
}
|