aboutsummaryrefslogtreecommitdiff
path: root/launcher/ui/dialogs/ProfileSetupDialog.cpp
diff options
context:
space:
mode:
authorPetr Mrázek <peterix@gmail.com>2021-11-22 03:55:16 +0100
committerPetr Mrázek <peterix@gmail.com>2021-11-22 03:55:16 +0100
commitb258eac215c791b2a8eed10cecbbf9551c87f0b9 (patch)
tree1ae72f62d344f6a9c982b9dc5d598d32fc742acc /launcher/ui/dialogs/ProfileSetupDialog.cpp
parent5040231f8d6ca865ea50250509c3315ea0c7400e (diff)
downloadPrismLauncher-b258eac215c791b2a8eed10cecbbf9551c87f0b9.tar.gz
PrismLauncher-b258eac215c791b2a8eed10cecbbf9551c87f0b9.tar.bz2
PrismLauncher-b258eac215c791b2a8eed10cecbbf9551c87f0b9.zip
NOISSUE continue reshuffling the codebase
Diffstat (limited to 'launcher/ui/dialogs/ProfileSetupDialog.cpp')
-rw-r--r--launcher/ui/dialogs/ProfileSetupDialog.cpp250
1 files changed, 250 insertions, 0 deletions
diff --git a/launcher/ui/dialogs/ProfileSetupDialog.cpp b/launcher/ui/dialogs/ProfileSetupDialog.cpp
new file mode 100644
index 00000000..d3e2b9a4
--- /dev/null
+++ b/launcher/ui/dialogs/ProfileSetupDialog.cpp
@@ -0,0 +1,250 @@
+/* Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ProfileSetupDialog.h"
+#include "ui_ProfileSetupDialog.h"
+
+#include <QPushButton>
+#include <QAction>
+#include <QRegExpValidator>
+#include <QJsonDocument>
+#include <QDebug>
+
+#include "ui/dialogs/ProgressDialog.h"
+
+#include <Application.h>
+#include "minecraft/auth/flows/AuthRequest.h"
+#include "minecraft/auth/flows/Parsers.h"
+
+
+ProfileSetupDialog::ProfileSetupDialog(MinecraftAccountPtr accountToSetup, QWidget *parent)
+ : QDialog(parent), m_accountToSetup(accountToSetup), ui(new Ui::ProfileSetupDialog)
+{
+ ui->setupUi(this);
+ ui->errorLabel->setVisible(false);
+
+ goodIcon = APPLICATION->getThemedIcon("status-good");
+ yellowIcon = APPLICATION->getThemedIcon("status-yellow");
+ badIcon = APPLICATION->getThemedIcon("status-bad");
+
+ QRegExp permittedNames("[a-zA-Z0-9_]{3,16}");
+ auto nameEdit = ui->nameEdit;
+ nameEdit->setValidator(new QRegExpValidator(permittedNames));
+ nameEdit->setClearButtonEnabled(true);
+ validityAction = nameEdit->addAction(yellowIcon, QLineEdit::LeadingPosition);
+ connect(nameEdit, &QLineEdit::textEdited, this, &ProfileSetupDialog::nameEdited);
+
+ checkStartTimer.setSingleShot(true);
+ connect(&checkStartTimer, &QTimer::timeout, this, &ProfileSetupDialog::startCheck);
+
+ setNameStatus(NameStatus::NotSet, QString());
+}
+
+ProfileSetupDialog::~ProfileSetupDialog()
+{
+ delete ui;
+}
+
+void ProfileSetupDialog::on_buttonBox_accepted()
+{
+ setupProfile(currentCheck);
+}
+
+void ProfileSetupDialog::on_buttonBox_rejected()
+{
+ reject();
+}
+
+void ProfileSetupDialog::setNameStatus(ProfileSetupDialog::NameStatus status, QString errorString = QString())
+{
+ nameStatus = status;
+ auto okButton = ui->buttonBox->button(QDialogButtonBox::Ok);
+ switch(nameStatus)
+ {
+ case NameStatus::Available: {
+ validityAction->setIcon(goodIcon);
+ okButton->setEnabled(true);
+ }
+ break;
+ case NameStatus::NotSet:
+ case NameStatus::Pending:
+ validityAction->setIcon(yellowIcon);
+ okButton->setEnabled(false);
+ break;
+ case NameStatus::Exists:
+ case NameStatus::Error:
+ validityAction->setIcon(badIcon);
+ okButton->setEnabled(false);
+ break;
+ }
+ if(!errorString.isEmpty()) {
+ ui->errorLabel->setText(errorString);
+ ui->errorLabel->setVisible(true);
+ }
+ else {
+ ui->errorLabel->setVisible(false);
+ }
+}
+
+void ProfileSetupDialog::nameEdited(const QString& name)
+{
+ if(!ui->nameEdit->hasAcceptableInput()) {
+ setNameStatus(NameStatus::NotSet, tr("Name is too short - must be between 3 and 16 characters long."));
+ return;
+ }
+ scheduleCheck(name);
+}
+
+void ProfileSetupDialog::scheduleCheck(const QString& name) {
+ queuedCheck = name;
+ setNameStatus(NameStatus::Pending);
+ checkStartTimer.start(1000);
+}
+
+void ProfileSetupDialog::startCheck() {
+ if(isChecking) {
+ return;
+ }
+ if(queuedCheck.isNull()) {
+ return;
+ }
+ checkName(queuedCheck);
+}
+
+
+void ProfileSetupDialog::checkName(const QString &name) {
+ if(isChecking) {
+ return;
+ }
+
+ currentCheck = name;
+ isChecking = true;
+
+ auto token = m_accountToSetup->accessToken();
+
+ auto url = QString("https://api.minecraftservices.com/minecraft/profile/name/%1/available").arg(name);
+ QNetworkRequest request = QNetworkRequest(url);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+ request.setRawHeader("Accept", "application/json");
+ request.setRawHeader("Authorization", QString("Bearer %1").arg(token).toUtf8());
+
+ AuthRequest *requestor = new AuthRequest(this);
+ connect(requestor, &AuthRequest::finished, this, &ProfileSetupDialog::checkFinished);
+ requestor->get(request);
+}
+
+void ProfileSetupDialog::checkFinished(
+ QNetworkReply::NetworkError error,
+ QByteArray data,
+ QList<QNetworkReply::RawHeaderPair> headers
+) {
+ if(error == QNetworkReply::NoError) {
+ auto doc = QJsonDocument::fromJson(data);
+ auto root = doc.object();
+ auto statusValue = root.value("status").toString("INVALID");
+ if(statusValue == "AVAILABLE") {
+ setNameStatus(NameStatus::Available);
+ }
+ else if (statusValue == "DUPLICATE") {
+ setNameStatus(NameStatus::Exists, tr("Minecraft profile with name %1 already exists.").arg(currentCheck));
+ }
+ else if (statusValue == "NOT_ALLOWED") {
+ setNameStatus(NameStatus::Exists, tr("The name %1 is not allowed.").arg(currentCheck));
+ }
+ else {
+ setNameStatus(NameStatus::Error, tr("Unhandled profile name status: %1").arg(statusValue));
+ }
+ }
+ else {
+ setNameStatus(NameStatus::Error, tr("Failed to check name availability."));
+ }
+ isChecking = false;
+}
+
+void ProfileSetupDialog::setupProfile(const QString &profileName) {
+ if(isWorking) {
+ return;
+ }
+
+ auto token = m_accountToSetup->accessToken();
+
+ auto url = QString("https://api.minecraftservices.com/minecraft/profile");
+ QNetworkRequest request = QNetworkRequest(url);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+ request.setRawHeader("Accept", "application/json");
+ request.setRawHeader("Authorization", QString("Bearer %1").arg(token).toUtf8());
+
+ QString payloadTemplate("{\"profileName\":\"%1\"}");
+ auto data = payloadTemplate.arg(profileName).toUtf8();
+
+ AuthRequest *requestor = new AuthRequest(this);
+ connect(requestor, &AuthRequest::finished, this, &ProfileSetupDialog::setupProfileFinished);
+ requestor->post(request, data);
+ isWorking = true;
+
+ auto button = ui->buttonBox->button(QDialogButtonBox::Cancel);
+ button->setEnabled(false);
+}
+
+namespace {
+
+struct MojangError{
+ static MojangError fromJSON(QByteArray data) {
+ MojangError out;
+ out.error = QString::fromUtf8(data);
+ auto doc = QJsonDocument::fromJson(data, &out.parseError);
+ auto object = doc.object();
+
+ out.fullyParsed = true;
+ out.fullyParsed &= Parsers::getString(object.value("path"), out.path);
+ out.fullyParsed &= Parsers::getString(object.value("error"), out.error);
+ out.fullyParsed &= Parsers::getString(object.value("errorMessage"), out.errorMessage);
+
+ return out;
+ }
+
+ QString rawError;
+ QJsonParseError parseError;
+ bool fullyParsed;
+
+ QString path;
+ QString error;
+ QString errorMessage;
+};
+
+}
+
+void ProfileSetupDialog::setupProfileFinished(
+ QNetworkReply::NetworkError error,
+ QByteArray data,
+ QList<QNetworkReply::RawHeaderPair> headers
+) {
+ isWorking = false;
+ if(error == QNetworkReply::NoError) {
+ /*
+ * data contains the profile in the response
+ * ... we could parse it and update the account, but let's just return back to the normal login flow instead...
+ */
+ accept();
+ }
+ else {
+ auto parsedError = MojangError::fromJSON(data);
+ ui->errorLabel->setVisible(true);
+ ui->errorLabel->setText(tr("The server returned the following error:") + "\n\n" + parsedError.errorMessage);
+ qDebug() << parsedError.rawError;
+ auto button = ui->buttonBox->button(QDialogButtonBox::Cancel);
+ button->setEnabled(true);
+ }
+}