More state informations
This commit is contained in:
parent
601985436d
commit
00921391a2
2 changed files with 134 additions and 92 deletions
179
src/notesapi.cpp
179
src/notesapi.cpp
|
@ -8,13 +8,15 @@ NotesApi::NotesApi(const QString statusEndpoint, const QString loginEndpoint, co
|
|||
: QObject(parent), m_statusEndpoint(statusEndpoint), m_loginEndpoint(loginEndpoint), m_notesEndpoint(notesEndpoint)
|
||||
{
|
||||
// TODO verify connections (also in destructor)
|
||||
m_loginPollTimer.setInterval(5000);
|
||||
m_loginPollTimer.setInterval(POLL_INTERVALL);
|
||||
connect(&m_loginPollTimer, SIGNAL(timeout()), this, SLOT(pollLoginUrl()));
|
||||
m_statusReply = NULL;
|
||||
m_loginReply = NULL;
|
||||
m_pollReply = NULL;
|
||||
m_statusStatus = RequestStatus::StatusNone;
|
||||
m_loginStatus = RequestStatus::StatusNone;
|
||||
setNcStatusStatus(NextcloudStatus::NextcloudUnknown);
|
||||
setLoginStatus(LoginStatus::LoginUnknown);
|
||||
m_ncStatusStatus = NextcloudStatus::NextcloudUnknown;
|
||||
m_loginStatus = LoginStatus::LoginUnknown;
|
||||
mp_model = new NotesModel(this);
|
||||
mp_modelProxy = new NotesProxyModel(this);
|
||||
mp_modelProxy->setSourceModel(mp_model);
|
||||
|
@ -37,12 +39,13 @@ NotesApi::NotesApi(const QString statusEndpoint, const QString loginEndpoint, co
|
|||
}
|
||||
|
||||
NotesApi::~NotesApi() {
|
||||
disconnect(mp_model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), this, SLOT(saveToFile(QModelIndex,QModelIndex,QVector<int>)));
|
||||
disconnect(&m_loginPollTimer, SIGNAL(timeout()), this, SLOT(pollLoginUrl()));
|
||||
disconnect(this, SIGNAL(urlChanged(QUrl)), this, SLOT(verifyUrl(QUrl)));
|
||||
disconnect(&m_manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), this, SLOT(requireAuthentication(QNetworkReply*,QAuthenticator*)));
|
||||
disconnect(&m_manager, SIGNAL(networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility)), this, SLOT(onNetworkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility)));
|
||||
disconnect(&m_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
|
||||
disconnect(&m_manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), this, SLOT(sslError(QNetworkReply*,QList<QSslError>)));
|
||||
disconnect(mp_model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), this, SLOT(saveToFile(QModelIndex,QModelIndex,QVector<int>)));
|
||||
m_jsonFile.close();
|
||||
if (mp_modelProxy)
|
||||
delete mp_modelProxy;
|
||||
|
@ -157,35 +160,38 @@ void NotesApi::setDataFile(QString dataFile) {
|
|||
}
|
||||
}
|
||||
|
||||
bool NotesApi::getStatus() {
|
||||
if (m_statusStatus != RequestStatus::StatusBusy) {
|
||||
m_statusStatus = RequestStatus::StatusBusy;
|
||||
emit statusStatusChanged(m_statusStatus);
|
||||
}
|
||||
bool NotesApi::getNcStatus() {
|
||||
QUrl url = apiEndpointUrl(m_statusEndpoint);
|
||||
qDebug() << "POST" << url.toDisplayString();
|
||||
if (url.isValid() && !url.scheme().isEmpty() && !url.host().isEmpty()) {
|
||||
qDebug() << "POST" << url.toDisplayString();
|
||||
setNcStatusStatus(NextcloudStatus::NextcloudBusy);
|
||||
m_request.setUrl(url);
|
||||
m_statusReply = m_manager.post(m_request, QByteArray());
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
qDebug() << "URL not valid!";
|
||||
setNcStatusStatus(NextcloudStatus::NextcloudUnknown);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NotesApi::initiateFlowV2Login() {
|
||||
if (m_loginStatus == RequestStatus::StatusInitiated || m_loginStatus == RequestStatus::StatusBusy) {
|
||||
if (m_loginStatus == LoginStatus::LoginFlowV2Initiating || m_loginStatus == LoginStatus::LoginFlowV2Polling) {
|
||||
abortFlowV2Login();
|
||||
}
|
||||
if (m_loginStatus != RequestStatus::StatusInitiated) {
|
||||
m_loginStatus = RequestStatus::StatusInitiated;
|
||||
emit loginStatusChanged(m_loginStatus);
|
||||
QUrl url = apiEndpointUrl(m_loginEndpoint);
|
||||
if (url.isValid() && !url.scheme().isEmpty() && !url.host().isEmpty()) {
|
||||
qDebug() << "POST" << url.toDisplayString();
|
||||
m_request.setUrl(url);
|
||||
m_loginReply = m_manager.post(m_request, QByteArray());
|
||||
return true;
|
||||
}
|
||||
QUrl url = apiEndpointUrl(m_loginEndpoint);
|
||||
qDebug() << "POST" << url.toDisplayString();
|
||||
if (url.isValid() && !url.scheme().isEmpty() && !url.host().isEmpty()) {
|
||||
setLoginStatus(LoginStatus::LoginFlowV2Initiating);
|
||||
m_request.setUrl(url);
|
||||
m_loginReply = m_manager.post(m_request, QByteArray());
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
qDebug() << "URL not valid!";
|
||||
setLoginStatus(LoginStatus::LoginFlowV2Failed);
|
||||
abortFlowV2Login();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -200,14 +206,20 @@ void NotesApi::abortFlowV2Login() {
|
|||
m_loginReply->abort();
|
||||
if (m_pollReply->isRunning())
|
||||
m_pollReply->abort();
|
||||
setLoginStatus(LoginStatus::LoginUnknown);
|
||||
}
|
||||
|
||||
void NotesApi::pollLoginUrl() {
|
||||
qDebug() << "POST" << m_pollUrl.toDisplayString();
|
||||
if (m_pollUrl.isValid() && !m_pollUrl.scheme().isEmpty() && !m_pollUrl.host().isEmpty() && !m_pollToken.isEmpty()) {
|
||||
qDebug() << "POST" << m_pollUrl.toDisplayString();
|
||||
m_request.setUrl(m_pollUrl);
|
||||
m_pollReply = m_manager.post(m_request, QByteArray("token=").append(m_pollToken));
|
||||
}
|
||||
else {
|
||||
qDebug() << "URL not valid!";
|
||||
setLoginStatus(LoginStatus::LoginFlowV2Failed);
|
||||
abortFlowV2Login();
|
||||
}
|
||||
}
|
||||
|
||||
void NotesApi::getAllNotes(QStringList excludeFields) {
|
||||
|
@ -279,10 +291,40 @@ void NotesApi::deleteNote(double noteId) {
|
|||
mp_model->removeNote(noteId);
|
||||
}
|
||||
|
||||
const QString NotesApi::errorMessage(ErrorCodes error) const {
|
||||
QString message;
|
||||
switch (error) {
|
||||
case NoError:
|
||||
break;
|
||||
case NoConnectionError:
|
||||
message = tr("No network connection available");
|
||||
break;
|
||||
case CommunicationError:
|
||||
message = tr("Failed to communicate with the Nextcloud server");
|
||||
break;
|
||||
case LocalFileReadError:
|
||||
message = tr("An error happened while reading from the local storage");
|
||||
break;
|
||||
case LocalFileWriteError:
|
||||
message = tr("An error happened while writing to the local storage");
|
||||
break;
|
||||
case SslHandshakeError:
|
||||
message = tr("An error occured while establishing an encrypted connection");
|
||||
break;
|
||||
case AuthenticationError:
|
||||
message = tr("Could not authenticate to the Nextcloud instance");
|
||||
break;
|
||||
default:
|
||||
message = tr("Unknown error");
|
||||
break;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
void NotesApi::verifyUrl(QUrl url) {
|
||||
emit urlValidChanged(url.isValid());
|
||||
if (m_url.isValid() && !m_url.scheme().isEmpty() && !m_url.host().isEmpty()) {
|
||||
getStatus();
|
||||
getNcStatus();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,7 +377,7 @@ void NotesApi::replyFinished(QNetworkReply *reply) {
|
|||
else if (reply == m_statusReply) {
|
||||
qDebug() << "Status reply";
|
||||
if (json.isObject())
|
||||
updateStatus(json.object());
|
||||
updateNcStatus(json.object());
|
||||
m_statusReply = NULL;
|
||||
}
|
||||
else if (m_notesReplies.contains(reply)) {
|
||||
|
@ -363,17 +405,17 @@ void NotesApi::replyFinished(QNetworkReply *reply) {
|
|||
else {
|
||||
if (reply == m_loginReply) {
|
||||
m_loginReply = NULL;
|
||||
m_loginStatus = RequestStatus::StatusError;
|
||||
m_loginStatus = LoginStatus::LoginFailed;
|
||||
emit loginStatusChanged(m_loginStatus);
|
||||
}
|
||||
else if (reply == m_pollReply) {
|
||||
m_pollReply = NULL;
|
||||
m_loginStatus = RequestStatus::StatusError;
|
||||
m_loginStatus = LoginStatus::LoginFlowV2Polling;
|
||||
emit loginStatusChanged(m_loginStatus);
|
||||
}
|
||||
else if (reply == m_statusReply) {
|
||||
m_statusReply = NULL;
|
||||
updateStatus(QJsonObject());
|
||||
updateNcStatus(QJsonObject());
|
||||
//m_statusStatus = RequestStatus::StatusError;
|
||||
//emit statusStatusChanged(m_statusStatus);
|
||||
}
|
||||
|
@ -412,7 +454,7 @@ QUrl NotesApi::apiEndpointUrl(const QString endpoint) const {
|
|||
return url;
|
||||
}
|
||||
|
||||
void NotesApi::updateStatus(const QJsonObject &status) {
|
||||
void NotesApi::updateNcStatus(const QJsonObject &status) {
|
||||
if (m_status_installed != status.value("installed").toBool()) {
|
||||
m_status_installed = status.value("installed").toBool();
|
||||
emit statusInstalledChanged(m_status_installed);
|
||||
|
@ -446,10 +488,17 @@ void NotesApi::updateStatus(const QJsonObject &status) {
|
|||
emit statusExtendedSupportChanged(m_status_extendedSupport);
|
||||
}
|
||||
if (status.isEmpty())
|
||||
m_statusStatus = RequestStatus::StatusError;
|
||||
setNcStatusStatus(NextcloudStatus::NextcloudFailed);
|
||||
else
|
||||
m_statusStatus = RequestStatus::StatusFinished;
|
||||
emit statusStatusChanged(m_statusStatus);
|
||||
setNcStatusStatus(NextcloudStatus::NextcloudSuccess);
|
||||
}
|
||||
|
||||
void NotesApi::setNcStatusStatus(NextcloudStatus status, bool *changed) {
|
||||
*changed = status != m_ncStatusStatus;
|
||||
if (*changed) {
|
||||
m_ncStatusStatus = status;
|
||||
emit ncStatusStatusChanged(m_ncStatusStatus);
|
||||
}
|
||||
}
|
||||
|
||||
bool NotesApi::updateLoginFlow(const QJsonObject &login) {
|
||||
|
@ -457,32 +506,29 @@ bool NotesApi::updateLoginFlow(const QJsonObject &login) {
|
|||
QString token;
|
||||
if (!login.isEmpty()) {
|
||||
QJsonObject poll = login.value("poll").toObject();
|
||||
if (!poll.isEmpty()) {
|
||||
url = poll.value("endpoint").toString() ;
|
||||
url = login.value("login").toString();
|
||||
if (!poll.isEmpty() && url.isValid()) {
|
||||
if (url != m_loginUrl) {
|
||||
m_loginUrl = url;
|
||||
emit loginUrlChanged(m_loginUrl);
|
||||
}
|
||||
url = poll.value("endpoint").toString();
|
||||
token = poll.value("token").toString();
|
||||
if (url.isValid() && !token.isEmpty()) {
|
||||
m_pollUrl = url;
|
||||
qDebug() << "Poll URL: " << m_pollUrl;
|
||||
m_pollToken = token;
|
||||
qDebug() << "Poll Token: " << m_pollToken;
|
||||
}
|
||||
else {
|
||||
qDebug() << "Invalid Poll URL:" << url;
|
||||
setLoginStatus(LoginStatus::LoginFlowV2Polling);
|
||||
m_loginPollTimer.start();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
url = login.value("login").toString();
|
||||
if (m_loginUrl != url && url.isValid() && m_pollUrl.isValid() && !m_pollToken.isEmpty()) {
|
||||
m_loginUrl = url;
|
||||
m_loginStatus = RequestStatus::StatusBusy;
|
||||
emit loginUrlChanged(m_loginUrl);
|
||||
emit loginStatusChanged(m_loginStatus);
|
||||
m_loginPollTimer.start();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
abortFlowV2Login();
|
||||
}
|
||||
}
|
||||
else {
|
||||
qDebug() << "Invalid Poll Data:" << login;
|
||||
setLoginStatus(LoginStatus::LoginFlowV2Failed);
|
||||
abortFlowV2Login();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -504,40 +550,17 @@ bool NotesApi::updateLoginCredentials(const QJsonObject &credentials) {
|
|||
}
|
||||
if (!serverAddr.isEmpty() && !loginName.isEmpty() && !appPassword.isEmpty()) {
|
||||
qDebug() << "Login successfull for user" << loginName << "on" << serverAddr;
|
||||
m_loginStatus = RequestStatus::StatusFinished;
|
||||
emit loginStatusChanged(m_loginStatus);
|
||||
setLoginStatus(LoginStatus::LoginFlowV2Success);
|
||||
return true;
|
||||
}
|
||||
qDebug() << "Login failed for user" << loginName << "on" << serverAddr;
|
||||
return false;
|
||||
}
|
||||
|
||||
const QString NotesApi::errorMessage(int error) const {
|
||||
QString message;
|
||||
switch (error) {
|
||||
case NoError:
|
||||
break;
|
||||
case NoConnectionError:
|
||||
message = tr("No network connection available");
|
||||
break;
|
||||
case CommunicationError:
|
||||
message = tr("Failed to communicate with the Nextcloud server");
|
||||
break;
|
||||
case LocalFileReadError:
|
||||
message = tr("An error happened while reading from the local storage");
|
||||
break;
|
||||
case LocalFileWriteError:
|
||||
message = tr("An error happened while writing to the local storage");
|
||||
break;
|
||||
case SslHandshakeError:
|
||||
message = tr("An error occured while establishing an encrypted connection");
|
||||
break;
|
||||
case AuthenticationError:
|
||||
message = tr("Could not authenticate to the Nextcloud instance");
|
||||
break;
|
||||
default:
|
||||
message = tr("Unknown error");
|
||||
break;
|
||||
void NotesApi::setLoginStatus(LoginStatus status, bool *changed) {
|
||||
*changed = status != m_loginStatus;
|
||||
if (*changed) {
|
||||
m_loginStatus = status;
|
||||
emit loginStatusChanged(m_loginStatus);
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define STATUS_ENDPOINT "/status.php"
|
||||
#define LOGIN_ENDPOINT "/index.php/login/v2"
|
||||
#define NOTES_ENDPOINT "/index.php/apps/notes/api/v0.2"
|
||||
#define POLL_INTERVALL 5000
|
||||
|
||||
class NotesApi : public QObject
|
||||
{
|
||||
|
@ -76,11 +77,27 @@ public:
|
|||
Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
|
||||
bool busy() const { return !m_notesReplies.empty();; }
|
||||
|
||||
enum RequestStatus { StatusNone, StatusInitiated, StatusBusy, StatusFinished, StatusError };
|
||||
Q_ENUM(RequestStatus)
|
||||
enum NextcloudStatus {
|
||||
NextcloudUnknown, // Nothing known about the nextcloud server
|
||||
NextcloudBusy, // Getting information from the nextcloud server
|
||||
NextcloudSuccess, // Got information about the nextcloud server
|
||||
NextcloudFailed // Error getting information from the nextcloud server, see error()
|
||||
};
|
||||
Q_ENUM(NextcloudStatus)
|
||||
enum LoginStatus {
|
||||
LoginUnknown, // Inital unknown state
|
||||
LoginLegacyReady, // Ready for legacy login
|
||||
LoginFlowV2Initiating, // Initiating login flow v2
|
||||
LoginFlowV2Polling, // Ready for login flow v2
|
||||
LoginFlowV2Success, // Finished login flow v2
|
||||
LoginFlowV2Failed, // An error in login flow v2
|
||||
LoginSuccess, // Login has been verified successfull
|
||||
LoginFailed // Login has failed, see error()
|
||||
};
|
||||
Q_ENUM(LoginStatus)
|
||||
|
||||
Q_PROPERTY(RequestStatus statusStatus READ statusStatus NOTIFY statusStatusChanged)
|
||||
RequestStatus statusStatus() const { return m_statusStatus; }
|
||||
Q_PROPERTY(NextcloudStatus ncStatusStatus READ ncStatusStatus NOTIFY ncStatusStatusChanged)
|
||||
NextcloudStatus ncStatusStatus() const { return m_ncStatusStatus; }
|
||||
Q_PROPERTY(bool statusInstalled READ statusInstalled NOTIFY statusInstalledChanged)
|
||||
bool statusInstalled() const { return m_status_installed; }
|
||||
Q_PROPERTY(bool statusMaintenance READ statusMaintenance NOTIFY statusMaintenanceChanged)
|
||||
|
@ -98,12 +115,12 @@ public:
|
|||
Q_PROPERTY(bool statusExtendedSupport READ statusExtendedSupport NOTIFY statusExtendedSupportChanged)
|
||||
bool statusExtendedSupport() const { return m_status_extendedSupport; }
|
||||
|
||||
Q_PROPERTY(RequestStatus loginStatus READ loginStatus NOTIFY loginStatusChanged)
|
||||
RequestStatus loginStatus() const { return m_loginStatus; }
|
||||
Q_PROPERTY(LoginStatus loginStatus READ loginStatus NOTIFY loginStatusChanged)
|
||||
LoginStatus loginStatus() const { return m_loginStatus; }
|
||||
Q_PROPERTY(QUrl loginUrl READ loginUrl NOTIFY loginUrlChanged)
|
||||
QUrl loginUrl() const { return m_loginUrl; }
|
||||
|
||||
Q_INVOKABLE bool getStatus();
|
||||
Q_INVOKABLE bool getNcStatus();
|
||||
Q_INVOKABLE bool initiateFlowV2Login();
|
||||
Q_INVOKABLE void abortFlowV2Login();
|
||||
Q_INVOKABLE void getAllNotes(QStringList excludeFields = QStringList());
|
||||
|
@ -122,7 +139,7 @@ public:
|
|||
SslHandshakeError,
|
||||
AuthenticationError
|
||||
};
|
||||
Q_INVOKABLE const QString errorMessage(int error) const;
|
||||
Q_INVOKABLE const QString errorMessage(ErrorCodes error) const;
|
||||
|
||||
signals:
|
||||
void sslVerifyChanged(bool verify);
|
||||
|
@ -140,7 +157,7 @@ signals:
|
|||
void lastSyncChanged(QDateTime lastSync);
|
||||
void busyChanged(bool busy);
|
||||
|
||||
void statusStatusChanged(RequestStatus status);
|
||||
void ncStatusStatusChanged(NextcloudStatus status);
|
||||
void statusInstalledChanged(bool installed);
|
||||
void statusMaintenanceChanged(bool maintenance);
|
||||
void statusNeedsDbUpgradeChanged(bool needsDbUpgrade);
|
||||
|
@ -150,9 +167,9 @@ signals:
|
|||
void statusProductNameChanged(QString productName);
|
||||
void statusExtendedSupportChanged(bool extendedSupport);
|
||||
|
||||
void loginStatusChanged(RequestStatus status);
|
||||
void loginStatusChanged(LoginStatus status);
|
||||
void loginUrlChanged(QUrl url);
|
||||
void error(int error);
|
||||
void error(ErrorCodes error);
|
||||
|
||||
public slots:
|
||||
|
||||
|
@ -178,8 +195,9 @@ private:
|
|||
// Nextcloud status.php
|
||||
const QString m_statusEndpoint;
|
||||
QNetworkReply* m_statusReply;
|
||||
void updateStatus(const QJsonObject &status);
|
||||
RequestStatus m_statusStatus;
|
||||
void updateNcStatus(const QJsonObject &status);
|
||||
NextcloudStatus m_ncStatusStatus;
|
||||
void setNcStatusStatus(NextcloudStatus status, bool *changed = NULL);
|
||||
bool m_status_installed;
|
||||
bool m_status_maintenance;
|
||||
bool m_status_needsDbUpgrade;
|
||||
|
@ -195,7 +213,8 @@ private:
|
|||
QNetworkReply* m_pollReply;
|
||||
bool updateLoginFlow(const QJsonObject &login);
|
||||
bool updateLoginCredentials(const QJsonObject &credentials);
|
||||
RequestStatus m_loginStatus;
|
||||
LoginStatus m_loginStatus;
|
||||
void setLoginStatus(LoginStatus status, bool *changed = NULL);
|
||||
QTimer m_loginPollTimer;
|
||||
QUrl m_loginUrl;
|
||||
QUrl m_pollUrl;
|
||||
|
|
Loading…
Reference in a new issue