mirror of
https://github.com/laurent22/joplin.git
synced 2025-01-11 18:24:43 +02:00
Handle sync and api state before and after login/logout
This commit is contained in:
parent
5c7581ae1d
commit
a1bffbb5e5
@ -22,7 +22,8 @@ SOURCES += \
|
||||
models/basemodel.cpp \
|
||||
models/setting.cpp \
|
||||
paths.cpp \
|
||||
window.cpp
|
||||
window.cpp \
|
||||
filters.cpp
|
||||
|
||||
RESOURCES += qml.qrc \
|
||||
database.qrc
|
||||
@ -59,7 +60,8 @@ HEADERS += \
|
||||
models/setting.h \
|
||||
paths.h \
|
||||
constants.h \
|
||||
window.h
|
||||
window.h \
|
||||
filters.h
|
||||
|
||||
DISTFILES += \
|
||||
AndroidManifest.xml
|
||||
|
@ -6,6 +6,12 @@ LoginPageForm {
|
||||
|
||||
id: root
|
||||
|
||||
function onShown() {
|
||||
root.apiBaseUrl = settings.valueString("api.baseUrl");
|
||||
root.email = settings.valueString("user.email");
|
||||
root.password = "";
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
onLoginButtonClicked: {
|
||||
|
@ -9,6 +9,10 @@ Item {
|
||||
property alias currentFolderIndex: folderList.currentIndex
|
||||
property alias currentNoteIndex: noteList.currentIndex
|
||||
|
||||
function onShown() {
|
||||
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: layout
|
||||
anchors.fill: parent
|
||||
@ -94,4 +98,12 @@ Item {
|
||||
onClicked: appRoot.syncButtonClicked()
|
||||
}
|
||||
|
||||
Button {
|
||||
id: logoutButton
|
||||
text: "Logout"
|
||||
anchors.right: syncButton.left
|
||||
anchors.top: parent.top
|
||||
onClicked: dispatcher.logoutClicked()
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -48,6 +48,8 @@ Item {
|
||||
print("Switching to page: " + pageName);
|
||||
var page = pageByName(pageName);
|
||||
page.visible = true;
|
||||
|
||||
page.onShown();
|
||||
}
|
||||
|
||||
MainPage {
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "dispatcher.h"
|
||||
#include "paths.h"
|
||||
#include "constants.h"
|
||||
#include "filters.h"
|
||||
|
||||
using namespace jop;
|
||||
|
||||
@ -42,12 +43,15 @@ Application::Application(int &argc, char **argv) :
|
||||
settings.setValue("clientId", uuid::createUuid());
|
||||
}
|
||||
|
||||
Settings* qmlSettings = new Settings();
|
||||
|
||||
view_.setResizeMode(QQuickView::SizeRootObjectToView);
|
||||
QQmlContext *ctxt = view_.rootContext();
|
||||
ctxt->setContextProperty("folderListModel", &folderModel_);
|
||||
ctxt->setContextProperty("noteListModel", ¬eModel_);
|
||||
ctxt->setContextProperty("noteModel", &selectedQmlNote_);
|
||||
ctxt->setContextProperty("dispatcher", &dispatcher());
|
||||
ctxt->setContextProperty("settings", qmlSettings);
|
||||
|
||||
view_.setSource(QUrl("qrc:/app.qml"));
|
||||
|
||||
@ -62,6 +66,7 @@ Application::Application(int &argc, char **argv) :
|
||||
connect(&dispatcher(), SIGNAL(folderUpdated(QString)), this, SLOT(dispatcher_folderUpdated(QString)));
|
||||
connect(&dispatcher(), SIGNAL(folderDeleted(QString)), this, SLOT(dispatcher_folderDeleted(QString)));
|
||||
connect(&dispatcher(), SIGNAL(loginClicked(QString,QString,QString)), this, SLOT(dispatcher_loginClicked(QString,QString,QString)));
|
||||
connect(&dispatcher(), SIGNAL(logoutClicked()), this, SLOT(dispatcher_logoutClicked()));
|
||||
|
||||
view_.show();
|
||||
|
||||
@ -75,6 +80,11 @@ Application::Application(int &argc, char **argv) :
|
||||
if (!settings.contains("user.email") || !settings.contains("session.id") || !settings.contains("api.baseUrl")) {
|
||||
view_.showPage("login");
|
||||
} else {
|
||||
afterSessionInitialization();
|
||||
//QString apiBaseUrl = settings.value("api.baseUrl").toString();
|
||||
//api_.setBaseUrl(apiBaseUrl);
|
||||
//synchronizer_.api().setBaseUrl(apiBaseUrl);
|
||||
//synchronizer_.setSessionId(settings.value("session.id").toString());
|
||||
view_.showPage("main");
|
||||
}
|
||||
|
||||
@ -107,8 +117,9 @@ void Application::api_requestDone(const QJsonObject& response, const QString& ta
|
||||
|
||||
if (tag == "getSession") {
|
||||
if (response.contains("error")) {
|
||||
qCritical() << "Could not get session:" << response.value("error").toString();
|
||||
qWarning() << "Could not get session:" << response.value("error").toString();
|
||||
dispatcher().emitLoginFailed();
|
||||
view_.showPage("login");
|
||||
} else {
|
||||
QString sessionId = response.value("id").toString();
|
||||
qDebug() << "Got session" << sessionId;
|
||||
@ -116,8 +127,8 @@ void Application::api_requestDone(const QJsonObject& response, const QString& ta
|
||||
settings.setValue("session.id", sessionId);
|
||||
afterSessionInitialization();
|
||||
dispatcher().emitLoginSuccess();
|
||||
view_.showPage("main");
|
||||
}
|
||||
view_.showPage("main");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -142,14 +153,24 @@ void Application::dispatcher_loginClicked(const QString &apiBaseUrl, const QStri
|
||||
dispatcher().emitLoginStarted();
|
||||
|
||||
Settings settings;
|
||||
settings.setValue("user.email", email);
|
||||
settings.setValue("api.baseUrl", apiBaseUrl);
|
||||
settings.setValue("user.email", filters::email(email));
|
||||
settings.setValue("api.baseUrl", filters::apiBaseUrl(apiBaseUrl));
|
||||
|
||||
api_.setBaseUrl(apiBaseUrl);
|
||||
|
||||
login(email, password);
|
||||
}
|
||||
|
||||
void Application::dispatcher_logoutClicked() {
|
||||
api_.abortAll();
|
||||
synchronizer_.abort();
|
||||
synchronizer_.freeze();
|
||||
|
||||
Settings settings;
|
||||
settings.setValue("session.id", "");
|
||||
view_.showPage("login");
|
||||
}
|
||||
|
||||
void Application::synchronizerTimer_timeout() {
|
||||
//synchronizerTimer_.start(1000 * 10);
|
||||
synchronizer_.start();
|
||||
@ -178,8 +199,11 @@ void Application::afterSessionInitialization() {
|
||||
Settings settings;
|
||||
QString sessionId = settings.value("session.id").toString();
|
||||
qDebug() << "Session:" << sessionId;
|
||||
api_.setBaseUrl(settings.value("api.baseUrl").toString());
|
||||
api_.setSessionId(sessionId);
|
||||
synchronizer_.api().setBaseUrl(settings.value("api.baseUrl").toString());
|
||||
synchronizer_.setSessionId(sessionId);
|
||||
synchronizer_.unfreeze();
|
||||
synchronizer_.start();
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,7 @@ public slots:
|
||||
void dispatcher_folderUpdated(const QString& folderId);
|
||||
void dispatcher_folderDeleted(const QString& folderId);
|
||||
void dispatcher_loginClicked(const QString &domain, const QString &email, const QString &password);
|
||||
void dispatcher_logoutClicked();
|
||||
|
||||
void synchronizerTimer_timeout();
|
||||
|
||||
|
@ -20,6 +20,10 @@ void Dispatcher::emitLoginClicked(const QString &apiBaseUrl, const QString &emai
|
||||
emit loginClicked(apiBaseUrl, email, password);
|
||||
}
|
||||
|
||||
void Dispatcher::emitLogoutClicked() {
|
||||
emit logoutClicked();
|
||||
}
|
||||
|
||||
void Dispatcher::emitLoginStarted() {
|
||||
emit loginStarted();
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ public slots:
|
||||
void emitFolderUpdated(const QString& folderId);
|
||||
void emitFolderDeleted(const QString& folderId);
|
||||
void emitLoginClicked(const QString& domain, const QString& email, const QString &password);
|
||||
void emitLogoutClicked();
|
||||
void emitLoginStarted();
|
||||
void emitLoginFailed();
|
||||
void emitLoginSuccess();
|
||||
@ -29,6 +30,7 @@ signals:
|
||||
void folderUpdated(const QString& folderId);
|
||||
void folderDeleted(const QString& folderId);
|
||||
void loginClicked(const QString& domain, const QString& email, const QString& password);
|
||||
void logoutClicked();
|
||||
void loginStarted();
|
||||
void loginFailed();
|
||||
void loginSuccess();
|
||||
|
19
QtClient/JoplinQtClient/filters.cpp
Executable file
19
QtClient/JoplinQtClient/filters.cpp
Executable file
@ -0,0 +1,19 @@
|
||||
#include "filters.h"
|
||||
|
||||
using namespace jop;
|
||||
|
||||
QString filters::apiBaseUrl(const QString &baseUrl) {
|
||||
QString output(baseUrl.trimmed());
|
||||
if (!output.startsWith("http://") && !output.startsWith("https://")) {
|
||||
output = "http://" + output;
|
||||
}
|
||||
while (output.endsWith("/")) {
|
||||
output = output.left(output.length() - 1);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
QString filters::email(const QString &email) {
|
||||
QString output(email.trimmed());
|
||||
return output;
|
||||
}
|
15
QtClient/JoplinQtClient/filters.h
Executable file
15
QtClient/JoplinQtClient/filters.h
Executable file
@ -0,0 +1,15 @@
|
||||
#ifndef FILTERS_H
|
||||
#define FILTERS_H
|
||||
|
||||
#include <stable.h>
|
||||
|
||||
namespace jop {
|
||||
namespace filters {
|
||||
|
||||
QString apiBaseUrl(const QString& apiBaseUrl);
|
||||
QString email(const QString& email);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // FILTERS_H
|
@ -187,7 +187,6 @@ bool BaseModel::trackChanges() const {
|
||||
}
|
||||
|
||||
bool BaseModel::isNew() const {
|
||||
qDebug() << "EEEEEEEEEEEEEEEEEEEEEE" << isNew_ << primaryKey() << valueIsSet(primaryKey()) << values_["id"].toString();
|
||||
if (isNew_ == 0) return false;
|
||||
if (isNew_ == 1) return true;
|
||||
return !valueIsSet(primaryKey());
|
||||
@ -415,7 +414,6 @@ int BaseModel::Value::toInt() const {
|
||||
QString BaseModel::Value::toString() const {
|
||||
if (type_ == QMetaType::QString) return stringValue_;
|
||||
if (type_ == QMetaType::Int) return QString::number(intValue_);
|
||||
qCritical("Unreachable");
|
||||
return QString("");
|
||||
}
|
||||
|
||||
|
@ -26,3 +26,11 @@ void Settings::initialize() {
|
||||
const QSettings::Format SqliteFormat = QSettings::registerFormat("sqlite", &readSqlite, &writeSqlite);
|
||||
QSettings::setDefaultFormat(SqliteFormat);
|
||||
}
|
||||
|
||||
QString Settings::valueString(const QString &name, const QString &defaultValue) {
|
||||
return value(name, defaultValue).toString();
|
||||
}
|
||||
|
||||
int Settings::valueInt(const QString &name, int defaultValue) {
|
||||
return value(name, defaultValue).toInt();
|
||||
}
|
||||
|
@ -16,6 +16,11 @@ public:
|
||||
|
||||
static void initialize();
|
||||
|
||||
public slots:
|
||||
|
||||
QString valueString(const QString& name, const QString& defaultValue = "");
|
||||
int valueInt(const QString& name, int defaultValue = 0);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -12,6 +12,11 @@ Synchronizer::Synchronizer(Database &database) : db_(database) {
|
||||
}
|
||||
|
||||
void Synchronizer::start() {
|
||||
if (state_ == Frozen) {
|
||||
qWarning() << "Cannot start synchronizer while frozen";
|
||||
return;
|
||||
}
|
||||
|
||||
if (state_ != Idle) {
|
||||
qWarning() << "Cannot start synchronizer because synchronization already in progress. State: " << state_;
|
||||
return;
|
||||
@ -26,6 +31,22 @@ void Synchronizer::setSessionId(const QString &v) {
|
||||
api_.setSessionId(v);
|
||||
}
|
||||
|
||||
void Synchronizer::abort() {
|
||||
switchState(Aborting);
|
||||
}
|
||||
|
||||
void Synchronizer::freeze() {
|
||||
switchState(Frozen);
|
||||
}
|
||||
|
||||
void Synchronizer::unfreeze() {
|
||||
switchState(Idle);
|
||||
}
|
||||
|
||||
WebApi &Synchronizer::api() {
|
||||
return api_;
|
||||
}
|
||||
|
||||
QUrlQuery Synchronizer::valuesToUrlQuery(const QHash<QString, Change::Value>& values) const {
|
||||
QUrlQuery query;
|
||||
for (QHash<QString, Change::Value>::const_iterator it = values.begin(); it != values.end(); ++it) {
|
||||
@ -57,6 +78,15 @@ void Synchronizer::checkNextState() {
|
||||
|
||||
break;
|
||||
|
||||
case Aborting:
|
||||
|
||||
switchState(Idle);
|
||||
break;
|
||||
|
||||
case Frozen:
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
qCritical() << "Synchronizer has invalid state" << state_;
|
||||
@ -142,11 +172,32 @@ void Synchronizer::switchState(Synchronizer::SynchronizationState state) {
|
||||
query.addQueryItem("last_id", lastRevId);
|
||||
api_.get("synchronizer", query, QUrlQuery(), "download:getSynchronizer");
|
||||
|
||||
} else if (state == Aborting) {
|
||||
|
||||
// =============================================================================================
|
||||
// ABORTING STATE
|
||||
// =============================================================================================
|
||||
|
||||
uploadsRemaining_ = 0;
|
||||
api_.abortAll();
|
||||
checkNextState();
|
||||
|
||||
} else if (state == Frozen) {
|
||||
|
||||
// =============================================================================================
|
||||
// FROZEN STATE
|
||||
// =============================================================================================
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Synchronizer::api_requestDone(const QJsonObject& response, const QString& tag) {
|
||||
if (state_ == Frozen) {
|
||||
qWarning() << "Receiving response while synchronizer is frozen";
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList parts = tag.split(':');
|
||||
QString category = parts[0];
|
||||
QString action = parts[1];
|
||||
@ -164,7 +215,7 @@ void Synchronizer::api_requestDone(const QJsonObject& response, const QString& t
|
||||
// HANDLE UPLOAD RESPONSE
|
||||
// =============================================================================================
|
||||
|
||||
if (category == "upload") {
|
||||
if (state_ == UploadingChanges) {
|
||||
uploadsRemaining_--;
|
||||
|
||||
qDebug() << "Synced folder" << arg1;
|
||||
@ -191,7 +242,7 @@ void Synchronizer::api_requestDone(const QJsonObject& response, const QString& t
|
||||
// HANDLE DOWNLOAD RESPONSE
|
||||
// =============================================================================================
|
||||
|
||||
} else if (category == "download") {
|
||||
} else if (state_ == DownloadingChanges) {
|
||||
if (action == "getSynchronizer") {
|
||||
QJsonArray items = response["items"].toArray();
|
||||
QString maxRevId = "";
|
||||
|
@ -14,11 +14,15 @@ class Synchronizer : public QObject {
|
||||
|
||||
public:
|
||||
|
||||
enum SynchronizationState { Idle, UploadingChanges, DownloadingChanges };
|
||||
enum SynchronizationState { Idle, UploadingChanges, DownloadingChanges, Aborting, Frozen };
|
||||
|
||||
Synchronizer(Database& database);
|
||||
void start();
|
||||
void setSessionId(const QString& v);
|
||||
void abort();
|
||||
void freeze();
|
||||
void unfreeze();
|
||||
WebApi& api();
|
||||
|
||||
private:
|
||||
|
||||
|
@ -30,6 +30,7 @@ void WebApi::execRequest(HttpMethod method, const QString &path, const QUrlQuery
|
||||
r.data = data;
|
||||
r.tag = tag;
|
||||
r.buffer = NULL;
|
||||
r.reply = NULL;
|
||||
queuedRequests_ << r;
|
||||
|
||||
processQueue();
|
||||
@ -45,6 +46,25 @@ void WebApi::setSessionId(const QString &v) {
|
||||
sessionId_ = v;
|
||||
}
|
||||
|
||||
void WebApi::abortAll() {
|
||||
for (int i = 0; i < inProgressRequests_.size(); i++) {
|
||||
QueuedRequest r = inProgressRequests_[i];
|
||||
if (r.reply) {
|
||||
r.reply->abort();
|
||||
// TODO: Delete r.reply?
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < queuedRequests_.size(); i++) {
|
||||
QueuedRequest r = queuedRequests_[i];
|
||||
if (r.reply) {
|
||||
r.reply->abort();
|
||||
// TODO: Delete r.reply?
|
||||
}
|
||||
}
|
||||
queuedRequests_.size();
|
||||
}
|
||||
|
||||
void WebApi::processQueue() {
|
||||
if (!queuedRequests_.size() || inProgressRequests_.size() >= 50) return;
|
||||
QueuedRequest r = queuedRequests_.takeFirst();
|
||||
|
@ -33,6 +33,7 @@ public:
|
||||
void del(const QString& path,const QUrlQuery& query = QUrlQuery(), const QUrlQuery& data = QUrlQuery(), const QString& tag = "");
|
||||
void patch(const QString& path,const QUrlQuery& query = QUrlQuery(), const QUrlQuery& data = QUrlQuery(), const QString& tag = "");
|
||||
void setSessionId(const QString& v);
|
||||
void abortAll();
|
||||
|
||||
private:
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user