Merge pull request #408 from jamierocks/atl-share-codes
This commit is contained in:
		@@ -1,6 +1,7 @@
 | 
			
		||||
// SPDX-License-Identifier: GPL-3.0-only
 | 
			
		||||
/*
 | 
			
		||||
 *  PolyMC - Minecraft Launcher
 | 
			
		||||
 *  Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
 | 
			
		||||
 *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
 | 
			
		||||
 *
 | 
			
		||||
 *  This program is free software: you can redistribute it and/or modify
 | 
			
		||||
@@ -139,6 +140,7 @@ public:
 | 
			
		||||
    QString LEGACY_FTB_CDN_BASE_URL = "https://dist.creeper.host/FTB2/";
 | 
			
		||||
 | 
			
		||||
    QString ATL_DOWNLOAD_SERVER_URL = "https://download.nodecdn.net/containers/atl/";
 | 
			
		||||
    QString ATL_API_BASE_URL = "https://api.atlauncher.com/v1/";
 | 
			
		||||
 | 
			
		||||
    QString TECHNIC_API_BASE_URL = "https://api.technicpack.net/";
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -557,6 +557,8 @@ set(ATLAUNCHER_SOURCES
 | 
			
		||||
    modplatform/atlauncher/ATLPackInstallTask.h
 | 
			
		||||
    modplatform/atlauncher/ATLPackManifest.cpp
 | 
			
		||||
    modplatform/atlauncher/ATLPackManifest.h
 | 
			
		||||
    modplatform/atlauncher/ATLShareCode.cpp
 | 
			
		||||
    modplatform/atlauncher/ATLShareCode.h
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
add_unit_test(Index
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										60
									
								
								launcher/modplatform/atlauncher/ATLShareCode.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								launcher/modplatform/atlauncher/ATLShareCode.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
			
		||||
// SPDX-License-Identifier: GPL-3.0-only
 | 
			
		||||
/*
 | 
			
		||||
 *  PolyMC - Minecraft Launcher
 | 
			
		||||
 *  Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 *  it under the terms of the GNU General Public License as published by
 | 
			
		||||
 *  the Free Software Foundation, version 3.
 | 
			
		||||
 *
 | 
			
		||||
 *  This program is distributed in the hope that it will be useful,
 | 
			
		||||
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 *  You should have received a copy of the GNU General Public License
 | 
			
		||||
 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "ATLShareCode.h"
 | 
			
		||||
 | 
			
		||||
#include "Json.h"
 | 
			
		||||
 | 
			
		||||
namespace ATLauncher {
 | 
			
		||||
 | 
			
		||||
static void loadShareCodeMod(ShareCodeMod& m, QJsonObject& obj)
 | 
			
		||||
{
 | 
			
		||||
    m.selected = Json::requireBoolean(obj, "selected");
 | 
			
		||||
    m.name = Json::requireString(obj, "name");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void loadShareCode(ShareCode& c, QJsonObject& obj)
 | 
			
		||||
{
 | 
			
		||||
    c.pack = Json::requireString(obj, "pack");
 | 
			
		||||
    c.version = Json::requireString(obj, "version");
 | 
			
		||||
 | 
			
		||||
    auto mods = Json::requireObject(obj, "mods");
 | 
			
		||||
    auto optional = Json::requireArray(mods, "optional");
 | 
			
		||||
    for (const auto modRaw : optional) {
 | 
			
		||||
        auto modObj = Json::requireObject(modRaw);
 | 
			
		||||
        ShareCodeMod mod;
 | 
			
		||||
        loadShareCodeMod(mod, modObj);
 | 
			
		||||
        c.mods.append(mod);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void loadShareCodeResponse(ShareCodeResponse& r, QJsonObject& obj)
 | 
			
		||||
{
 | 
			
		||||
    r.error = Json::requireBoolean(obj, "error");
 | 
			
		||||
    r.code = Json::requireInteger(obj, "code");
 | 
			
		||||
 | 
			
		||||
    if (obj.contains("message") && !obj.value("message").isNull())
 | 
			
		||||
        r.message = Json::requireString(obj, "message");
 | 
			
		||||
 | 
			
		||||
    if (!r.error) {
 | 
			
		||||
        auto dataRaw = Json::requireObject(obj, "data");
 | 
			
		||||
        loadShareCode(r.data, dataRaw);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										47
									
								
								launcher/modplatform/atlauncher/ATLShareCode.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								launcher/modplatform/atlauncher/ATLShareCode.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
// SPDX-License-Identifier: GPL-3.0-only
 | 
			
		||||
/*
 | 
			
		||||
 *  PolyMC - Minecraft Launcher
 | 
			
		||||
 *  Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 *  it under the terms of the GNU General Public License as published by
 | 
			
		||||
 *  the Free Software Foundation, version 3.
 | 
			
		||||
 *
 | 
			
		||||
 *  This program is distributed in the hope that it will be useful,
 | 
			
		||||
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 *  You should have received a copy of the GNU General Public License
 | 
			
		||||
 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <QString>
 | 
			
		||||
#include <QVector>
 | 
			
		||||
#include <QJsonObject>
 | 
			
		||||
 | 
			
		||||
namespace ATLauncher {
 | 
			
		||||
 | 
			
		||||
struct ShareCodeMod {
 | 
			
		||||
    bool selected;
 | 
			
		||||
    QString name;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ShareCode {
 | 
			
		||||
    QString pack;
 | 
			
		||||
    QString version;
 | 
			
		||||
    QVector<ShareCodeMod> mods;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ShareCodeResponse {
 | 
			
		||||
    bool error;
 | 
			
		||||
    int code;
 | 
			
		||||
    QString message;
 | 
			
		||||
    ShareCode data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void loadShareCodeResponse(ShareCodeResponse& r, QJsonObject& obj);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,23 @@
 | 
			
		||||
// SPDX-License-Identifier: GPL-3.0-only
 | 
			
		||||
/*
 | 
			
		||||
 *  PolyMC - Minecraft Launcher
 | 
			
		||||
 *  Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 *  it under the terms of the GNU General Public License as published by
 | 
			
		||||
 *  the Free Software Foundation, version 3.
 | 
			
		||||
 *
 | 
			
		||||
 *  This program is distributed in the hope that it will be useful,
 | 
			
		||||
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 *  You should have received a copy of the GNU General Public License
 | 
			
		||||
 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 * This file incorporates work covered by the following copyright and
 | 
			
		||||
 * permission notice:
 | 
			
		||||
 *
 | 
			
		||||
 *      Copyright 2021 Jamie Mansfield <jmansfield@cadixdev.org>
 | 
			
		||||
 *
 | 
			
		||||
 *      Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
@@ -17,14 +36,21 @@
 | 
			
		||||
#include "AtlOptionalModDialog.h"
 | 
			
		||||
#include "ui_AtlOptionalModDialog.h"
 | 
			
		||||
 | 
			
		||||
#include <QInputDialog>
 | 
			
		||||
#include <QMessageBox>
 | 
			
		||||
#include "BuildConfig.h"
 | 
			
		||||
#include "Json.h"
 | 
			
		||||
#include "modplatform/atlauncher/ATLShareCode.h"
 | 
			
		||||
#include "Application.h"
 | 
			
		||||
 | 
			
		||||
AtlOptionalModListModel::AtlOptionalModListModel(QWidget *parent, QVector<ATLauncher::VersionMod> mods)
 | 
			
		||||
    : QAbstractListModel(parent), m_mods(mods) {
 | 
			
		||||
 | 
			
		||||
    // fill mod index
 | 
			
		||||
    for (int i = 0; i < m_mods.size(); i++) {
 | 
			
		||||
        auto mod = m_mods.at(i);
 | 
			
		||||
        m_index[mod.name] = i;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // set initial state
 | 
			
		||||
    for (int i = 0; i < m_mods.size(); i++) {
 | 
			
		||||
        auto mod = m_mods.at(i);
 | 
			
		||||
@@ -77,7 +103,7 @@ QVariant AtlOptionalModListModel::data(const QModelIndex &index, int role) const
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return QVariant();
 | 
			
		||||
    return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AtlOptionalModListModel::setData(const QModelIndex &index, const QVariant &value, int role) {
 | 
			
		||||
@@ -104,7 +130,7 @@ QVariant AtlOptionalModListModel::headerData(int section, Qt::Orientation orient
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return QVariant();
 | 
			
		||||
    return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Qt::ItemFlags AtlOptionalModListModel::flags(const QModelIndex &index) const {
 | 
			
		||||
@@ -115,6 +141,69 @@ Qt::ItemFlags AtlOptionalModListModel::flags(const QModelIndex &index) const {
 | 
			
		||||
    return flags;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AtlOptionalModListModel::useShareCode(const QString& code) {
 | 
			
		||||
    m_jobPtr.reset(new NetJob("Atl::Request", APPLICATION->network()));
 | 
			
		||||
    auto url = QString(BuildConfig.ATL_API_BASE_URL + "share-codes/" + code);
 | 
			
		||||
    m_jobPtr->addNetAction(Net::Download::makeByteArray(QUrl(url), &m_response));
 | 
			
		||||
 | 
			
		||||
    connect(m_jobPtr.get(), &NetJob::succeeded,
 | 
			
		||||
            this, &AtlOptionalModListModel::shareCodeSuccess);
 | 
			
		||||
    connect(m_jobPtr.get(), &NetJob::failed,
 | 
			
		||||
            this, &AtlOptionalModListModel::shareCodeFailure);
 | 
			
		||||
 | 
			
		||||
    m_jobPtr->start();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AtlOptionalModListModel::shareCodeSuccess() {
 | 
			
		||||
    m_jobPtr.reset();
 | 
			
		||||
 | 
			
		||||
    QJsonParseError parse_error {};
 | 
			
		||||
    auto doc = QJsonDocument::fromJson(m_response, &parse_error);
 | 
			
		||||
    if (parse_error.error != QJsonParseError::NoError) {
 | 
			
		||||
        qWarning() << "Error while parsing JSON response from ATL at " << parse_error.offset << " reason: " << parse_error.errorString();
 | 
			
		||||
        qWarning() << m_response;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    auto obj = doc.object();
 | 
			
		||||
 | 
			
		||||
    ATLauncher::ShareCodeResponse response;
 | 
			
		||||
    try {
 | 
			
		||||
        ATLauncher::loadShareCodeResponse(response, obj);
 | 
			
		||||
    }
 | 
			
		||||
    catch (const JSONValidationError& e) {
 | 
			
		||||
        qDebug() << QString::fromUtf8(m_response);
 | 
			
		||||
        qWarning() << "Error while reading response from ATLauncher: " << e.cause();
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (response.error) {
 | 
			
		||||
        // fixme: plumb in an error message
 | 
			
		||||
        qWarning() << "ATLauncher API Response Error" << response.message;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // FIXME: verify pack and version, error if not matching.
 | 
			
		||||
 | 
			
		||||
    // Clear the current selection
 | 
			
		||||
    for (const auto& mod : m_mods) {
 | 
			
		||||
        m_selection[mod.name] = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Make the selections, as per the share code.
 | 
			
		||||
    for (const auto& mod : response.data.mods) {
 | 
			
		||||
        m_selection[mod.name] = mod.selected;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    emit dataChanged(AtlOptionalModListModel::index(0, EnabledColumn),
 | 
			
		||||
                     AtlOptionalModListModel::index(m_mods.size() - 1, EnabledColumn));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AtlOptionalModListModel::shareCodeFailure(const QString& reason) {
 | 
			
		||||
    m_jobPtr.reset();
 | 
			
		||||
 | 
			
		||||
    // fixme: plumb in an error message
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AtlOptionalModListModel::selectRecommended() {
 | 
			
		||||
    for (const auto& mod : m_mods) {
 | 
			
		||||
        m_selection[mod.name] = mod.recommended;
 | 
			
		||||
@@ -212,14 +301,43 @@ AtlOptionalModDialog::AtlOptionalModDialog(QWidget *parent, QVector<ATLauncher::
 | 
			
		||||
    ui->treeView->header()->setSectionResizeMode(
 | 
			
		||||
            AtlOptionalModListModel::DescriptionColumn, QHeaderView::Stretch);
 | 
			
		||||
 | 
			
		||||
    connect(ui->selectRecommendedButton, &QPushButton::pressed,
 | 
			
		||||
    connect(ui->shareCodeButton, &QPushButton::clicked,
 | 
			
		||||
            this, &AtlOptionalModDialog::useShareCode);
 | 
			
		||||
    connect(ui->selectRecommendedButton, &QPushButton::clicked,
 | 
			
		||||
            listModel, &AtlOptionalModListModel::selectRecommended);
 | 
			
		||||
    connect(ui->clearAllButton, &QPushButton::pressed,
 | 
			
		||||
    connect(ui->clearAllButton, &QPushButton::clicked,
 | 
			
		||||
            listModel, &AtlOptionalModListModel::clearAll);
 | 
			
		||||
    connect(ui->installButton, &QPushButton::pressed,
 | 
			
		||||
    connect(ui->installButton, &QPushButton::clicked,
 | 
			
		||||
            this, &QDialog::close);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AtlOptionalModDialog::~AtlOptionalModDialog() {
 | 
			
		||||
    delete ui;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AtlOptionalModDialog::useShareCode() {
 | 
			
		||||
    bool ok;
 | 
			
		||||
    auto shareCode = QInputDialog::getText(
 | 
			
		||||
            this,
 | 
			
		||||
            tr("Select a share code"),
 | 
			
		||||
            tr("Share code:"),
 | 
			
		||||
            QLineEdit::Normal,
 | 
			
		||||
            "",
 | 
			
		||||
            &ok
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
    if (!ok) {
 | 
			
		||||
        // If the user cancels the dialog, we don't need to show any error dialogs.
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (shareCode.isEmpty()) {
 | 
			
		||||
        QMessageBox box;
 | 
			
		||||
        box.setIcon(QMessageBox::Warning);
 | 
			
		||||
        box.setText(tr("No share code specified!"));
 | 
			
		||||
        box.exec();
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    listModel->useShareCode(shareCode);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,23 @@
 | 
			
		||||
// SPDX-License-Identifier: GPL-3.0-only
 | 
			
		||||
/*
 | 
			
		||||
 *  PolyMC - Minecraft Launcher
 | 
			
		||||
 *  Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
 | 
			
		||||
 *
 | 
			
		||||
 *  This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 *  it under the terms of the GNU General Public License as published by
 | 
			
		||||
 *  the Free Software Foundation, version 3.
 | 
			
		||||
 *
 | 
			
		||||
 *  This program is distributed in the hope that it will be useful,
 | 
			
		||||
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 *  You should have received a copy of the GNU General Public License
 | 
			
		||||
 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 * This file incorporates work covered by the following copyright and
 | 
			
		||||
 * permission notice:
 | 
			
		||||
 *
 | 
			
		||||
 *      Copyright 2021 Jamie Mansfield <jmansfield@cadixdev.org>
 | 
			
		||||
 *
 | 
			
		||||
 *      Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
@@ -20,6 +39,7 @@
 | 
			
		||||
#include <QAbstractListModel>
 | 
			
		||||
 | 
			
		||||
#include "modplatform/atlauncher/ATLPackIndex.h"
 | 
			
		||||
#include "net/NetJob.h"
 | 
			
		||||
 | 
			
		||||
namespace Ui {
 | 
			
		||||
class AtlOptionalModDialog;
 | 
			
		||||
@@ -49,7 +69,12 @@ public:
 | 
			
		||||
 | 
			
		||||
    Qt::ItemFlags flags(const QModelIndex &index) const override;
 | 
			
		||||
 | 
			
		||||
    void useShareCode(const QString& code);
 | 
			
		||||
 | 
			
		||||
public slots:
 | 
			
		||||
    void shareCodeSuccess();
 | 
			
		||||
    void shareCodeFailure(const QString& reason);
 | 
			
		||||
 | 
			
		||||
    void selectRecommended();
 | 
			
		||||
    void clearAll();
 | 
			
		||||
 | 
			
		||||
@@ -58,6 +83,9 @@ private:
 | 
			
		||||
    void setMod(ATLauncher::VersionMod mod, int index, bool enable, bool shouldEmit = true);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    NetJob::Ptr m_jobPtr;
 | 
			
		||||
    QByteArray m_response;
 | 
			
		||||
 | 
			
		||||
    QVector<ATLauncher::VersionMod> m_mods;
 | 
			
		||||
    QMap<QString, bool> m_selection;
 | 
			
		||||
    QMap<QString, int> m_index;
 | 
			
		||||
@@ -75,6 +103,8 @@ public:
 | 
			
		||||
        return listModel->getResult();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void useShareCode();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Ui::AtlOptionalModDialog *ui;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,16 @@
 | 
			
		||||
     </property>
 | 
			
		||||
    </widget>
 | 
			
		||||
   </item>
 | 
			
		||||
   <item row="1" column="0">
 | 
			
		||||
    <widget class="QPushButton" name="shareCodeButton">
 | 
			
		||||
     <property name="enabled">
 | 
			
		||||
      <bool>true</bool>
 | 
			
		||||
     </property>
 | 
			
		||||
     <property name="text">
 | 
			
		||||
      <string>Use Share Code</string>
 | 
			
		||||
     </property>
 | 
			
		||||
    </widget>
 | 
			
		||||
   </item>
 | 
			
		||||
   <item row="1" column="1">
 | 
			
		||||
    <widget class="QPushButton" name="selectRecommendedButton">
 | 
			
		||||
     <property name="text">
 | 
			
		||||
@@ -31,16 +41,6 @@
 | 
			
		||||
     </property>
 | 
			
		||||
    </widget>
 | 
			
		||||
   </item>
 | 
			
		||||
   <item row="1" column="0">
 | 
			
		||||
    <widget class="QPushButton" name="shareCodeButton">
 | 
			
		||||
     <property name="enabled">
 | 
			
		||||
      <bool>false</bool>
 | 
			
		||||
     </property>
 | 
			
		||||
     <property name="text">
 | 
			
		||||
      <string>Use Share Code</string>
 | 
			
		||||
     </property>
 | 
			
		||||
    </widget>
 | 
			
		||||
   </item>
 | 
			
		||||
   <item row="1" column="2">
 | 
			
		||||
    <widget class="QPushButton" name="clearAllButton">
 | 
			
		||||
     <property name="text">
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user