mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 21:57:00 +02:00
Changed AccountManager to only rely on a proper OAuth response.
This involved making another request after the initial OAuth authorization. Because of this now-two-step process, some methods and signals were renamed to make their purpose more clear. Additionally, a _hasProfile member variable was added to DataServerAccountInfo in order to allow for knowledge of whether the profile elements had been fetched when being deserialized from disk. Error handling for the whole process is still nonexistant.
This commit is contained in:
parent
e8ba3c8bb1
commit
14f56310f6
6 changed files with 172 additions and 97 deletions
|
@ -127,7 +127,7 @@ Menu::Menu() :
|
||||||
toggleLoginMenuItem();
|
toggleLoginMenuItem();
|
||||||
|
|
||||||
// connect to the appropriate slots of the AccountManager so that we can change the Login/Logout menu item
|
// connect to the appropriate slots of the AccountManager so that we can change the Login/Logout menu item
|
||||||
connect(&accountManager, &AccountManager::accessTokenChanged, this, &Menu::toggleLoginMenuItem);
|
connect(&accountManager, &AccountManager::profileChanged, this, &Menu::toggleLoginMenuItem);
|
||||||
connect(&accountManager, &AccountManager::logoutComplete, this, &Menu::toggleLoginMenuItem);
|
connect(&accountManager, &AccountManager::logoutComplete, this, &Menu::toggleLoginMenuItem);
|
||||||
|
|
||||||
addDisabledActionAndSeparator(fileMenu, "Scripts");
|
addDisabledActionAndSeparator(fileMenu, "Scripts");
|
||||||
|
@ -326,7 +326,7 @@ Menu::Menu() :
|
||||||
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, "None", 0, true));
|
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, "None", 0, true));
|
||||||
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::SimpleShadows, 0, false));
|
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::SimpleShadows, 0, false));
|
||||||
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::CascadedShadows, 0, false));
|
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::CascadedShadows, 0, false));
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, true);
|
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, true);
|
||||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::BuckyBalls, 0, false);
|
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::BuckyBalls, 0, false);
|
||||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Particles, 0, true);
|
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Particles, 0, true);
|
||||||
|
@ -407,7 +407,7 @@ Menu::Menu() :
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisableNackPackets, 0, false);
|
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisableNackPackets, 0, false);
|
||||||
|
|
||||||
addDisabledActionAndSeparator(developerMenu, "Testing");
|
addDisabledActionAndSeparator(developerMenu, "Testing");
|
||||||
|
|
||||||
QMenu* timingMenu = developerMenu->addMenu("Timing and Statistics Tools");
|
QMenu* timingMenu = developerMenu->addMenu("Timing and Statistics Tools");
|
||||||
QMenu* perfTimerMenu = timingMenu->addMenu("Performance Timer");
|
QMenu* perfTimerMenu = timingMenu->addMenu("Performance Timer");
|
||||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayTimingDetails, 0, true);
|
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayTimingDetails, 0, true);
|
||||||
|
@ -462,7 +462,7 @@ Menu::Menu() :
|
||||||
false,
|
false,
|
||||||
appInstance->getAudio(),
|
appInstance->getAudio(),
|
||||||
SLOT(toggleToneInjection()));
|
SLOT(toggleToneInjection()));
|
||||||
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioScope,
|
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioScope,
|
||||||
Qt::CTRL | Qt::Key_P, false,
|
Qt::CTRL | Qt::Key_P, false,
|
||||||
appInstance->getAudio(),
|
appInstance->getAudio(),
|
||||||
SLOT(toggleScope()));
|
SLOT(toggleScope()));
|
||||||
|
@ -1775,4 +1775,3 @@ QString Menu::getSnapshotsLocation() const {
|
||||||
}
|
}
|
||||||
return _snapshotsLocation;
|
return _snapshotsLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ XmppClient::XmppClient() :
|
||||||
_xmppMUCManager()
|
_xmppMUCManager()
|
||||||
{
|
{
|
||||||
AccountManager& accountManager = AccountManager::getInstance();
|
AccountManager& accountManager = AccountManager::getInstance();
|
||||||
connect(&accountManager, SIGNAL(accessTokenChanged()), this, SLOT(connectToServer()));
|
connect(&accountManager, SIGNAL(profileChanged()), this, SLOT(connectToServer()));
|
||||||
connect(&accountManager, SIGNAL(logoutComplete()), this, SLOT(disconnectFromServer()));
|
connect(&accountManager, SIGNAL(logoutComplete()), this, SLOT(disconnectFromServer()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,13 +55,13 @@ AccountManager::AccountManager() :
|
||||||
{
|
{
|
||||||
qRegisterMetaType<OAuthAccessToken>("OAuthAccessToken");
|
qRegisterMetaType<OAuthAccessToken>("OAuthAccessToken");
|
||||||
qRegisterMetaTypeStreamOperators<OAuthAccessToken>("OAuthAccessToken");
|
qRegisterMetaTypeStreamOperators<OAuthAccessToken>("OAuthAccessToken");
|
||||||
|
|
||||||
qRegisterMetaType<DataServerAccountInfo>("DataServerAccountInfo");
|
qRegisterMetaType<DataServerAccountInfo>("DataServerAccountInfo");
|
||||||
qRegisterMetaTypeStreamOperators<DataServerAccountInfo>("DataServerAccountInfo");
|
qRegisterMetaTypeStreamOperators<DataServerAccountInfo>("DataServerAccountInfo");
|
||||||
|
|
||||||
qRegisterMetaType<QNetworkAccessManager::Operation>("QNetworkAccessManager::Operation");
|
qRegisterMetaType<QNetworkAccessManager::Operation>("QNetworkAccessManager::Operation");
|
||||||
qRegisterMetaType<JSONCallbackParameters>("JSONCallbackParameters");
|
qRegisterMetaType<JSONCallbackParameters>("JSONCallbackParameters");
|
||||||
|
|
||||||
connect(&_accountInfo, &DataServerAccountInfo::balanceChanged, this, &AccountManager::accountInfoBalanceChanged);
|
connect(&_accountInfo, &DataServerAccountInfo::balanceChanged, this, &AccountManager::accountInfoBalanceChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,18 +70,18 @@ const QString DOUBLE_SLASH_SUBSTITUTE = "slashslash";
|
||||||
void AccountManager::logout() {
|
void AccountManager::logout() {
|
||||||
// a logout means we want to delete the DataServerAccountInfo we currently have for this URL, in-memory and in file
|
// a logout means we want to delete the DataServerAccountInfo we currently have for this URL, in-memory and in file
|
||||||
_accountInfo = DataServerAccountInfo();
|
_accountInfo = DataServerAccountInfo();
|
||||||
|
|
||||||
emit balanceChanged(0);
|
emit balanceChanged(0);
|
||||||
connect(&_accountInfo, &DataServerAccountInfo::balanceChanged, this, &AccountManager::accountInfoBalanceChanged);
|
connect(&_accountInfo, &DataServerAccountInfo::balanceChanged, this, &AccountManager::accountInfoBalanceChanged);
|
||||||
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
settings.beginGroup(ACCOUNTS_GROUP);
|
settings.beginGroup(ACCOUNTS_GROUP);
|
||||||
|
|
||||||
QString keyURLString(_authURL.toString().replace("//", DOUBLE_SLASH_SUBSTITUTE));
|
QString keyURLString(_authURL.toString().replace("//", DOUBLE_SLASH_SUBSTITUTE));
|
||||||
settings.remove(keyURLString);
|
settings.remove(keyURLString);
|
||||||
|
|
||||||
qDebug() << "Removed account info for" << _authURL << "from in-memory accounts and .ini file";
|
qDebug() << "Removed account info for" << _authURL << "from in-memory accounts and .ini file";
|
||||||
|
|
||||||
emit logoutComplete();
|
emit logoutComplete();
|
||||||
// the username has changed to blank
|
// the username has changed to blank
|
||||||
emit usernameChanged(QString());
|
emit usernameChanged(QString());
|
||||||
|
@ -93,7 +93,7 @@ void AccountManager::updateBalance() {
|
||||||
JSONCallbackParameters callbackParameters;
|
JSONCallbackParameters callbackParameters;
|
||||||
callbackParameters.jsonCallbackReceiver = &_accountInfo;
|
callbackParameters.jsonCallbackReceiver = &_accountInfo;
|
||||||
callbackParameters.jsonCallbackMethod = "setBalanceFromJSON";
|
callbackParameters.jsonCallbackMethod = "setBalanceFromJSON";
|
||||||
|
|
||||||
authenticatedRequest("/api/v1/wallets/mine", QNetworkAccessManager::GetOperation, callbackParameters);
|
authenticatedRequest("/api/v1/wallets/mine", QNetworkAccessManager::GetOperation, callbackParameters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,28 +105,33 @@ void AccountManager::accountInfoBalanceChanged(qint64 newBalance) {
|
||||||
void AccountManager::setAuthURL(const QUrl& authURL) {
|
void AccountManager::setAuthURL(const QUrl& authURL) {
|
||||||
if (_authURL != authURL) {
|
if (_authURL != authURL) {
|
||||||
_authURL = authURL;
|
_authURL = authURL;
|
||||||
|
|
||||||
qDebug() << "URL for node authentication has been changed to" << qPrintable(_authURL.toString());
|
qDebug() << "URL for node authentication has been changed to" << qPrintable(_authURL.toString());
|
||||||
qDebug() << "Re-setting authentication flow.";
|
qDebug() << "Re-setting authentication flow.";
|
||||||
|
|
||||||
// check if there are existing access tokens to load from settings
|
// check if there are existing access tokens to load from settings
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
settings.beginGroup(ACCOUNTS_GROUP);
|
settings.beginGroup(ACCOUNTS_GROUP);
|
||||||
|
|
||||||
foreach(const QString& key, settings.allKeys()) {
|
foreach(const QString& key, settings.allKeys()) {
|
||||||
// take a key copy to perform the double slash replacement
|
// take a key copy to perform the double slash replacement
|
||||||
QString keyCopy(key);
|
QString keyCopy(key);
|
||||||
QUrl keyURL(keyCopy.replace("slashslash", "//"));
|
QUrl keyURL(keyCopy.replace("slashslash", "//"));
|
||||||
|
|
||||||
if (keyURL == _authURL) {
|
if (keyURL == _authURL) {
|
||||||
// pull out the stored access token and store it in memory
|
// pull out the stored access token and store it in memory
|
||||||
_accountInfo = settings.value(key).value<DataServerAccountInfo>();
|
_accountInfo = settings.value(key).value<DataServerAccountInfo>();
|
||||||
qDebug() << "Found a data-server access token for" << qPrintable(keyURL.toString());
|
qDebug() << "Found a data-server access token for" << qPrintable(keyURL.toString());
|
||||||
|
|
||||||
emit accessTokenChanged();
|
// profile info isn't guaranteed to be saved too
|
||||||
|
if (_accountInfo.hasProfile()) {
|
||||||
|
emit profileChanged();
|
||||||
|
} else {
|
||||||
|
requestProfile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// tell listeners that the auth endpoint has changed
|
// tell listeners that the auth endpoint has changed
|
||||||
emit authEndpointChanged();
|
emit authEndpointChanged();
|
||||||
}
|
}
|
||||||
|
@ -147,36 +152,36 @@ void AccountManager::authenticatedRequest(const QString& path, QNetworkAccessMan
|
||||||
void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager::Operation operation,
|
void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager::Operation operation,
|
||||||
const JSONCallbackParameters& callbackParams,
|
const JSONCallbackParameters& callbackParams,
|
||||||
const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart) {
|
const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart) {
|
||||||
|
|
||||||
if (!_networkAccessManager) {
|
if (!_networkAccessManager) {
|
||||||
_networkAccessManager = new QNetworkAccessManager(this);
|
_networkAccessManager = new QNetworkAccessManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasValidAccessToken()) {
|
if (hasValidAccessToken()) {
|
||||||
QNetworkRequest authenticatedRequest;
|
QNetworkRequest authenticatedRequest;
|
||||||
|
|
||||||
QUrl requestURL = _authURL;
|
QUrl requestURL = _authURL;
|
||||||
|
|
||||||
if (path.startsWith("/")) {
|
if (path.startsWith("/")) {
|
||||||
requestURL.setPath(path);
|
requestURL.setPath(path);
|
||||||
} else {
|
} else {
|
||||||
requestURL.setPath("/" + path);
|
requestURL.setPath("/" + path);
|
||||||
}
|
}
|
||||||
|
|
||||||
requestURL.setQuery("access_token=" + _accountInfo.getAccessToken().token);
|
requestURL.setQuery("access_token=" + _accountInfo.getAccessToken().token);
|
||||||
|
|
||||||
authenticatedRequest.setUrl(requestURL);
|
authenticatedRequest.setUrl(requestURL);
|
||||||
|
|
||||||
if (VERBOSE_HTTP_REQUEST_DEBUGGING) {
|
if (VERBOSE_HTTP_REQUEST_DEBUGGING) {
|
||||||
qDebug() << "Making an authenticated request to" << qPrintable(requestURL.toString());
|
qDebug() << "Making an authenticated request to" << qPrintable(requestURL.toString());
|
||||||
|
|
||||||
if (!dataByteArray.isEmpty()) {
|
if (!dataByteArray.isEmpty()) {
|
||||||
qDebug() << "The POST/PUT body -" << QString(dataByteArray);
|
qDebug() << "The POST/PUT body -" << QString(dataByteArray);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QNetworkReply* networkReply = NULL;
|
QNetworkReply* networkReply = NULL;
|
||||||
|
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case QNetworkAccessManager::GetOperation:
|
case QNetworkAccessManager::GetOperation:
|
||||||
networkReply = _networkAccessManager->get(authenticatedRequest);
|
networkReply = _networkAccessManager->get(authenticatedRequest);
|
||||||
|
@ -198,24 +203,24 @@ void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager::
|
||||||
networkReply = _networkAccessManager->put(authenticatedRequest, dataByteArray);
|
networkReply = _networkAccessManager->put(authenticatedRequest, dataByteArray);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// other methods not yet handled
|
// other methods not yet handled
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (networkReply) {
|
if (networkReply) {
|
||||||
if (!callbackParams.isEmpty()) {
|
if (!callbackParams.isEmpty()) {
|
||||||
// if we have information for a callback, insert the callbackParams into our local map
|
// if we have information for a callback, insert the callbackParams into our local map
|
||||||
_pendingCallbackMap.insert(networkReply, callbackParams);
|
_pendingCallbackMap.insert(networkReply, callbackParams);
|
||||||
|
|
||||||
if (callbackParams.updateReciever && !callbackParams.updateSlot.isEmpty()) {
|
if (callbackParams.updateReciever && !callbackParams.updateSlot.isEmpty()) {
|
||||||
callbackParams.updateReciever->connect(networkReply, SIGNAL(uploadProgress(qint64, qint64)),
|
callbackParams.updateReciever->connect(networkReply, SIGNAL(uploadProgress(qint64, qint64)),
|
||||||
callbackParams.updateSlot.toStdString().c_str());
|
callbackParams.updateSlot.toStdString().c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we ended up firing of a request, hook up to it now
|
// if we ended up firing of a request, hook up to it now
|
||||||
connect(networkReply, SIGNAL(finished()), SLOT(processReply()));
|
connect(networkReply, SIGNAL(finished()), SLOT(processReply()));
|
||||||
}
|
}
|
||||||
|
@ -224,7 +229,7 @@ void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager::
|
||||||
|
|
||||||
void AccountManager::processReply() {
|
void AccountManager::processReply() {
|
||||||
QNetworkReply* requestReply = reinterpret_cast<QNetworkReply*>(sender());
|
QNetworkReply* requestReply = reinterpret_cast<QNetworkReply*>(sender());
|
||||||
|
|
||||||
if (requestReply->error() == QNetworkReply::NoError) {
|
if (requestReply->error() == QNetworkReply::NoError) {
|
||||||
passSuccessToCallback(requestReply);
|
passSuccessToCallback(requestReply);
|
||||||
} else {
|
} else {
|
||||||
|
@ -235,17 +240,17 @@ void AccountManager::processReply() {
|
||||||
|
|
||||||
void AccountManager::passSuccessToCallback(QNetworkReply* requestReply) {
|
void AccountManager::passSuccessToCallback(QNetworkReply* requestReply) {
|
||||||
QJsonDocument jsonResponse = QJsonDocument::fromJson(requestReply->readAll());
|
QJsonDocument jsonResponse = QJsonDocument::fromJson(requestReply->readAll());
|
||||||
|
|
||||||
JSONCallbackParameters callbackParams = _pendingCallbackMap.value(requestReply);
|
JSONCallbackParameters callbackParams = _pendingCallbackMap.value(requestReply);
|
||||||
|
|
||||||
if (callbackParams.jsonCallbackReceiver) {
|
if (callbackParams.jsonCallbackReceiver) {
|
||||||
// invoke the right method on the callback receiver
|
// invoke the right method on the callback receiver
|
||||||
QMetaObject::invokeMethod(callbackParams.jsonCallbackReceiver, qPrintable(callbackParams.jsonCallbackMethod),
|
QMetaObject::invokeMethod(callbackParams.jsonCallbackReceiver, qPrintable(callbackParams.jsonCallbackMethod),
|
||||||
Q_ARG(const QJsonObject&, jsonResponse.object()));
|
Q_ARG(const QJsonObject&, jsonResponse.object()));
|
||||||
|
|
||||||
// remove the related reply-callback group from the map
|
// remove the related reply-callback group from the map
|
||||||
_pendingCallbackMap.remove(requestReply);
|
_pendingCallbackMap.remove(requestReply);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (VERBOSE_HTTP_REQUEST_DEBUGGING) {
|
if (VERBOSE_HTTP_REQUEST_DEBUGGING) {
|
||||||
qDebug() << "Received JSON response from data-server that has no matching callback.";
|
qDebug() << "Received JSON response from data-server that has no matching callback.";
|
||||||
|
@ -256,13 +261,13 @@ void AccountManager::passSuccessToCallback(QNetworkReply* requestReply) {
|
||||||
|
|
||||||
void AccountManager::passErrorToCallback(QNetworkReply* requestReply) {
|
void AccountManager::passErrorToCallback(QNetworkReply* requestReply) {
|
||||||
JSONCallbackParameters callbackParams = _pendingCallbackMap.value(requestReply);
|
JSONCallbackParameters callbackParams = _pendingCallbackMap.value(requestReply);
|
||||||
|
|
||||||
if (callbackParams.errorCallbackReceiver) {
|
if (callbackParams.errorCallbackReceiver) {
|
||||||
// invoke the right method on the callback receiver
|
// invoke the right method on the callback receiver
|
||||||
QMetaObject::invokeMethod(callbackParams.errorCallbackReceiver, qPrintable(callbackParams.errorCallbackMethod),
|
QMetaObject::invokeMethod(callbackParams.errorCallbackReceiver, qPrintable(callbackParams.errorCallbackMethod),
|
||||||
Q_ARG(QNetworkReply::NetworkError, requestReply->error()),
|
Q_ARG(QNetworkReply::NetworkError, requestReply->error()),
|
||||||
Q_ARG(const QString&, requestReply->errorString()));
|
Q_ARG(const QString&, requestReply->errorString()));
|
||||||
|
|
||||||
// remove the related reply-callback group from the map
|
// remove the related reply-callback group from the map
|
||||||
_pendingCallbackMap.remove(requestReply);
|
_pendingCallbackMap.remove(requestReply);
|
||||||
} else {
|
} else {
|
||||||
|
@ -274,12 +279,12 @@ void AccountManager::passErrorToCallback(QNetworkReply* requestReply) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AccountManager::hasValidAccessToken() {
|
bool AccountManager::hasValidAccessToken() {
|
||||||
|
|
||||||
if (_accountInfo.getAccessToken().token.isEmpty() || _accountInfo.getAccessToken().isExpired()) {
|
if (_accountInfo.getAccessToken().token.isEmpty() || _accountInfo.getAccessToken().isExpired()) {
|
||||||
if (VERBOSE_HTTP_REQUEST_DEBUGGING) {
|
if (VERBOSE_HTTP_REQUEST_DEBUGGING) {
|
||||||
qDebug() << "An access token is required for requests to" << qPrintable(_authURL.toString());
|
qDebug() << "An access token is required for requests to" << qPrintable(_authURL.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
|
@ -288,12 +293,12 @@ bool AccountManager::hasValidAccessToken() {
|
||||||
|
|
||||||
bool AccountManager::checkAndSignalForAccessToken() {
|
bool AccountManager::checkAndSignalForAccessToken() {
|
||||||
bool hasToken = hasValidAccessToken();
|
bool hasToken = hasValidAccessToken();
|
||||||
|
|
||||||
if (!hasToken) {
|
if (!hasToken) {
|
||||||
// emit a signal so somebody can call back to us and request an access token given a username and password
|
// emit a signal so somebody can call back to us and request an access token given a username and password
|
||||||
emit authRequired();
|
emit authRequired();
|
||||||
}
|
}
|
||||||
|
|
||||||
return hasToken;
|
return hasToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,36 +309,36 @@ void AccountManager::requestAccessToken(const QString& login, const QString& pas
|
||||||
}
|
}
|
||||||
|
|
||||||
QNetworkRequest request;
|
QNetworkRequest request;
|
||||||
|
|
||||||
QUrl grantURL = _authURL;
|
QUrl grantURL = _authURL;
|
||||||
grantURL.setPath("/oauth/token");
|
grantURL.setPath("/oauth/token");
|
||||||
|
|
||||||
const QString ACCOUNT_MANAGER_REQUESTED_SCOPE = "owner";
|
const QString ACCOUNT_MANAGER_REQUESTED_SCOPE = "owner";
|
||||||
|
|
||||||
QByteArray postData;
|
QByteArray postData;
|
||||||
postData.append("grant_type=password&");
|
postData.append("grant_type=password&");
|
||||||
postData.append("username=" + login + "&");
|
postData.append("username=" + login + "&");
|
||||||
postData.append("password=" + QUrl::toPercentEncoding(password) + "&");
|
postData.append("password=" + QUrl::toPercentEncoding(password) + "&");
|
||||||
postData.append("scope=" + ACCOUNT_MANAGER_REQUESTED_SCOPE);
|
postData.append("scope=" + ACCOUNT_MANAGER_REQUESTED_SCOPE);
|
||||||
|
|
||||||
request.setUrl(grantURL);
|
request.setUrl(grantURL);
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||||
|
|
||||||
QNetworkReply* requestReply = _networkAccessManager->post(request, postData);
|
QNetworkReply* requestReply = _networkAccessManager->post(request, postData);
|
||||||
connect(requestReply, &QNetworkReply::finished, this, &AccountManager::requestFinished);
|
connect(requestReply, &QNetworkReply::finished, this, &AccountManager::requestAccessTokenFinished);
|
||||||
connect(requestReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestError(QNetworkReply::NetworkError)));
|
connect(requestReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestAccessTokenError(QNetworkReply::NetworkError)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AccountManager::requestFinished() {
|
void AccountManager::requestAccessTokenFinished() {
|
||||||
QNetworkReply* requestReply = reinterpret_cast<QNetworkReply*>(sender());
|
QNetworkReply* requestReply = reinterpret_cast<QNetworkReply*>(sender());
|
||||||
|
|
||||||
QJsonDocument jsonResponse = QJsonDocument::fromJson(requestReply->readAll());
|
QJsonDocument jsonResponse = QJsonDocument::fromJson(requestReply->readAll());
|
||||||
const QJsonObject& rootObject = jsonResponse.object();
|
const QJsonObject& rootObject = jsonResponse.object();
|
||||||
|
|
||||||
if (!rootObject.contains("error")) {
|
if (!rootObject.contains("error")) {
|
||||||
// construct an OAuthAccessToken from the json object
|
// construct an OAuthAccessToken from the json object
|
||||||
|
|
||||||
if (!rootObject.contains("access_token") || !rootObject.contains("expires_in")
|
if (!rootObject.contains("access_token") || !rootObject.contains("expires_in")
|
||||||
|| !rootObject.contains("token_type")) {
|
|| !rootObject.contains("token_type")) {
|
||||||
// TODO: error handling - malformed token response
|
// TODO: error handling - malformed token response
|
||||||
|
@ -342,23 +347,21 @@ void AccountManager::requestFinished() {
|
||||||
// clear the path from the response URL so we have the right root URL for this access token
|
// clear the path from the response URL so we have the right root URL for this access token
|
||||||
QUrl rootURL = requestReply->url();
|
QUrl rootURL = requestReply->url();
|
||||||
rootURL.setPath("");
|
rootURL.setPath("");
|
||||||
|
|
||||||
qDebug() << "Storing an account with access-token for" << qPrintable(rootURL.toString());
|
qDebug() << "Storing an account with access-token for" << qPrintable(rootURL.toString());
|
||||||
|
|
||||||
_accountInfo = DataServerAccountInfo(rootObject);
|
_accountInfo = DataServerAccountInfo();
|
||||||
|
_accountInfo.setAccessTokenFromJSON(rootObject);
|
||||||
|
|
||||||
emit loginComplete(rootURL);
|
emit loginComplete(rootURL);
|
||||||
// the username has changed to whatever came back
|
|
||||||
emit usernameChanged(_accountInfo.getUsername());
|
|
||||||
|
|
||||||
// we have found or requested an access token
|
|
||||||
emit accessTokenChanged();
|
|
||||||
|
|
||||||
// store this access token into the local settings
|
// store this access token into the local settings
|
||||||
QSettings localSettings;
|
QSettings localSettings;
|
||||||
localSettings.beginGroup(ACCOUNTS_GROUP);
|
localSettings.beginGroup(ACCOUNTS_GROUP);
|
||||||
localSettings.setValue(rootURL.toString().replace("//", DOUBLE_SLASH_SUBSTITUTE),
|
localSettings.setValue(rootURL.toString().replace("//", DOUBLE_SLASH_SUBSTITUTE),
|
||||||
QVariant::fromValue(_accountInfo));
|
QVariant::fromValue(_accountInfo));
|
||||||
|
|
||||||
|
requestProfile();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO: error handling
|
// TODO: error handling
|
||||||
|
@ -367,7 +370,53 @@ void AccountManager::requestFinished() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountManager::requestError(QNetworkReply::NetworkError error) {
|
void AccountManager::requestAccessTokenError(QNetworkReply::NetworkError error) {
|
||||||
// TODO: error handling
|
// TODO: error handling
|
||||||
qDebug() << "AccountManager requestError - " << error;
|
qDebug() << "AccountManager requestError - " << error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AccountManager::requestProfile() {
|
||||||
|
if (!_networkAccessManager) {
|
||||||
|
_networkAccessManager = new QNetworkAccessManager(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrl profileURL = _authURL;
|
||||||
|
profileURL.setPath("/api/v1/users/profile");
|
||||||
|
profileURL.setQuery("access_token=" + _accountInfo.getAccessToken().token);
|
||||||
|
|
||||||
|
QNetworkReply* profileReply = _networkAccessManager->get(QNetworkRequest(profileURL));
|
||||||
|
connect(profileReply, &QNetworkReply::finished, this, &AccountManager::requestProfileFinished);
|
||||||
|
connect(profileReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestProfileError(QNetworkReply::NetworkError)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountManager::requestProfileFinished() {
|
||||||
|
QNetworkReply* profileReply = reinterpret_cast<QNetworkReply*>(sender());
|
||||||
|
|
||||||
|
QJsonDocument jsonResponse = QJsonDocument::fromJson(profileReply->readAll());
|
||||||
|
const QJsonObject& rootObject = jsonResponse.object();
|
||||||
|
|
||||||
|
if (rootObject.contains("status") && rootObject["status"].toString() == "success") {
|
||||||
|
_accountInfo.setProfileInfoFromJSON(rootObject);
|
||||||
|
|
||||||
|
emit profileChanged();
|
||||||
|
|
||||||
|
// the username has changed to whatever came back
|
||||||
|
emit usernameChanged(_accountInfo.getUsername());
|
||||||
|
|
||||||
|
// store the whole profile into the local settings
|
||||||
|
QUrl rootURL = profileReply->url();
|
||||||
|
rootURL.setPath("");
|
||||||
|
QSettings localSettings;
|
||||||
|
localSettings.beginGroup(ACCOUNTS_GROUP);
|
||||||
|
localSettings.setValue(rootURL.toString().replace("//", DOUBLE_SLASH_SUBSTITUTE),
|
||||||
|
QVariant::fromValue(_accountInfo));
|
||||||
|
} else {
|
||||||
|
// TODO: error handling
|
||||||
|
qDebug() << "Error in response for profile";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountManager::requestProfileError(QNetworkReply::NetworkError error) {
|
||||||
|
// TODO: error handling
|
||||||
|
qDebug() << "AccountManager requestProfileError - " << error;
|
||||||
|
}
|
||||||
|
|
|
@ -23,9 +23,9 @@
|
||||||
class JSONCallbackParameters {
|
class JSONCallbackParameters {
|
||||||
public:
|
public:
|
||||||
JSONCallbackParameters();
|
JSONCallbackParameters();
|
||||||
|
|
||||||
bool isEmpty() const { return !jsonCallbackReceiver && !errorCallbackReceiver; }
|
bool isEmpty() const { return !jsonCallbackReceiver && !errorCallbackReceiver; }
|
||||||
|
|
||||||
QObject* jsonCallbackReceiver;
|
QObject* jsonCallbackReceiver;
|
||||||
QString jsonCallbackMethod;
|
QString jsonCallbackMethod;
|
||||||
QObject* errorCallbackReceiver;
|
QObject* errorCallbackReceiver;
|
||||||
|
@ -38,30 +38,33 @@ class AccountManager : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
static AccountManager& getInstance();
|
static AccountManager& getInstance();
|
||||||
|
|
||||||
void authenticatedRequest(const QString& path,
|
void authenticatedRequest(const QString& path,
|
||||||
QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation,
|
QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation,
|
||||||
const JSONCallbackParameters& callbackParams = JSONCallbackParameters(),
|
const JSONCallbackParameters& callbackParams = JSONCallbackParameters(),
|
||||||
const QByteArray& dataByteArray = QByteArray(),
|
const QByteArray& dataByteArray = QByteArray(),
|
||||||
QHttpMultiPart* dataMultiPart = NULL);
|
QHttpMultiPart* dataMultiPart = NULL);
|
||||||
|
|
||||||
const QUrl& getAuthURL() const { return _authURL; }
|
const QUrl& getAuthURL() const { return _authURL; }
|
||||||
void setAuthURL(const QUrl& authURL);
|
void setAuthURL(const QUrl& authURL);
|
||||||
bool hasAuthEndpoint() { return !_authURL.isEmpty(); }
|
bool hasAuthEndpoint() { return !_authURL.isEmpty(); }
|
||||||
|
|
||||||
bool isLoggedIn() { return !_authURL.isEmpty() && hasValidAccessToken(); }
|
bool isLoggedIn() { return !_authURL.isEmpty() && hasValidAccessToken(); }
|
||||||
bool hasValidAccessToken();
|
bool hasValidAccessToken();
|
||||||
Q_INVOKABLE bool checkAndSignalForAccessToken();
|
Q_INVOKABLE bool checkAndSignalForAccessToken();
|
||||||
|
|
||||||
void requestAccessToken(const QString& login, const QString& password);
|
void requestAccessToken(const QString& login, const QString& password);
|
||||||
|
void requestProfile();
|
||||||
|
|
||||||
const DataServerAccountInfo& getAccountInfo() const { return _accountInfo; }
|
const DataServerAccountInfo& getAccountInfo() const { return _accountInfo; }
|
||||||
|
|
||||||
void destroy() { delete _networkAccessManager; }
|
void destroy() { delete _networkAccessManager; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void requestFinished();
|
void requestAccessTokenFinished();
|
||||||
void requestError(QNetworkReply::NetworkError error);
|
void requestProfileFinished();
|
||||||
|
void requestAccessTokenError(QNetworkReply::NetworkError error);
|
||||||
|
void requestProfileError(QNetworkReply::NetworkError error);
|
||||||
void logout();
|
void logout();
|
||||||
void updateBalance();
|
void updateBalance();
|
||||||
void accountInfoBalanceChanged(qint64 newBalance);
|
void accountInfoBalanceChanged(qint64 newBalance);
|
||||||
|
@ -69,7 +72,7 @@ signals:
|
||||||
void authRequired();
|
void authRequired();
|
||||||
void authEndpointChanged();
|
void authEndpointChanged();
|
||||||
void usernameChanged(const QString& username);
|
void usernameChanged(const QString& username);
|
||||||
void accessTokenChanged();
|
void profileChanged();
|
||||||
void loginComplete(const QUrl& authURL);
|
void loginComplete(const QUrl& authURL);
|
||||||
void loginFailed();
|
void loginFailed();
|
||||||
void logoutComplete();
|
void logoutComplete();
|
||||||
|
@ -80,19 +83,19 @@ private:
|
||||||
AccountManager();
|
AccountManager();
|
||||||
AccountManager(AccountManager const& other); // not implemented
|
AccountManager(AccountManager const& other); // not implemented
|
||||||
void operator=(AccountManager const& other); // not implemented
|
void operator=(AccountManager const& other); // not implemented
|
||||||
|
|
||||||
void passSuccessToCallback(QNetworkReply* reply);
|
void passSuccessToCallback(QNetworkReply* reply);
|
||||||
void passErrorToCallback(QNetworkReply* reply);
|
void passErrorToCallback(QNetworkReply* reply);
|
||||||
|
|
||||||
Q_INVOKABLE void invokedRequest(const QString& path, QNetworkAccessManager::Operation operation,
|
Q_INVOKABLE void invokedRequest(const QString& path, QNetworkAccessManager::Operation operation,
|
||||||
const JSONCallbackParameters& callbackParams,
|
const JSONCallbackParameters& callbackParams,
|
||||||
const QByteArray& dataByteArray,
|
const QByteArray& dataByteArray,
|
||||||
QHttpMultiPart* dataMultiPart);
|
QHttpMultiPart* dataMultiPart);
|
||||||
|
|
||||||
QUrl _authURL;
|
QUrl _authURL;
|
||||||
QNetworkAccessManager* _networkAccessManager;
|
QNetworkAccessManager* _networkAccessManager;
|
||||||
QMap<QNetworkReply*, JSONCallbackParameters> _pendingCallbackMap;
|
QMap<QNetworkReply*, JSONCallbackParameters> _pendingCallbackMap;
|
||||||
|
|
||||||
DataServerAccountInfo _accountInfo;
|
DataServerAccountInfo _accountInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -19,11 +19,13 @@ DataServerAccountInfo::DataServerAccountInfo() :
|
||||||
_xmppPassword(),
|
_xmppPassword(),
|
||||||
_discourseApiKey(),
|
_discourseApiKey(),
|
||||||
_balance(0),
|
_balance(0),
|
||||||
_hasBalance(false)
|
_hasBalance(false),
|
||||||
|
_hasProfile(false)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
DataServerAccountInfo::DataServerAccountInfo(const QJsonObject& jsonObject) :
|
DataServerAccountInfo::DataServerAccountInfo(const QJsonObject& jsonObject) :
|
||||||
_accessToken(jsonObject),
|
_accessToken(jsonObject),
|
||||||
_username(),
|
_username(),
|
||||||
|
@ -36,6 +38,7 @@ DataServerAccountInfo::DataServerAccountInfo(const QJsonObject& jsonObject) :
|
||||||
setXMPPPassword(userJSONObject["xmpp_password"].toString());
|
setXMPPPassword(userJSONObject["xmpp_password"].toString());
|
||||||
setDiscourseApiKey(userJSONObject["discourse_api_key"].toString());
|
setDiscourseApiKey(userJSONObject["discourse_api_key"].toString());
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
DataServerAccountInfo::DataServerAccountInfo(const DataServerAccountInfo& otherInfo) {
|
DataServerAccountInfo::DataServerAccountInfo(const DataServerAccountInfo& otherInfo) {
|
||||||
_accessToken = otherInfo._accessToken;
|
_accessToken = otherInfo._accessToken;
|
||||||
|
@ -44,6 +47,7 @@ DataServerAccountInfo::DataServerAccountInfo(const DataServerAccountInfo& otherI
|
||||||
_discourseApiKey = otherInfo._discourseApiKey;
|
_discourseApiKey = otherInfo._discourseApiKey;
|
||||||
_balance = otherInfo._balance;
|
_balance = otherInfo._balance;
|
||||||
_hasBalance = otherInfo._hasBalance;
|
_hasBalance = otherInfo._hasBalance;
|
||||||
|
_hasProfile = otherInfo._hasProfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataServerAccountInfo& DataServerAccountInfo::operator=(const DataServerAccountInfo& otherInfo) {
|
DataServerAccountInfo& DataServerAccountInfo::operator=(const DataServerAccountInfo& otherInfo) {
|
||||||
|
@ -54,19 +58,24 @@ DataServerAccountInfo& DataServerAccountInfo::operator=(const DataServerAccountI
|
||||||
|
|
||||||
void DataServerAccountInfo::swap(DataServerAccountInfo& otherInfo) {
|
void DataServerAccountInfo::swap(DataServerAccountInfo& otherInfo) {
|
||||||
using std::swap;
|
using std::swap;
|
||||||
|
|
||||||
swap(_accessToken, otherInfo._accessToken);
|
swap(_accessToken, otherInfo._accessToken);
|
||||||
swap(_username, otherInfo._username);
|
swap(_username, otherInfo._username);
|
||||||
swap(_xmppPassword, otherInfo._xmppPassword);
|
swap(_xmppPassword, otherInfo._xmppPassword);
|
||||||
swap(_discourseApiKey, otherInfo._discourseApiKey);
|
swap(_discourseApiKey, otherInfo._discourseApiKey);
|
||||||
swap(_balance, otherInfo._balance);
|
swap(_balance, otherInfo._balance);
|
||||||
swap(_hasBalance, otherInfo._hasBalance);
|
swap(_hasBalance, otherInfo._hasBalance);
|
||||||
|
swap(_hasProfile, otherInfo._hasProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataServerAccountInfo::setAccessTokenFromJSON(const QJsonObject& jsonObject) {
|
||||||
|
_accessToken = OAuthAccessToken(jsonObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataServerAccountInfo::setUsername(const QString& username) {
|
void DataServerAccountInfo::setUsername(const QString& username) {
|
||||||
if (_username != username) {
|
if (_username != username) {
|
||||||
_username = username;
|
_username = username;
|
||||||
|
|
||||||
qDebug() << "Username changed to" << username;
|
qDebug() << "Username changed to" << username;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,7 +96,7 @@ void DataServerAccountInfo::setBalance(qint64 balance) {
|
||||||
if (!_hasBalance || _balance != balance) {
|
if (!_hasBalance || _balance != balance) {
|
||||||
_balance = balance;
|
_balance = balance;
|
||||||
_hasBalance = true;
|
_hasBalance = true;
|
||||||
|
|
||||||
emit balanceChanged(_balance);
|
emit balanceChanged(_balance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,12 +108,20 @@ void DataServerAccountInfo::setBalanceFromJSON(const QJsonObject& jsonObject) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DataServerAccountInfo::setProfileInfoFromJSON(const QJsonObject& jsonObject) {
|
||||||
|
QJsonObject user = jsonObject["data"].toObject()["user"].toObject();
|
||||||
|
setUsername(user["username"].toString());
|
||||||
|
setXMPPPassword(user["xmpp_password"].toString());
|
||||||
|
setDiscourseApiKey(user["discourse_api_key"].toString());
|
||||||
|
setHasProfile(true);
|
||||||
|
}
|
||||||
|
|
||||||
QDataStream& operator<<(QDataStream &out, const DataServerAccountInfo& info) {
|
QDataStream& operator<<(QDataStream &out, const DataServerAccountInfo& info) {
|
||||||
out << info._accessToken << info._username << info._xmppPassword << info._discourseApiKey;
|
out << info._accessToken << info._username << info._xmppPassword << info._discourseApiKey << info._hasProfile;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDataStream& operator>>(QDataStream &in, DataServerAccountInfo& info) {
|
QDataStream& operator>>(QDataStream &in, DataServerAccountInfo& info) {
|
||||||
in >> info._accessToken >> info._username >> info._xmppPassword >> info._discourseApiKey;
|
in >> info._accessToken >> info._username >> info._xmppPassword >> info._discourseApiKey >> info._hasProfile;
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,12 +22,13 @@ class DataServerAccountInfo : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
DataServerAccountInfo();
|
DataServerAccountInfo();
|
||||||
DataServerAccountInfo(const QJsonObject& jsonObject);
|
// DataServerAccountInfo(const QJsonObject& jsonObject);
|
||||||
DataServerAccountInfo(const DataServerAccountInfo& otherInfo);
|
DataServerAccountInfo(const DataServerAccountInfo& otherInfo);
|
||||||
DataServerAccountInfo& operator=(const DataServerAccountInfo& otherInfo);
|
DataServerAccountInfo& operator=(const DataServerAccountInfo& otherInfo);
|
||||||
|
|
||||||
const OAuthAccessToken& getAccessToken() const { return _accessToken; }
|
const OAuthAccessToken& getAccessToken() const { return _accessToken; }
|
||||||
|
void setAccessTokenFromJSON(const QJsonObject& jsonObject);
|
||||||
|
|
||||||
const QString& getUsername() const { return _username; }
|
const QString& getUsername() const { return _username; }
|
||||||
void setUsername(const QString& username);
|
void setUsername(const QString& username);
|
||||||
|
|
||||||
|
@ -36,26 +37,32 @@ public:
|
||||||
|
|
||||||
const QString& getDiscourseApiKey() const { return _discourseApiKey; }
|
const QString& getDiscourseApiKey() const { return _discourseApiKey; }
|
||||||
void setDiscourseApiKey(const QString& discourseApiKey);
|
void setDiscourseApiKey(const QString& discourseApiKey);
|
||||||
|
|
||||||
qint64 getBalance() const { return _balance; }
|
qint64 getBalance() const { return _balance; }
|
||||||
void setBalance(qint64 balance);
|
void setBalance(qint64 balance);
|
||||||
bool hasBalance() const { return _hasBalance; }
|
bool hasBalance() const { return _hasBalance; }
|
||||||
void setHasBalance(bool hasBalance) { _hasBalance = hasBalance; }
|
void setHasBalance(bool hasBalance) { _hasBalance = hasBalance; }
|
||||||
Q_INVOKABLE void setBalanceFromJSON(const QJsonObject& jsonObject);
|
Q_INVOKABLE void setBalanceFromJSON(const QJsonObject& jsonObject);
|
||||||
|
|
||||||
|
bool hasProfile() const { return _hasProfile; }
|
||||||
|
void setHasProfile(bool hasProfile) { _hasProfile = hasProfile; }
|
||||||
|
|
||||||
|
void setProfileInfoFromJSON(const QJsonObject& jsonObject);
|
||||||
|
|
||||||
friend QDataStream& operator<<(QDataStream &out, const DataServerAccountInfo& info);
|
friend QDataStream& operator<<(QDataStream &out, const DataServerAccountInfo& info);
|
||||||
friend QDataStream& operator>>(QDataStream &in, DataServerAccountInfo& info);
|
friend QDataStream& operator>>(QDataStream &in, DataServerAccountInfo& info);
|
||||||
signals:
|
signals:
|
||||||
qint64 balanceChanged(qint64 newBalance);
|
qint64 balanceChanged(qint64 newBalance);
|
||||||
private:
|
private:
|
||||||
void swap(DataServerAccountInfo& otherInfo);
|
void swap(DataServerAccountInfo& otherInfo);
|
||||||
|
|
||||||
OAuthAccessToken _accessToken;
|
OAuthAccessToken _accessToken;
|
||||||
QString _username;
|
QString _username;
|
||||||
QString _xmppPassword;
|
QString _xmppPassword;
|
||||||
QString _discourseApiKey;
|
QString _discourseApiKey;
|
||||||
qint64 _balance;
|
qint64 _balance;
|
||||||
bool _hasBalance;
|
bool _hasBalance;
|
||||||
|
bool _hasProfile;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_DataServerAccountInfo_h
|
#endif // hifi_DataServerAccountInfo_h
|
||||||
|
|
Loading…
Reference in a new issue