enabled delete account again
This commit is contained in:
parent
303527b75b
commit
59cb232744
@ -74,9 +74,23 @@ AWSClient::AWSClient(QObject *parent) : QObject(parent),
|
||||
config.apiEndpoint = "testapi-cloud.guh.io";
|
||||
m_configs.append(config);
|
||||
|
||||
// Marantec environment
|
||||
config.clientId = "7rf6da8pcqi1qi8tp1evf933h2";
|
||||
config.poolId = "eu-west-1_d4DdcqKJ8";
|
||||
config.identityPoolId = "eu-west-1:d32f6d94-caae-4f08-a193-f9fba8652646";
|
||||
// Generating certificates is not supported for the Marantec environment
|
||||
config.certificateEndpoint = "";
|
||||
config.certificateApiKey = "";
|
||||
config.certificateVendorId = "";
|
||||
config.mqttEndpoint = "a27q7a2x15m8h3.iot.eu-west-1.amazonaws.com";
|
||||
config.region = "eu-west-1";
|
||||
config.apiEndpoint = "api-cloud.guh.io";
|
||||
m_configs.append(config);
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup("cloud");
|
||||
m_username = settings.value("username").toString();
|
||||
m_userId = settings.value("userId").toString();
|
||||
m_password = settings.value("password").toString();
|
||||
m_accessToken = settings.value("accessToken").toByteArray();
|
||||
m_accessTokenExpiry = settings.value("accessTokenExpiry").toDateTime();
|
||||
@ -94,7 +108,7 @@ AWSClient::AWSClient(QObject *parent) : QObject(parent),
|
||||
|
||||
bool AWSClient::isLoggedIn() const
|
||||
{
|
||||
return !m_username.isEmpty() && !m_password.isEmpty();
|
||||
return !m_userId.isEmpty() && !m_username.isEmpty() && !m_password.isEmpty();
|
||||
}
|
||||
|
||||
QString AWSClient::username() const
|
||||
@ -181,18 +195,30 @@ void AWSClient::login(const QString &username, const QString &password)
|
||||
m_idToken = authenticationResult.value("IdToken").toByteArray();
|
||||
m_refreshToken = authenticationResult.value("RefreshToken").toByteArray();
|
||||
|
||||
qDebug() << "AWS ID token" << m_idToken;
|
||||
QList<QByteArray> jwtParts = m_idToken.split('.');
|
||||
if (jwtParts.count() != 3) {
|
||||
qWarning() << "JWT token doesn't have 3 parts";
|
||||
return;
|
||||
}
|
||||
// qDebug() << "decoded header:" << QByteArray::fromBase64(jwtParts.at(0));
|
||||
// qDebug() << "decoded payload:" << QByteArray::fromBase64(jwtParts.at(1));
|
||||
QJsonDocument tokenPayloadJsonDoc = QJsonDocument::fromJson(QByteArray::fromBase64(jwtParts.at(1)));
|
||||
m_userId = tokenPayloadJsonDoc.toVariant().toMap().value("cognito:username").toByteArray();
|
||||
|
||||
QSettings settings;
|
||||
settings.remove("cloud");
|
||||
|
||||
settings.beginGroup("cloud");
|
||||
settings.setValue("username", m_username);
|
||||
settings.setValue("userId", m_userId);
|
||||
settings.setValue("password", m_password);
|
||||
settings.setValue("accessToken", m_accessToken);
|
||||
settings.setValue("accessTokenExpiry", m_accessTokenExpiry);
|
||||
settings.setValue("idToken", m_idToken);
|
||||
settings.setValue("refreshToken", m_refreshToken);
|
||||
|
||||
qDebug() << "AWS login successful";// << qUtf8Printable(jsonDoc.toJson(QJsonDocument::Indented));
|
||||
qDebug() << "AWS login successful. Userid:" << m_userId;// << qUtf8Printable(jsonDoc.toJson(QJsonDocument::Indented));
|
||||
emit isLoggedInChanged();
|
||||
|
||||
qDebug() << "Getting cognito ID";
|
||||
@ -202,8 +228,10 @@ void AWSClient::login(const QString &username, const QString &password)
|
||||
|
||||
void AWSClient::logout()
|
||||
{
|
||||
m_userId.clear();
|
||||
m_username.clear();
|
||||
m_password.clear();
|
||||
m_devices->clear();
|
||||
QSettings settings;
|
||||
settings.remove("cloud");
|
||||
emit isLoggedInChanged();
|
||||
@ -441,7 +469,7 @@ void AWSClient::deleteAccount()
|
||||
}
|
||||
qDebug() << "Deleting account";
|
||||
|
||||
QUrl url(QString("https://%1/users/profiles/%2").arg(m_configs.at(m_usedConfigIndex).apiEndpoint).arg(m_username));
|
||||
QUrl url(QString("https://%1/users/profiles/%2").arg(m_configs.at(m_usedConfigIndex).apiEndpoint).arg(m_userId));
|
||||
QNetworkRequest request(url);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
request.setRawHeader("x-api-idToken", m_idToken);
|
||||
@ -458,14 +486,17 @@ void AWSClient::deleteAccount()
|
||||
QByteArray data = reply->readAll();
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
qWarning() << "Error deleting cloud user account:" << reply->error() << reply->errorString() << qUtf8Printable(data);
|
||||
emit deleteAccountResult(LoginErrorUnknownError);
|
||||
return;
|
||||
}
|
||||
QJsonParseError error;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
|
||||
if (error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Failed to parse JSON from server" << error.errorString() << qUtf8Printable(data);
|
||||
emit deleteAccountResult(LoginErrorUnknownError);
|
||||
return;
|
||||
}
|
||||
emit deleteAccountResult(LoginErrorNoError);
|
||||
logout();
|
||||
qDebug() << "Account deleted" << data;
|
||||
});
|
||||
@ -489,9 +520,11 @@ void AWSClient::unpairDevice(const QString &boxId)
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
request.setRawHeader("x-api-idToken", m_idToken);
|
||||
|
||||
m_devices->setBusy(true);
|
||||
QNetworkReply *reply = m_nam->deleteResource(request);
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply, boxId]() {
|
||||
reply->deleteLater();
|
||||
m_devices->setBusy(false);
|
||||
QByteArray data = reply->readAll();
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
qWarning() << "Error unpairing cloud device:" << reply->error() << reply->errorString() << qUtf8Printable(data);
|
||||
@ -787,9 +820,11 @@ void AWSClient::fetchDevices()
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
request.setRawHeader("x-api-idToken", m_idToken);
|
||||
|
||||
m_devices->setBusy(true);
|
||||
QNetworkReply *reply = m_nam->get(request);
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
|
||||
reply->deleteLater();
|
||||
m_devices->setBusy(false);
|
||||
QByteArray data = reply->readAll();
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
qWarning() << "Error fetching cloud devices:" << reply->error() << reply->errorString() << qUtf8Printable(data);
|
||||
@ -931,6 +966,19 @@ QHash<int, QByteArray> AWSDevices::roleNames() const
|
||||
return roles;
|
||||
}
|
||||
|
||||
bool AWSDevices::busy() const
|
||||
{
|
||||
return m_busy;
|
||||
}
|
||||
|
||||
void AWSDevices::setBusy(bool busy)
|
||||
{
|
||||
if (m_busy != busy) {
|
||||
m_busy = busy;
|
||||
emit busyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
AWSDevice *AWSDevices::getDevice(const QString &uuid) const
|
||||
{
|
||||
for (int i = 0; i < m_list.count(); i++) {
|
||||
@ -977,6 +1025,16 @@ void AWSDevices::remove(const QString &uuid)
|
||||
emit countChanged();
|
||||
}
|
||||
|
||||
void AWSDevices::clear()
|
||||
{
|
||||
beginResetModel();
|
||||
while (m_list.count() > 0) {
|
||||
m_list.takeFirst()->deleteLater();
|
||||
}
|
||||
endResetModel();
|
||||
emit countChanged();
|
||||
}
|
||||
|
||||
AWSDevice::AWSDevice(const QString &id, const QString &name, bool online, QObject *parent):
|
||||
QObject (parent),
|
||||
m_id(id),
|
||||
|
||||
@ -33,6 +33,7 @@ private:
|
||||
class AWSDevices: public QAbstractListModel {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
|
||||
Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
|
||||
public:
|
||||
enum Roles {
|
||||
RoleName,
|
||||
@ -43,14 +44,19 @@ public:
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
bool busy() const;
|
||||
void setBusy(bool busy);
|
||||
Q_INVOKABLE AWSDevice* getDevice(const QString &uuid) const;
|
||||
Q_INVOKABLE AWSDevice* get(int index) const;
|
||||
void insert(AWSDevice *device);
|
||||
void remove(const QString &uuid);
|
||||
void clear();
|
||||
signals:
|
||||
void countChanged();
|
||||
void busyChanged();
|
||||
private:
|
||||
QList<AWSDevice*> m_list;
|
||||
bool m_busy = false;
|
||||
};
|
||||
|
||||
class AWSConfiguration {
|
||||
@ -127,6 +133,7 @@ signals:
|
||||
void confirmationResult(LoginError error);
|
||||
void forgotPasswordResult(LoginError error);
|
||||
void confirmForgotPasswordResult(LoginError error);
|
||||
void deleteAccountResult(LoginError error);
|
||||
|
||||
void isLoggedInChanged();
|
||||
void confirmationPendingChanged();
|
||||
|
||||
@ -127,14 +127,14 @@ Engine::Engine(QObject *parent) :
|
||||
connect(m_aws, &AWSClient::devicesFetched, this, [this]() {
|
||||
if (m_jsonRpcClient->connected() && m_jsonRpcClient->cloudConnectionState() == JsonRpcClient::CloudConnectionStateConnected) {
|
||||
if (m_aws->awsDevices()->getDevice(m_jsonRpcClient->serverUuid()) == nullptr) {
|
||||
m_jsonRpcClient->setupRemoteAccess(m_aws->idToken(), m_aws->cognitoIdentityId());
|
||||
m_jsonRpcClient->setupRemoteAccess(m_aws->idToken(), m_aws->userId());
|
||||
}
|
||||
}
|
||||
});
|
||||
connect(m_jsonRpcClient, &JsonRpcClient::connectedChanged, this, [this]() {
|
||||
if (m_jsonRpcClient->connected() && m_jsonRpcClient->cloudConnectionState() == JsonRpcClient::CloudConnectionStateConnected) {
|
||||
if (m_aws->awsDevices()->getDevice(m_jsonRpcClient->serverUuid()) == nullptr) {
|
||||
m_jsonRpcClient->setupRemoteAccess(m_aws->idToken(), m_aws->cognitoIdentityId());
|
||||
m_jsonRpcClient->setupRemoteAccess(m_aws->idToken(), m_aws->userId());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -96,7 +96,7 @@ void JsonRpcClient::setNotificationsEnabledResponse(const QVariantMap ¶ms)
|
||||
|
||||
void JsonRpcClient::notificationReceived(const QVariantMap &data)
|
||||
{
|
||||
//JsonRpcClient: Notification received QMap(("id", QVariant(double, 2))("notification", QVariant(QString, "JSONRPC.PushButtonAuthFinished"))("params", QVariant(QVariantMap, QMap(("success", QVariant(bool, true))("token", QVariant(QString, "FJPaAJ8FEtrqcC+/s0s/lAcDubz0OyEtwbRsyFIWM9c="))("transactionId", QVariant(double, 2))))))
|
||||
qDebug() << "Notification received:" << data;
|
||||
if (data.value("notification").toString() == "JSONRPC.PushButtonAuthFinished") {
|
||||
qDebug() << "Push button auth finished.";
|
||||
if (data.value("params").toMap().value("transactionId").toInt() != m_pendingPushButtonTransaction) {
|
||||
|
||||
@ -18,7 +18,7 @@ Page {
|
||||
ListElement { iconSource: "../images/share.svg"; text: qsTr("Configure things"); page: "EditDevicesPage.qml" }
|
||||
ListElement { iconSource: "../images/magic.svg"; text: qsTr("Magic"); page: "MagicPage.qml" }
|
||||
ListElement { iconSource: "../images/stock_application.svg"; text: qsTr("App settings"); page: "appsettings/AppSettingsPage.qml" }
|
||||
ListElement { iconSource: "../images/settings.svg"; text: qsTr("System settings"); page: "SettingsPage.qml" }
|
||||
ListElement { iconSource: "../images/settings.svg"; text: qsTr("Box settings"); page: "SettingsPage.qml" }
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
@ -173,39 +173,38 @@ Page {
|
||||
}
|
||||
}
|
||||
|
||||
TabBar {
|
||||
id: tabBar
|
||||
Layout.fillWidth: true
|
||||
Material.elevation: 3
|
||||
currentIndex: settings.currentMainViewIndex
|
||||
position: TabBar.Footer
|
||||
Layout.preferredHeight: 70 + (app.landscape ?
|
||||
((systemProductType === "ios" && Screen.height === 375) ? -10 : -20) :
|
||||
(systemProductType === "ios" && Screen.height === 812) ? 14 : 0)
|
||||
}
|
||||
footer: TabBar {
|
||||
id: tabBar
|
||||
Material.elevation: 3
|
||||
currentIndex: settings.currentMainViewIndex
|
||||
position: TabBar.Footer
|
||||
implicitHeight: 70 + (app.landscape ?
|
||||
((systemProductType === "ios" && Screen.height === 375) ? -10 : -20) :
|
||||
(systemProductType === "ios" && Screen.height === 812) ? 14 : 0)
|
||||
|
||||
|
||||
// FIXME: All this can go away when we require Controls 2.3 (Qt 5.10) or greater as TabBar got a major rework there.
|
||||
// Ideally we'd just list the 3 items and set visible to false if the server version isn't good enough but TabBar
|
||||
// has troubles dealing with that. For now, let's manually fill it and use a timer to initialize the currentIndex.
|
||||
Component.onCompleted: {
|
||||
var pi = 0;
|
||||
if (Engine.jsonRpcClient.ensureServerVersion(1.6)) {
|
||||
tabEntryComponent.createObject(tabBar, {text: qsTr("Favorites"), iconSource: "../images/starred.svg", pageIndex: pi++})
|
||||
}
|
||||
tabEntryComponent.createObject(tabBar, {text: qsTr("Things"), iconSource: "../images/share.svg", pageIndex: pi++})
|
||||
tabEntryComponent.createObject(tabBar, {text: qsTr("Scenes"), iconSource: "../images/slideshow.svg", pageIndex: pi++})
|
||||
initTimer.start()
|
||||
// FIXME: All this can go away when we require Controls 2.3 (Qt 5.10) or greater as TabBar got a major rework there.
|
||||
// Ideally we'd just list the 3 items and set visible to false if the server version isn't good enough but TabBar
|
||||
// has troubles dealing with that. For now, let's manually fill it and use a timer to initialize the currentIndex.
|
||||
Component.onCompleted: {
|
||||
var pi = 0;
|
||||
if (Engine.jsonRpcClient.ensureServerVersion(1.6)) {
|
||||
tabEntryComponent.createObject(tabBar, {text: qsTr("Favorites"), iconSource: "../images/starred.svg", pageIndex: pi++})
|
||||
}
|
||||
Timer { id: initTimer; interval: 1; repeat: false; onTriggered: tabBar.currentIndex = Qt.binding(function() {return settings.currentMainViewIndex;})}
|
||||
tabEntryComponent.createObject(tabBar, {text: qsTr("Things"), iconSource: "../images/share.svg", pageIndex: pi++})
|
||||
tabEntryComponent.createObject(tabBar, {text: qsTr("Scenes"), iconSource: "../images/slideshow.svg", pageIndex: pi++})
|
||||
initTimer.start()
|
||||
}
|
||||
Timer { id: initTimer; interval: 1; repeat: false; onTriggered: tabBar.currentIndex = Qt.binding(function() {return settings.currentMainViewIndex;})}
|
||||
|
||||
Component {
|
||||
id: tabEntryComponent
|
||||
MainPageTabButton {
|
||||
property int pageIndex: 0
|
||||
Component {
|
||||
id: tabEntryComponent
|
||||
MainPageTabButton {
|
||||
property int pageIndex: 0
|
||||
// height: tabBar.height
|
||||
onClicked: settings.currentMainViewIndex = pageIndex
|
||||
alignment: app.landscape ? Qt.Horizontal : Qt.Vertical
|
||||
}
|
||||
onClicked: settings.currentMainViewIndex = pageIndex
|
||||
alignment: app.landscape ? Qt.Horizontal : Qt.Vertical
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ import "components"
|
||||
Page {
|
||||
id: root
|
||||
header: GuhHeader {
|
||||
text: qsTr("System settings")
|
||||
text: qsTr("Box settings")
|
||||
backButtonVisible: true
|
||||
onBackPressed: pageStack.pop()
|
||||
}
|
||||
|
||||
@ -124,7 +124,7 @@ Page {
|
||||
}
|
||||
MeaListItemDelegate {
|
||||
Layout.fillWidth: true
|
||||
visible: settings.showHiddenOption
|
||||
visible: settings.showHiddenOptions
|
||||
text: qsTr("Developer options")
|
||||
iconName: "../images/configure.svg"
|
||||
onClicked: pageStack.push(Qt.resolvedUrl("DeveloperOptionsPage.qml"))
|
||||
|
||||
@ -25,10 +25,20 @@ Page {
|
||||
Engine.awsClient.fetchDevices();
|
||||
}
|
||||
}
|
||||
onDeleteAccountResult: {
|
||||
busyOverlay.shown = false;
|
||||
if (error !== AWSClient.LoginErrorNoError) {
|
||||
var errorDialog = Qt.createComponent(Qt.resolvedUrl("../components/ErrorDialog.qml"));
|
||||
var text = qsTr("Sorry, an error happened removing the account. Please try again later.");
|
||||
var popup = errorDialog.createObject(app, {text: text})
|
||||
popup.open()
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors { left: parent.left; top: parent.top; right: parent.right }
|
||||
anchors.fill: parent
|
||||
visible: Engine.awsClient.isLoggedIn
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
@ -64,6 +74,7 @@ Page {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
model: Engine.awsClient.awsDevices
|
||||
clip: true
|
||||
delegate: MeaListItemDelegate {
|
||||
width: parent.width
|
||||
text: model.name
|
||||
@ -77,6 +88,11 @@ Page {
|
||||
Engine.awsClient.unpairDevice(model.id);
|
||||
}
|
||||
}
|
||||
|
||||
BusyIndicator {
|
||||
anchors.centerIn: parent
|
||||
visible: Engine.awsClient.awsDevices.busy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,28 +100,29 @@ Page {
|
||||
id: logoutDialog
|
||||
title: qsTr("Goodbye")
|
||||
// Deleting user profile not working in cloud yet
|
||||
// text: qsTr("Sorry to see you go. If you log out you won't be able to connect to %1 boxes remotely any more. However, you can come back any time, we'll keep your user account. If you whish to completely delete your account and all the data associated with it, check the box below before hitting ok.").arg(app.systemName)
|
||||
text: qsTr("Sorry to see you go. If you log out you won't be able to connect to %1 boxes remotely any more. However, you can come back any time.").arg(app.systemName)
|
||||
text: qsTr("Sorry to see you go. If you log out you won't be able to connect to %1 boxes remotely any more. However, you can come back any time, we'll keep your user account. If you whish to completely delete your account and all the data associated with it, check the box below before hitting ok.").arg(app.systemName)
|
||||
// text: qsTr("Sorry to see you go. If you log out you won't be able to connect to %1 boxes remotely any more. However, you can come back any time.").arg(app.systemName)
|
||||
headerIcon: "../images/dialog-warning-symbolic.svg"
|
||||
standardButtons: Dialog.Cancel | Dialog.Ok
|
||||
|
||||
// RowLayout {
|
||||
// CheckBox {
|
||||
// id: deleteCheckbox
|
||||
// }
|
||||
// Label {
|
||||
// Layout.fillWidth: true
|
||||
// wrapMode: Text.WordWrap
|
||||
// text: qsTr("Delete my account")
|
||||
// }
|
||||
// }
|
||||
RowLayout {
|
||||
CheckBox {
|
||||
id: deleteCheckbox
|
||||
}
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WordWrap
|
||||
text: qsTr("Delete my account")
|
||||
}
|
||||
}
|
||||
|
||||
onAccepted: {
|
||||
// if (deleteCheckbox.checked) {
|
||||
// Engine.awsClient.deleteAccount()
|
||||
// } else {
|
||||
if (deleteCheckbox.checked) {
|
||||
busyOverlay.shown = true;
|
||||
Engine.awsClient.deleteAccount()
|
||||
} else {
|
||||
Engine.awsClient.logout()
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ Page {
|
||||
|
||||
ComboBox {
|
||||
currentIndex: app.settings.cloudEnvironment
|
||||
model: [qsTr("Community"), qsTr("Testing")]
|
||||
model: [qsTr("Community"), qsTr("Testing"), qsTr("Marantec")]
|
||||
onActivated: {
|
||||
app.settings.cloudEnvironment = index;
|
||||
}
|
||||
|
||||
@ -18,8 +18,12 @@ Page {
|
||||
Connections {
|
||||
target: Engine.jsonRpcClient
|
||||
onCloudConnectionStateChanged: {
|
||||
print("cloud connection state changed", Engine.jsonRpcClient.cloudConnectionState)
|
||||
if (Engine.jsonRpcClient.cloudConnectionState == JsonRpcClient.CloudConnectionStateConnected) {
|
||||
d.deploymentStarted = false;
|
||||
if (Engine.awsClient.awsDevices.getDevice(Engine.jsonRpcClient.serverUuid) === null) {
|
||||
Engine.jsonRpcClient.setupRemoteAccess(Engine.awsClient.idToken, Engine.awsClient.userId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -37,6 +41,11 @@ Page {
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
// Button {
|
||||
// text: "pair"
|
||||
// onClicked: Engine.jsonRpcClient.setupRemoteAccess(Engine.awsClient.idToken, Engine.awsClient.userId)
|
||||
// }
|
||||
|
||||
SwitchDelegate {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Cloud connection enabled")
|
||||
|
||||
Reference in New Issue
Block a user