Add signup to qt launcher, and cleanup

This commit is contained in:
Ryan Huffman 2019-09-30 10:42:00 -07:00
parent 6db88dae3c
commit e81deff4e9
15 changed files with 575 additions and 153 deletions

View file

@ -127,8 +127,14 @@ set(src_files
src/LauncherState.cpp
src/LauncherWindow.h
src/LauncherWindow.cpp
src/PathUtils.cpp
src/LoginRequest.h
src/LoginRequest.cpp
src/SignupRequest.h
src/SignupRequest.cpp
src/UserSettingsRequest.h
src/UserSettingsRequest.cpp
src/PathUtils.h
src/PathUtils.cpp
src/Unzipper.h
src/Unzipper.cpp
src/Helper.h
@ -159,7 +165,7 @@ set(TARGET_NAME ${PROJECT_NAME})
set_packaging_parameters()
if (WIN32)
add_executable(${PROJECT_NAME} ${src_files} build/resources.qrc)
add_executable(${PROJECT_NAME} ${src_files} ${CMAKE_CURRENT_BINARY_DIR}/resources.qrc)
elseif (APPLE)
set_target_properties(${this_target} PROPERTIES
MACOSX_BUNDLE_INFO_PLIST MacOSXBundleInfo.plist.in)

View file

@ -47,7 +47,7 @@ Item {
font.family: "Graphik"
font.pixelSize: 14
color: "#C4C4C4"
text: "Use the email address that you regisetered with."
text: "Use the email address that you regisetered with. " + LauncherState.lastSignupError
anchors {
left: root.left
leftMargin: root.marginLeft
@ -57,7 +57,7 @@ Item {
}
HFTextField {
id: organization
id: email
width: 430
height: 50
font.family: "Graphik"
@ -83,7 +83,7 @@ Item {
color: "#7e8c81"
seperatorColor: Qt.rgba(1, 1, 1, 0.3)
anchors {
top: organization.bottom
top: email.bottom
left: root.left
leftMargin: root.marginLeft
topMargin: 18
@ -157,7 +157,7 @@ Item {
topMargin: 21
}
onClicked: LauncherState.login(username.text, passwordField.text)
onClicked: LauncherState.signup(email.text, username.text, passwordField.text, displayName.text)
}
@ -181,7 +181,7 @@ Item {
onClicked: {
console.log("clicked");
root.parent.source = PathUtils.resourcePath("qml/Login.qml");
LauncherState.gotoLogin();
}
}
}

View file

@ -109,7 +109,6 @@ Item {
placeholderText: "Display name"
color: "#7E8C81"
seperatorColor: Qt.rgba(1, 1, 1, 0.3)
echoMode: TextInput.Password
anchors {
top: displayText.bottom
horizontalCenter: instruction.horizontalCenter
@ -132,7 +131,7 @@ Item {
topMargin: 25
}
onClicked: LauncherState.login(username.text, password.text)
onClicked: LauncherState.login(username.text, password.text, displayName.text)
}
Text {
@ -155,7 +154,7 @@ Item {
onClicked: {
console.log("clicked");
root.parent.source = PathUtils.resourcePath("qml/Login.qml");
LauncherState.gotoSignup();
}
}
}

View file

@ -25,3 +25,47 @@ void swapLaunchers(const QString& oldLauncherPath, const QString& newLauncherPat
exit(0);
}
}
QString getHTTPUserAgent() {
#if defined(Q_OS_WIN)
return "HQLauncher/fixme (Windows)";
#elif defined(Q_OS_MACOS)
return "HQLauncher/fixme (MacOS)";
#else
#error Unsupported platform
#endif
}
const QString& getInterfaceSharedMemoryName() {
static const QString applicationName = "High Fidelity Interface - " + qgetenv("USERNAME");
return applicationName;
}
//#ifdef Q_OS_WIN
//#include <Windows.h>
//#include <tlhelp32.h>
//#include <wincrypt.h>
//#include <tlhelp32.h>
//#include <strsafe.h>
//#include <winhttp.h>
//
//bool isProcessRunning(const wchar_t *processName, int& processID) {
// bool exists = false;
// PROCESSENTRY32 entry;
// entry.dwSize = sizeof(PROCESSENTRY32);
//
// HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
//
// if (Process32First(snapshot, &entry)) {
// while (Process32Next(snapshot, &entry)) {
// if (!_wcsicmp(entry.szExeFile, processName)) {
// exists = true;
// processID = entry.th32ProcessID;
// break;
// }
// }
// }
// CloseHandle(snapshot);
// return exists;
//}
//#endif

View file

@ -1,6 +1,14 @@
#include <QString>
#include <string>
//#define USE_STAGING
#ifdef USE_STAGING
const QString METAVERSE_API_DOMAIN{ "https://staging.highfidelity.com" };
#else
const QString METAVERSE_API_DOMAIN{ "https://metaverse.highfidelity.com" };
#endif
void launchClient(const QString& clientPath, const QString& homePath, const QString& defaultScriptOverride,
const QString& displayName, const QString& contentCachePath, QString loginResponseToken = QString());
@ -11,3 +19,11 @@ void swapLaunchers(const QString& oldLauncherPath = QString(), const QString& ne
#ifdef Q_OS_MAC
bool replaceDirectory(const QString& orginalDirectory, const QString& newDirectory);
#endif
QString getHTTPUserAgent();
const QString& getInterfaceSharedMemoryName();
//#ifdef Q_OS_WIN
//bool isProcessRunning(const wchar_t *processName, int& processID) {
//#endif

View file

@ -9,7 +9,7 @@ void launchClient(const QString& clientPath, const QString& homePath, const QStr
// TODO Fix parameters
QString params = "--url \"" + homePath + "\""
+ " --setBookmark \"hqhome=" + homePath + "\""
+ " --defaultScriptsOverride \"" + defaultScriptsPath + "\""
+ " --defaultScriptsOverride \"file:///" + defaultScriptsPath + "\""
+ " --displayName \"" + displayName + "\""
+ " --cache \"" + contentCachePath + "\"";

View file

@ -30,8 +30,6 @@
#include <qregularexpression.h>
const QString METAVERSE_API_URL{ "https://metaverse.highfidelity.com" };
const QByteArray ACCESS_TOKEN_AUTHORIZATION_HEADER = "Authorization";
QString LauncherState::getContentCachePath() const {
return _launcherDirectory.filePath("cache");
@ -70,7 +68,7 @@ bool LatestBuilds::getBuild(QString tag, Build* outBuild) {
}
static const std::array<QString, LauncherState::UIState::UI_STATE_NUM> QML_FILE_FOR_UI_STATE =
{ { "SplashScreen.qml", "qml/HFBase/CreateAccountBase.qml", "DisplayName.qml",
{ { "SplashScreen.qml", "qml/HFBase/CreateAccountBase.qml", "qml/HFBase/LoginBase.qml", "DisplayName.qml",
"qml/Download.qml", "qml/DownloadFinished.qml", "qml/HFBase/Error.qml" } };
void LauncherState::ASSERT_STATE(LauncherState::ApplicationState state) {
@ -82,7 +80,7 @@ void LauncherState::ASSERT_STATE(LauncherState::ApplicationState state) {
}
}
void LauncherState::ASSERT_STATE(std::vector<LauncherState::ApplicationState> states) {
void LauncherState::ASSERT_STATE(const std::vector<LauncherState::ApplicationState>& states) {
for (auto state : states) {
if (_applicationState == state) {
return;
@ -120,6 +118,9 @@ LauncherState::UIState LauncherState::getUIState() const {
case ApplicationState::WaitingForLogin:
case ApplicationState::RequestingLogin:
return LOGIN_SCREEN;
case ApplicationState::WaitingForSignup:
case ApplicationState::RequestingSignup:
return SIGNUP_SCREEN;
case ApplicationState::DownloadingClient:
case ApplicationState::InstallingClient:
case ApplicationState::DownloadingContentCache:
@ -240,33 +241,11 @@ void LauncherState::getCurrentClientVersion() {
QProcess client;
QEventLoop loop;
//connect(&client, &QProcess::errorOccurred, &loop, &QEventLoop::exit);
connect(&client, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), &loop, &QEventLoop::exit);
/*
connect(&client, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), [&]() {
qDebug() << "Finished";
});
connect(&client, &QProcess::errorOccurred, [&](QProcess::ProcessError err) {
qDebug() << "Error occurred" << err << client.error();
});
connect(&client, &QProcess::started, [&]() {
qDebug() << "Started";
});
connect(&client, &QProcess::stateChanged, [&]() {
qDebug() << "State changed " << client.state();
});
*/
connect(&client, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), &loop, &QEventLoop::exit, Qt::QueuedConnection);
connect(&client, &QProcess::errorOccurred, &loop, &QEventLoop::exit, Qt::QueuedConnection);
//qDebug() << "Starting client";
client.start(getClientExecutablePath(), { "--version" });
//qDebug() << "Started" << client.error();
if (client.state() != QProcess::NotRunning) {
//qDebug() << "Starting loop";
loop.exec();
} else {
qDebug() << "Not waiting for client, there was an error starting it: " << client.error();
}
loop.exec();
// TODO Handle errors
auto output = client.readAllStandardOutput();
@ -282,132 +261,140 @@ void LauncherState::getCurrentClientVersion() {
}
qDebug() << "Current client version is: " << _currentClientVersion;
setApplicationState(ApplicationState::WaitingForLogin);
setApplicationState(ApplicationState::WaitingForSignup);
}
QString getUserAgent() {
#if defined(Q_OS_WIN)
return "HQLauncher/fixme (Windows)";
#elif defined(Q_OS_MACOS)
return "HQLauncher/fixme (MacOS)";
#else
#error Unsupported platform
#endif
void LauncherState::gotoSignup() {
if (_applicationState == ApplicationState::WaitingForLogin) {
setApplicationState(ApplicationState::WaitingForSignup);
} else {
qDebug() << "Error, can't switch to signup page, current state is: " << _applicationState;
}
}
void LauncherState::login(QString username, QString password) {
void LauncherState::gotoLogin() {
if (_applicationState == ApplicationState::WaitingForSignup) {
setApplicationState(ApplicationState::WaitingForLogin);
} else {
qDebug() << "Error, can't switch to signup page, current state is: " << _applicationState;
}
}
void LauncherState::signup(QString email, QString username, QString password, QString displayName) {
ASSERT_STATE(ApplicationState::WaitingForSignup);
_username = username;
_password = password;
setApplicationState(ApplicationState::RequestingSignup);
auto signupRequest = new SignupRequest();
_displayName = displayName;
{
_lastSignupError = SignupRequest::Error::None;
emit lastSignupErrorChanged();
}
QObject::connect(signupRequest, &SignupRequest::finished, this, [this, signupRequest] {
signupRequest->deleteLater();
_lastSignupError = signupRequest->getError();
emit lastSignupErrorChanged();
if (_lastSignupError != SignupRequest::Error::None) {
setApplicationStateError("Failed to sign up");
return;
}
setApplicationState(ApplicationState::RequestingLoginAfterSignup);
// After successfully signing up, attempt to login
auto loginRequest = new LoginRequest();
connect(loginRequest, &LoginRequest::finished, this, [this, loginRequest]() {
ASSERT_STATE(ApplicationState::RequestingLoginAfterSignup);
loginRequest->deleteLater();
auto err = loginRequest->getError();
if (err != LoginRequest::Error::None) {
setApplicationStateError("Failed to login");
return;
}
_loginResponse = loginRequest->getToken();
_loginTokenResponse = loginRequest->getRawToken();
requestSettings();
});
setApplicationState(ApplicationState::RequestingLoginAfterSignup);
loginRequest->send(_networkAccessManager, _username, _password);
});
signupRequest->send(_networkAccessManager, email, username, password);
}
void LauncherState::login(QString username, QString password, QString displayName) {
ASSERT_STATE(ApplicationState::WaitingForLogin);
setApplicationState(ApplicationState::RequestingLogin);
_displayName = displayName;
qDebug() << "Got login: " << username << password;
auto request = new QNetworkRequest(QUrl(METAVERSE_API_URL + "/oauth/token"));
auto request = new LoginRequest();
request->setHeader(QNetworkRequest::UserAgentHeader, getUserAgent());
request->setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
QUrlQuery query;
query.addQueryItem("grant_type", "password");
query.addQueryItem("username", username);
query.addQueryItem("password", password);
query.addQueryItem("scope", "owner");
connect(request, &LoginRequest::finished, this, [this, request]() {
ASSERT_STATE(ApplicationState::RequestingLogin);
auto reply = _networkAccessManager.post(*request, query.toString().toUtf8());
QObject::connect(reply, &QNetworkReply::finished, this, &LauncherState::receivedLoginReply);
}
request->deleteLater();
Q_INVOKABLE void LauncherState::receivedLoginReply() {
ASSERT_STATE(ApplicationState::RequestingLogin);
auto err = request->getError();
if (err != LoginRequest::Error::None) {
setApplicationStateError("Failed to login");
return;
}
// TODO Check for errors
auto reply = static_cast<QNetworkReply*>(sender());
_loginResponse = request->getToken();
_loginTokenResponse = request->getRawToken();
if (reply->error()) {
setApplicationState(ApplicationState::UnexpectedError);
return;
}
requestSettings();
});
auto data = reply->readAll();
QJsonParseError parseError;
auto doc = QJsonDocument::fromJson(data, &parseError);
auto root = doc.object();
if (!root.contains("access_token")
|| !root.contains("token_type")
|| !root.contains("expires_in")
|| !root.contains("refresh_token")
|| !root.contains("scope")
|| !root.contains("created_at")) {
setApplicationState(ApplicationState::UnexpectedError);
return;
}
_loginResponse.accessToken = root["access_token"].toString();
_loginResponse.refreshToken = root["refresh_token"].toString();
_loginResponse.tokenType = root["token_type"].toString();
qDebug() << "Got response for login: " << data;
_loginTokenResponse = data;
requestSettings();
request->send(_networkAccessManager, username, password);
}
void LauncherState::requestSettings() {
// TODO Request settings if already logged in
qDebug() << "Requesting settings";
QUrl lockerURL = METAVERSE_API_URL;
lockerURL.setPath("/api/v1/user/locker");
auto request = new UserSettingsRequest();
auto lockerRequest = new QNetworkRequest(lockerURL);
lockerRequest->setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
lockerRequest->setHeader(QNetworkRequest::UserAgentHeader, getUserAgent());
lockerRequest->setRawHeader(ACCESS_TOKEN_AUTHORIZATION_HEADER, QString("Bearer %1").arg(_loginResponse.accessToken).toUtf8());
QNetworkReply* lockerReply = _networkAccessManager.get(*lockerRequest);
connect(lockerReply, &QNetworkReply::finished, this, &LauncherState::receivedSettingsReply);
}
void LauncherState::receivedSettingsReply() {
auto reply = static_cast<QNetworkReply*>(sender());
qDebug() << "Got reply: " << reply->error();
if (reply->error()) {
setApplicationState(ApplicationState::UnexpectedError);
return;
}
auto data = reply->readAll();
qDebug() << "Settings: " << data;
QJsonParseError parseError;
auto doc = QJsonDocument::fromJson(data, &parseError);
if (parseError.error != QJsonParseError::NoError) {
qDebug() << "Error parsing settings";
setApplicationStateError("Error retreiving settings");
return;
}
auto root = doc.object();
if (root["status"] != "success") {
qDebug() << "Status is not \"success\"";
setApplicationStateError("Error retreiving settings");
return;
}
_homeLocation = "hifi://hq";
if (root["data"].toObject().contains("home_location")) {
auto homeLocation = root["data"].toObject()["home_location"];
if (homeLocation.isString()) {
_homeLocation = homeLocation.toString();
connect(request, &UserSettingsRequest::finished, this, [this, request]() {
auto userSettings = request->getUserSettings();
if (userSettings.homeLocation.isEmpty()) {
_homeLocation = "hifi://hq";
_contentCacheURL = "";
} else {
_homeLocation = userSettings.homeLocation;
auto host = QUrl(_homeLocation).host();
_contentCacheURL = "http://orgs.highfidelity.com/host-content-cache/" + host + ".zip";
qDebug() << "Home location is: " << _homeLocation;
qDebug() << "Content cache url is: " << _contentCacheURL;
}
}
//qDebug() << "Home:" << _homeLocation << QUrl(_homeLocation).host();
qDebug() << "Home location is: " << _homeLocation;
qDebug() << "Content cache url is: " << _contentCacheURL;
downloadClient();
downloadClient();
});
request->send(_networkAccessManager, _loginResponse);
}
void LauncherState::downloadClient() {
@ -683,10 +670,9 @@ void LauncherState::launchClient() {
defaultScriptsPath = installDirectory.filePath("interface.app/Contents/Resources/scripts/simplifiedUIBootstrapper.js");
#endif
QString displayName = "fixMe";
QString contentCachePath = _launcherDirectory.filePath("cache");
::launchClient(clientPath, _homeLocation, QDir::toNativeSeparators(defaultScriptsPath), displayName, contentCachePath, _loginTokenResponse);
::launchClient(clientPath, _homeLocation, defaultScriptsPath, _displayName, contentCachePath, _loginTokenResponse);
}
void LauncherState::setApplicationStateError(QString errorMessage) {

View file

@ -7,6 +7,10 @@
#include <QNetworkAccessManager>
#include <QFile>
#include "LoginRequest.h"
#include "SignupRequest.h"
#include "UserSettingsRequest.h"
struct Build {
QString tag;
int latestVersion;
@ -22,18 +26,13 @@ struct LatestBuilds {
Build launcherBuild;
};
struct LoginResponse {
QString accessToken;
QString tokenType;
QString refreshToken;
};
class LauncherState : public QObject {
Q_OBJECT
Q_PROPERTY(UIState uiState READ getUIState NOTIFY uiStateChanged);
Q_PROPERTY(ApplicationState applicationState READ getApplicationState NOTIFY applicationStateChanged);
Q_PROPERTY(float downloadProgress READ getDownloadProgress NOTIFY downloadProgressChanged);
Q_PROPERTY(SignupRequest::Error lastSignupError MEMBER _lastSignupError NOTIFY lastSignupErrorChanged);
public:
LauncherState();
@ -41,6 +40,7 @@ public:
enum UIState {
SPLASH_SCREEN = 0,
SIGNUP_SCREEN,
LOGIN_SCREEN,
DISPLAY_NAME_SCREEN,
DOWNLOAD_SCREEN,
@ -60,6 +60,10 @@ public:
WaitingForLogin,
RequestingLogin,
WaitingForSignup,
RequestingSignup,
RequestingLoginAfterSignup,
DownloadingClient,
DownloadingLauncher,
DownloadingContentCache,
@ -85,7 +89,7 @@ public:
Q_INVOKABLE QString getCurrentUISource() const;
void ASSERT_STATE(LauncherState::ApplicationState state);
void ASSERT_STATE(std::vector<LauncherState::ApplicationState> states);
void ASSERT_STATE(const std::vector<LauncherState::ApplicationState>& states);
static void declareQML();
@ -98,17 +102,21 @@ public:
void setApplicationState(ApplicationState state);
ApplicationState getApplicationState() const;
Q_INVOKABLE void gotoSignup();
Q_INVOKABLE void gotoLogin();
// Request builds
void requestBuilds();
Q_INVOKABLE void receivedBuildsReply();
// Signup
Q_INVOKABLE void signup(QString email, QString username, QString password, QString displayName);
// Login
Q_INVOKABLE void login(QString username, QString password);
Q_INVOKABLE void receivedLoginReply();
Q_INVOKABLE void login(QString username, QString password, QString displayName);
// Request Settings
void requestSettings();
Q_INVOKABLE void receivedSettingsReply();
// Launcher
void downloadLauncher();
@ -132,6 +140,7 @@ signals:
void uiStateChanged();
void applicationStateChanged();
void downloadProgressChanged();
void lastSignupErrorChanged();
private slots:
void clientDownloadComplete();
@ -154,8 +163,10 @@ private:
// Application State
ApplicationState _applicationState { ApplicationState::Init };
LoginResponse _loginResponse;
LoginToken _loginResponse;
LastLoginError _lastLoginError { NONE };
SignupRequest::Error _lastSignupError{ SignupRequest::Error::None };
QString _displayName;
QString _applicationErrorMessage;
QString _currentClientVersion;
QString _buildTag { QString::null };
@ -166,5 +177,8 @@ private:
QFile _launcherZipFile;
QFile _contentZipFile;
QString _username;
QString _password;
float _downloadProgress { 0 };
};

View file

@ -0,0 +1,73 @@
#include "LoginRequest.h"
#include "Helper.h"
#include <QUrlQuery>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
void LoginRequest::send(QNetworkAccessManager& nam, QString username, QString password) {
QNetworkRequest request(QUrl(METAVERSE_API_DOMAIN + "/oauth/token"));
request.setHeader(QNetworkRequest::UserAgentHeader, getHTTPUserAgent());
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
QUrlQuery query;
query.addQueryItem("grant_type", "password");
query.addQueryItem("username", username);
query.addQueryItem("password", password);
query.addQueryItem("scope", "owner");
auto reply = nam.post(request, query.toString().toUtf8());
QObject::connect(reply, &QNetworkReply::finished, this, &LoginRequest::receivedResponse);
}
void LoginRequest::receivedResponse() {
_state = State::Finished;
auto reply = static_cast<QNetworkReply*>(sender());
if (reply->error()) {
qDebug() << "Error logging in: " << reply->readAll();
_error = Error::Unknown;
emit finished();
//setApplicationState(ApplicationState::UnexpectedError);
return;
}
auto data = reply->readAll();
QJsonParseError parseError;
auto doc = QJsonDocument::fromJson(data, &parseError);
if (parseError.error != QJsonParseError::NoError) {
qDebug() << "Error parsing response for login" << data;
_error = Error::BadResponse;
emit finished();
//setApplicationStateError("Failed to login");
return;
}
auto root = doc.object();
if (!root.contains("access_token")
|| !root.contains("token_type")
|| !root.contains("expires_in")
|| !root.contains("refresh_token")
|| !root.contains("scope")
|| !root.contains("created_at")) {
_error = Error::BadUsernameOrPassword;
emit finished();
return;
}
_token.accessToken = root["access_token"].toString();
_token.refreshToken = root["refresh_token"].toString();
_token.tokenType = root["token_type"].toString();
qDebug() << "Got response for login: " << data;
_rawLoginToken = data;
emit finished();
}

View file

@ -0,0 +1,49 @@
#pragma once
#include <QObject>
#include <QNetworkAccessManager>
struct LoginToken {
QString accessToken;
QString tokenType;
QString refreshToken;
};
class LoginRequest : public QObject {
Q_OBJECT
public:
enum class State {
Unsent,
Sending,
Finished
};
enum class Error {
None = 0,
Unknown,
BadResponse,
BadUsernameOrPassword
};
Q_ENUM(Error)
void send(QNetworkAccessManager& nam, QString username, QString password);
Error getError() const { return _error; }
// The token is only valid if the request has finished without error
QString getRawToken() const { return _rawLoginToken; }
LoginToken getToken() const { return _token; }
signals:
void finished();
private slots:
void receivedResponse();
private:
State _state { State::Unsent };
Error _error { Error::None };
QString _rawLoginToken;
LoginToken _token;
};

View file

@ -0,0 +1,79 @@
#include "SignupRequest.h"
#include "Helper.h"
#include <QUrlQuery>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
void SignupRequest::send(QNetworkAccessManager& nam, QString email, QString username, QString password) {
if (_state != State::Unsent) {
qDebug() << "Error: Trying to send signuprequest, but not unsent";
return;
}
_state = State::Sending;
QUrl signupURL { METAVERSE_API_DOMAIN };
signupURL.setPath("/api/v1/user/channel_user");
QNetworkRequest request(signupURL);
request.setHeader(QNetworkRequest::UserAgentHeader, getHTTPUserAgent());
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
QUrlQuery query;
query.addQueryItem("email", email);
query.addQueryItem("username", username);
query.addQueryItem("password", password);
auto reply = nam.post(request, query.toString().toUtf8());
QObject::connect(reply, &QNetworkReply::finished, this, &SignupRequest::receivedResponse);
}
void SignupRequest::receivedResponse() {
_state = State::Finished;
auto reply = static_cast<QNetworkReply*>(sender());
if (reply->error() && reply->size() == 0) {
qDebug() << "Error signing up: " << reply->error() << reply->readAll();
_error = Error::Unknown;
emit finished();
return;
}
auto data = reply->readAll();
QJsonParseError parseError;
auto doc = QJsonDocument::fromJson(data, &parseError);
if (parseError.error != QJsonParseError::NoError) {
qDebug() << "Error parsing response for signup " << data;
_error = Error::Unknown;
emit finished();
return;
}
auto root = doc.object();
auto status = root["status"];
if (status.isString() && status.toString() != "success") {
auto error = root["data"].toString();
_error = Error::Unknown;
if (error == "no_such_email") {
_error = Error::NoSuchEmail;
} else if (error == "user_profile_already_completed") {
_error = Error::UserProfileAlreadyCompleted;
} else if (error == "bad_username") {
_error = Error::BadUsername;
} else if (error == "existing_username") {
_error = Error::ExistingUsername;
} else if (error == "bad_password") {
_error = Error::BadPassword;
}
}
emit finished();
}

View file

@ -0,0 +1,38 @@
#pragma once
#include <QObject>
#include <QNetworkAccessManager>
class SignupRequest : public QObject {
Q_OBJECT
public:
enum class State {
Unsent,
Sending,
Finished
};
enum class Error {
None = 0,
Unknown,
NoSuchEmail,
UserProfileAlreadyCompleted,
BadUsername,
ExistingUsername,
BadPassword,
};
Q_ENUM(Error)
void send(QNetworkAccessManager& nam, QString email, QString username, QString password);
Error getError() const { return _error; }
signals:
void finished();
private slots:
void receivedResponse();
private:
State _state { State::Unsent };
Error _error { Error::None };
};

View file

@ -0,0 +1,67 @@
#include "UserSettingsRequest.h"
#include "Helper.h"
#include <QUrlQuery>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
const QByteArray ACCESS_TOKEN_AUTHORIZATION_HEADER = "Authorization";
void UserSettingsRequest::send(QNetworkAccessManager& nam, const LoginToken& token) {
_state = State::Sending;
QUrl lockerURL = METAVERSE_API_DOMAIN;
lockerURL.setPath("/api/v1/user/locker");
QNetworkRequest lockerRequest(lockerURL);
lockerRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
lockerRequest.setHeader(QNetworkRequest::UserAgentHeader, getHTTPUserAgent());
lockerRequest.setRawHeader(ACCESS_TOKEN_AUTHORIZATION_HEADER, QString("Bearer %1").arg(token.accessToken).toUtf8());
QNetworkReply* lockerReply = nam.get(lockerRequest);
connect(lockerReply, &QNetworkReply::finished, this, &UserSettingsRequest::receivedResponse);
}
void UserSettingsRequest::receivedResponse() {
_state = State::Finished;
auto reply = static_cast<QNetworkReply*>(sender());
qDebug() << "Got reply: " << reply->error();
if (reply->error()) {
_error = Error::Unknown;
emit finished();
return;
}
auto data = reply->readAll();
qDebug() << "Settings: " << data;
QJsonParseError parseError;
auto doc = QJsonDocument::fromJson(data, &parseError);
if (parseError.error != QJsonParseError::NoError) {
qDebug() << "Error parsing settings";
_error = Error::Unknown;
emit finished();
return;
}
auto root = doc.object();
if (root["status"] != "success") {
qDebug() << "Status is not \"success\"";
_error = Error::Unknown;
emit finished();
return;
}
if (root["data"].toObject().contains("home_location")) {
auto homeLocation = root["data"].toObject()["home_location"];
if (homeLocation.isString()) {
_userSettings.homeLocation = homeLocation.toString();
}
}
emit finished();
}

View file

@ -0,0 +1,43 @@
#pragma once
#include <QObject>
#include <QNetworkAccessManager>
#include "LoginRequest.h"
struct UserSettings {
QString homeLocation{ QString::null };
};
class UserSettingsRequest : public QObject {
Q_OBJECT
public:
enum class State {
Unsent,
Sending,
Finished
};
enum class Error {
None = 0,
Unknown,
};
Q_ENUM(Error)
void send(QNetworkAccessManager& nam, const LoginToken& token);
Error getError() const { return _error; }
UserSettings getUserSettings() const { return _userSettings; }
signals:
void finished();
private slots:
void receivedResponse();
private:
State _state { State::Unsent };
Error _error { Error::None };
UserSettings _userSettings;
};

View file

@ -1,5 +1,7 @@
#include <QtPlugin>
#include <qsharedmemory.h>
#include "LauncherWindow.h"
#include "Launcher.h"
#include <iostream>
@ -19,7 +21,7 @@ Q_IMPORT_PLUGIN(QtQuickTemplates2Plugin);
bool hasSuffix(const std::string path, const std::string suffix) {
bool hasSuffix(const std::string& path, const std::string& suffix) {
if (path.substr(path.find_last_of(".") + 1) == suffix) {
return true;
}
@ -61,6 +63,12 @@ int main(int argc, char *argv[]) {
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QCoreApplication::setOrganizationName(name);
#ifdef Q_OS_WIN
//QSharedMemory sharedMemory{ applicationName };
//instanceMightBeRunning = !sharedMemory.create(1, QSharedMemory::ReadOnly);
#endif
Launcher launcher(argc, argv);
return launcher.exec();