1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-24 10:27:10 +02:00

Handle login frontend

This commit is contained in:
Laurent Cozic 2017-01-11 00:28:51 +01:00
parent 7e0ee0ba9c
commit e16122d978
15 changed files with 220 additions and 27 deletions

View File

@ -21,7 +21,8 @@ SOURCES += \
models/change.cpp \
models/basemodel.cpp \
models/setting.cpp \
paths.cpp
paths.cpp \
window.cpp
RESOURCES += qml.qrc \
database.qrc
@ -57,7 +58,8 @@ HEADERS += \
enum.h \
models/setting.h \
paths.h \
constants.h
constants.h \
window.h
DISTFILES += \
AndroidManifest.xml

View File

@ -1,4 +1,29 @@
import QtQuick 2.4
LoginPageForm {
property Item appRoot
id: root
Connections {
target: root
onLoginButtonClicked: {
dispatcher.emitLoginClicked(root.apiBaseUrl, root.email, root.password);
}
}
Connections {
target: dispatcher
onLoginStarted: {
root.enabled = false;
}
onLoginFailed: {
root.enabled = true;
}
onLoginSuccess: {
root.enabled = true;
}
}
}

View File

@ -3,8 +3,19 @@ import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
Item {
id: root
width: 400
height: 400
signal loginButtonClicked()
property alias apiBaseUrl: apiBaseUrlTF.text
property alias email: emailTF.text
property alias password: passwordTF.text
Rectangle {
id: rectangle2
color: "#ffffff"
anchors.fill: parent
}
GridLayout {
id: gridLayout1
@ -15,11 +26,12 @@ Item {
Label {
id: label1
text: qsTr("Domain")
text: qsTr("API base URL")
}
TextField {
id: textField1
id: apiBaseUrlTF
text: "http://joplin.local"
Layout.fillWidth: true
}
@ -29,7 +41,8 @@ Item {
}
TextField {
id: textField2
id: emailTF
text: "laurent@cozic.net"
Layout.fillWidth: true
}
@ -39,12 +52,13 @@ Item {
}
TextField {
id: textField3
id: passwordTF
text: "12345678"
Layout.fillWidth: true
}
Button {
id: button1
id: loginButton
text: qsTr("Login")
Layout.fillWidth: true
Layout.columnSpan: 2
@ -65,4 +79,10 @@ Item {
}
Connections {
target: loginButton
onClicked: root.loginButtonClicked()
}
}

View File

@ -12,17 +12,49 @@ Item {
signal addNoteButtonClicked()
signal addFolderButtonClicked()
signal syncButtonClicked()
signal loginButtonClicked()
property alias currentFolderIndex: mainPage.currentFolderIndex
property alias currentNoteIndex: mainPage.currentNoteIndex
property var pages : ({})
function pageByName(pageName) {
if (root.pages[pageName]) return root.pages[pageName];
var page = null;
if (pageName === "main") {
page = mainPage
} else if (pageName === "login") {
var s = '
LoginPage {
id: loginPage
anchors.fill: parent
visible: false
appRoot: root
}';
page = Qt.createQmlObject(s, root);
}
root.pages[pageName] = page;
return page;
}
function showPage(pageName) {
for (var n in root.pages) {
root.pages[n].visible = false;
}
print("Switching to page: " + pageName);
var page = pageByName(pageName);
page.visible = true;
}
MainPage {
id: mainPage
anchors.fill: parent
appRoot: root
}
LoginPage {
visible: false
}
}

View File

@ -16,8 +16,7 @@ using namespace jop;
Application::Application(int &argc, char **argv) :
QGuiApplication(argc, argv),
db_(jop::db()),
api_(jop::API_BASE_URL),
synchronizer_(api_.baseUrl(), db_),
synchronizer_(db_),
folderModel_(db_)
{
@ -43,6 +42,7 @@ Application::Application(int &argc, char **argv) :
ctxt->setContextProperty("folderListModel", &folderModel_);
ctxt->setContextProperty("noteListModel", &noteModel_);
ctxt->setContextProperty("noteModel", &selectedQmlNote_);
ctxt->setContextProperty("dispatcher", &dispatcher());
view_.setSource(QUrl("qrc:/app.qml"));
@ -56,6 +56,7 @@ Application::Application(int &argc, char **argv) :
connect(&dispatcher(), SIGNAL(folderCreated(QString)), this, SLOT(dispatcher_folderCreated(QString)));
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)));
view_.show();
@ -66,6 +67,12 @@ Application::Application(int &argc, char **argv) :
connect(&api_, SIGNAL(requestDone(const QJsonObject&, const QString&)), this, SLOT(api_requestDone(const QJsonObject&, const QString&)));
if (!settings.contains("user.email") || !settings.contains("session.id") || !settings.contains("api.baseUrl")) {
view_.showPage("login");
} else {
view_.showPage("main");
}
// Don't store password, store session ID
// QString clientId = "B6E12222B6E12222";
// if (!settings.contains("user.email")) {
@ -80,15 +87,35 @@ Application::Application(int &argc, char **argv) :
// api_.post("sessions", QUrlQuery(), postData, "getSession");
}
void Application::login(const QString &email, const QString &password) {
QUrlQuery postData;
postData.addQueryItem("email", email);
postData.addQueryItem("password", password);
postData.addQueryItem("client_id", clientId());
api_.post("sessions", QUrlQuery(), postData, "getSession");
}
QString Application::clientId() const {
return "2222222222222222";
}
void Application::api_requestDone(const QJsonObject& response, const QString& tag) {
// TODO: handle errors
// Handle expired sessions
if (tag == "getSession") {
if (response.contains("error")) {
qCritical() << "Could not get session:" << response.value("error").toString();
dispatcher().emitLoginFailed();
} else {
QString sessionId = response.value("id").toString();
qDebug() << "Got session" << sessionId;
Settings settings;
settings.setValue("sessionId", sessionId);
settings.setValue("session.id", sessionId);
afterSessionInitialization();
dispatcher().emitLoginSuccess();
}
view_.showPage("main");
return;
}
}
@ -108,6 +135,19 @@ void Application::dispatcher_folderDeleted(const QString &folderId) {
//synchronizerTimer_.start(1000 * 3);
}
void Application::dispatcher_loginClicked(const QString &apiBaseUrl, const QString &email, const QString &password) {
qDebug() << apiBaseUrl << email << password;
dispatcher().emitLoginStarted();
Settings settings;
settings.setValue("user.email", email);
settings.setValue("api.baseUrl", apiBaseUrl);
api_.setBaseUrl(apiBaseUrl);
login(email, password);
}
void Application::synchronizerTimer_timeout() {
//synchronizerTimer_.start(1000 * 10);
synchronizer_.start();
@ -134,7 +174,7 @@ void Application::afterSessionInitialization() {
// request a new session everytime on startup.
Settings settings;
QString sessionId = settings.value("sessionId").toString();
QString sessionId = settings.value("session.id").toString();
qDebug() << "Session:" << sessionId;
api_.setSessionId(sessionId);
synchronizer_.setSessionId(sessionId);

View File

@ -10,6 +10,7 @@
#include "models/qmlnote.h"
#include "webapi.h"
#include "synchronizer.h"
#include "window.h"
namespace jop {
@ -20,10 +21,12 @@ class Application : public QGuiApplication {
public:
Application(int &argc, char **argv);
void login(const QString& email, const QString& password);
QString clientId() const;
private:
QQuickView view_;
Window view_;
Database& db_;
NoteCollection noteCollection_;
FolderModel folderModel_;
@ -50,6 +53,7 @@ public slots:
void dispatcher_folderCreated(const QString& folderId);
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 synchronizerTimer_timeout();

View File

@ -8,7 +8,6 @@ namespace jop {
const QString ORG_NAME = "Cozic";
const QString ORG_DOMAIN = "cozic.net";
const QString APP_NAME = "Joplin";
const QString API_BASE_URL = "https://joplin.cozic.net";
}

View File

@ -16,6 +16,22 @@ void Dispatcher::emitFolderDeleted(const QString &folderId) {
emit folderDeleted(folderId);
}
void Dispatcher::emitLoginClicked(const QString &apiBaseUrl, const QString &email, const QString &password) {
emit loginClicked(apiBaseUrl, email, password);
}
void Dispatcher::emitLoginStarted() {
emit loginStarted();
}
void Dispatcher::emitLoginFailed() {
emit loginFailed();
}
void Dispatcher::emitLoginSuccess() {
emit loginSuccess();
}
Dispatcher dispatcherInstance_;
Dispatcher& jop::dispatcher() {

View File

@ -12,15 +12,26 @@ class Dispatcher : public QObject {
public:
Dispatcher();
public slots:
void emitFolderCreated(const QString& folderId);
void emitFolderUpdated(const QString& folderId);
void emitFolderDeleted(const QString& folderId);
void emitLoginClicked(const QString& domain, const QString& email, const QString &password);
void emitLoginStarted();
void emitLoginFailed();
void emitLoginSuccess();
signals:
void folderCreated(const QString& folderId);
void folderUpdated(const QString& folderId);
void folderDeleted(const QString& folderId);
void loginClicked(const QString& domain, const QString& email, const QString& password);
void loginStarted();
void loginFailed();
void loginSuccess();
};

View File

@ -5,8 +5,7 @@
using namespace jop;
Synchronizer::Synchronizer(const QString &apiUrl, Database &database) : api_(apiUrl), db_(database) {
qDebug() << api_.baseUrl();
Synchronizer::Synchronizer(Database &database) : db_(database) {
state_ = Idle;
uploadsRemaining_ = 0;
connect(&api_, SIGNAL(requestDone(QJsonObject,QString)), this, SLOT(api_requestDone(QJsonObject,QString)));

View File

@ -16,7 +16,7 @@ public:
enum SynchronizationState { Idle, UploadingChanges, DownloadingChanges };
Synchronizer(const QString& apiUrl, Database& database);
Synchronizer(Database& database);
void start();
void setSessionId(const QString& v);

View File

@ -4,8 +4,8 @@
using namespace jop;
WebApi::WebApi(const QString &baseUrl) {
baseUrl_ = baseUrl;
WebApi::WebApi() {
baseUrl_ = "";
sessionId_ = "";
connect(&manager_, SIGNAL(finished(QNetworkReply*)), this, SLOT(request_finished(QNetworkReply*)));
}
@ -15,6 +15,14 @@ QString WebApi::baseUrl() const {
}
void WebApi::execRequest(HttpMethod method, const QString &path, const QUrlQuery &query, const QUrlQuery &data, const QString& tag) {
if (baseUrl() == "") {
qCritical() << "Trying to execute request before base URL has been set";
QJsonObject obj;
obj["error"] = "Trying to execute request before base URL has been set";
emit requestDone(obj, tag);
return;
}
QueuedRequest r;
r.method = method;
r.path = path;
@ -136,3 +144,7 @@ void WebApi::request_finished(QNetworkReply *reply) {
void WebApi::request_error(QNetworkReply::NetworkError e) {
qDebug() << "Network error" << e;
}
void jop::WebApi::setBaseUrl(const QString &v) {
baseUrl_ = v;
}

View File

@ -23,7 +23,8 @@ public:
QBuffer* buffer;
};
WebApi(const QString& baseUrl);
WebApi();
void setBaseUrl(const QString& v);
QString baseUrl() const;
void execRequest(HttpMethod method, const QString& path,const QUrlQuery& query = QUrlQuery(), const QUrlQuery& data = QUrlQuery(), const QString& tag = "");
void post(const QString& path,const QUrlQuery& query = QUrlQuery(), const QUrlQuery& data = QUrlQuery(), const QString& tag = "");

View File

@ -0,0 +1,11 @@
#include "window.h"
using namespace jop;
Window::Window() : QQuickView() {}
void Window::showPage(const QString &pageName) {
QVariant pageNameV(pageName);
QVariant returnedValue;
QMetaObject::invokeMethod((QObject*)rootObject(), "showPage", Q_RETURN_ARG(QVariant, returnedValue), Q_ARG(QVariant, pageNameV));
}

View File

@ -0,0 +1,21 @@
#ifndef WINDOW_H
#define WINDOW_H
#include <stable.h>
namespace jop {
class Window : public QQuickView {
Q_OBJECT
public:
Window();
void showPage(const QString& pageName);
};
}
#endif // WINDOW_H