some experiments about sending form
This commit is contained in:
parent
be3d8b0e77
commit
c966d95058
110
API/api.cpp
110
API/api.cpp
@ -2,8 +2,10 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
#include <QUrlQuery>
|
||||||
|
|
||||||
constexpr const char* json = "application/json";
|
constexpr const char* json = "application/json";
|
||||||
|
constexpr const char* urlEncoded = "application/x-www-form-urlencoded";
|
||||||
|
|
||||||
struct NetworkReplyDeleter {
|
struct NetworkReplyDeleter {
|
||||||
void operator () (QNetworkReply* reply) {
|
void operator () (QNetworkReply* reply) {
|
||||||
@ -14,23 +16,53 @@ struct NetworkReplyDeleter {
|
|||||||
API::API(const QUrl& address, QObject* parent):
|
API::API(const QUrl& address, QObject* parent):
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
address(address),
|
address(address),
|
||||||
network()
|
network(),
|
||||||
{
|
state(NoServer)
|
||||||
|
{}
|
||||||
|
|
||||||
|
QUrl API::getAddress() const {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
API::State API::getState() const {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void API::setAddress(const QUrl& path) {
|
||||||
|
if (address == path)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (state == Authenticated) {
|
||||||
|
//do something
|
||||||
|
}
|
||||||
|
|
||||||
|
address = path;
|
||||||
|
state = address.isEmpty() ? NoServer : NotAuthenticated;
|
||||||
|
|
||||||
|
emit addressChanged(address);
|
||||||
|
emit stateChanged(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void API::test(const QString& path, const QJSValue& finished) {
|
void API::test(const QString& path, const QJSValue& finished) {
|
||||||
qDebug() << "Testing" << path;
|
qDebug() << "Testing" << path;
|
||||||
|
|
||||||
|
if (state == Offline) {
|
||||||
|
QString err = "Need to be online to test";
|
||||||
|
qDebug() << "Test for" << path << "failed:" << err;
|
||||||
|
callCallback(finished, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QNetworkRequest request(path + "/info");
|
QNetworkRequest request(path + "/info");
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, json);
|
request.setHeader(QNetworkRequest::ContentTypeHeader, json);
|
||||||
|
|
||||||
QNetworkReply* reply = network.get(request);
|
QNetworkReply* reply = network.get(request);
|
||||||
connect(reply, &QNetworkReply::finished,
|
connect(reply, &QNetworkReply::finished,
|
||||||
std::bind(&API::onTestSuccess, this, reply, finished)
|
std::bind(&API::onTestFinished, this, reply, finished)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void API::onTestSuccess(QNetworkReply* reply, const QJSValue& finished) const {
|
void API::onTestFinished(QNetworkReply* reply, const QJSValue& finished) const {
|
||||||
std::unique_ptr<QNetworkReply, NetworkReplyDeleter> rpl(reply);
|
std::unique_ptr<QNetworkReply, NetworkReplyDeleter> rpl(reply);
|
||||||
QNetworkReply::NetworkError error = reply->error();
|
QNetworkReply::NetworkError error = reply->error();
|
||||||
if (error != QNetworkReply::NoError) {
|
if (error != QNetworkReply::NoError) {
|
||||||
@ -65,7 +97,7 @@ void API::onTestSuccess(QNetworkReply* reply, const QJSValue& finished) const {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type.toString() != "Pica") {
|
if (type.toString() != "pica") {
|
||||||
QString err("server of this type (" + type.toString() + ") is not supported");
|
QString err("server of this type (" + type.toString() + ") is not supported");
|
||||||
qDebug() << "Test for" << reply->url() << "failed:" << err;
|
qDebug() << "Test for" << reply->url() << "failed:" << err;
|
||||||
callCallback(finished, err);
|
callCallback(finished, err);
|
||||||
@ -82,6 +114,74 @@ void API::onTestSuccess(QNetworkReply* reply, const QJSValue& finished) const {
|
|||||||
callCallback(finished, QString(), {QJSValue(true)});
|
callCallback(finished, QString(), {QJSValue(true)});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void API::sendRegister(const QString& login, const QString& password, const QJSValue &finished) {
|
||||||
|
qDebug() << "Registering...";
|
||||||
|
|
||||||
|
if (state != NotAuthenticated) {
|
||||||
|
QString err = "Can not register in current state";
|
||||||
|
qDebug() << "Register failed:" << err;
|
||||||
|
callCallback(finished, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrlQuery params({
|
||||||
|
{"login", login},
|
||||||
|
{"password", password}
|
||||||
|
});
|
||||||
|
|
||||||
|
QNetworkRequest request(address.path() + "/register");
|
||||||
|
request.setHeader(QNetworkRequest::ContentTypeHeader, urlEncoded);
|
||||||
|
|
||||||
|
QNetworkReply* reply = network.post(request, params.toString(QUrl::FullyEncoded).toUtf8());
|
||||||
|
connect(reply, &QNetworkReply::finished,
|
||||||
|
std::bind(&API::onRegisterFinished, this, reply, finished)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void API::onRegisterFinished(QNetworkReply *reply, const QJSValue &finished) const {
|
||||||
|
std::unique_ptr<QNetworkReply, NetworkReplyDeleter> rpl(reply);
|
||||||
|
QNetworkReply::NetworkError error = reply->error();
|
||||||
|
if (error != QNetworkReply::NoError) {
|
||||||
|
QString err = reply->errorString();
|
||||||
|
qDebug() << "Register failed:" << err;
|
||||||
|
callCallback(finished, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant contentType = reply->header(QNetworkRequest::ContentTypeHeader);
|
||||||
|
if (!
|
||||||
|
contentType.isValid() ||
|
||||||
|
!contentType.canConvert<QString>() ||
|
||||||
|
contentType.toString() != json
|
||||||
|
) {
|
||||||
|
QString err("wrong response content type");
|
||||||
|
qDebug() << "Register failed:" << err;
|
||||||
|
callCallback(finished, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray data = reply->readAll();
|
||||||
|
QJsonDocument document = QJsonDocument::fromJson(data);
|
||||||
|
QJsonObject rootObj = document.object();
|
||||||
|
|
||||||
|
QJsonValue result = rootObj.value("result");
|
||||||
|
if (!result.isString()) {
|
||||||
|
QString err("malformed json");
|
||||||
|
qDebug() << "Register failed:" << err;
|
||||||
|
callCallback(finished, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.toString() != "ok") {
|
||||||
|
QString err("Registration result was not okay");
|
||||||
|
qDebug() << "Register failed:" << err;
|
||||||
|
callCallback(finished, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
callCallback(finished, QString(), {QJSValue(true)});
|
||||||
|
}
|
||||||
|
|
||||||
void API::callCallback(const QJSValue& callback, const QString& error, const QJSValueList& arguments) const {
|
void API::callCallback(const QJSValue& callback, const QString& error, const QJSValueList& arguments) const {
|
||||||
if (callback.isCallable()) {
|
if (callback.isCallable()) {
|
||||||
if (error.isEmpty())
|
if (error.isEmpty())
|
||||||
|
25
API/api.h
25
API/api.h
@ -11,13 +11,33 @@
|
|||||||
|
|
||||||
class API : public QObject {
|
class API : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
enum State {Offline, NoServer, NotAuthenticated, Authenticated};
|
||||||
|
Q_ENUM(State)
|
||||||
|
|
||||||
|
private:
|
||||||
|
Q_PROPERTY(QUrl address READ getAddress WRITE setAddress NOTIFY addressChanged)
|
||||||
|
Q_PROPERTY(State state READ getState NOTIFY stateChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit API(const QUrl& path = QString(), QObject* parent = nullptr);
|
explicit API(const QUrl& path = QString(), QObject* parent = nullptr);
|
||||||
|
|
||||||
Q_INVOKABLE void test(const QString& path, const QJSValue& finished = QJSValue());
|
QUrl getAddress() const;
|
||||||
|
State getState() const;
|
||||||
|
|
||||||
|
void setAddress(const QUrl& path);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void addressChanged(const QUrl& path);
|
||||||
|
void stateChanged(State state);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void test(const QString& path, const QJSValue& finished = QJSValue());
|
||||||
|
void sendRegister(const QString& login, const QString& password, const QJSValue& finished = QJSValue());
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onTestSuccess(QNetworkReply* reply, const QJSValue& finished) const;
|
void onTestFinished(QNetworkReply* reply, const QJSValue& finished) const;
|
||||||
|
void onRegisterFinished(QNetworkReply* reply, const QJSValue& finished) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void callCallback(const QJSValue& callback, const QString& error = QString(), const QJSValueList& arguments = QJSValueList()) const;
|
void callCallback(const QJSValue& callback, const QString& error = QString(), const QJSValueList& arguments = QJSValueList()) const;
|
||||||
@ -25,4 +45,5 @@ private:
|
|||||||
private:
|
private:
|
||||||
QUrl address;
|
QUrl address;
|
||||||
QNetworkAccessManager network;
|
QNetworkAccessManager network;
|
||||||
|
State state;
|
||||||
};
|
};
|
||||||
|
@ -2,6 +2,8 @@ import QtQuick
|
|||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
import API
|
||||||
|
|
||||||
Page {
|
Page {
|
||||||
property string address
|
property string address
|
||||||
property bool valid: false
|
property bool valid: false
|
||||||
|
158
qml/Welcome.qml
158
qml/Welcome.qml
@ -2,9 +2,9 @@ import QtQuick
|
|||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
Page {
|
import API
|
||||||
property string serverAddress
|
|
||||||
|
|
||||||
|
Page {
|
||||||
signal pickServer(address: string)
|
signal pickServer(address: string)
|
||||||
|
|
||||||
title: qsTr("Welcome")
|
title: qsTr("Welcome")
|
||||||
@ -32,7 +32,7 @@ Page {
|
|||||||
}
|
}
|
||||||
Label {
|
Label {
|
||||||
horizontalAlignment: Label.AlignLeft
|
horizontalAlignment: Label.AlignLeft
|
||||||
text: serverAddress || qsTr("choose")
|
text: API.state === API.NoServer ? qsTr("choose") : API.address
|
||||||
font {
|
font {
|
||||||
italic: true
|
italic: true
|
||||||
underline: true
|
underline: true
|
||||||
@ -40,7 +40,157 @@ Page {
|
|||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: pickServer(serverAddress)
|
onClicked: pickServer(API.address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: forms
|
||||||
|
property bool registering: false
|
||||||
|
|
||||||
|
visible: API.state === API.NotAuthenticated
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
topPadding: 10
|
||||||
|
|
||||||
|
Column {
|
||||||
|
visible: forms.registering === false
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
Label {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
text: qsTr("Please, log in to your account")
|
||||||
|
font {
|
||||||
|
pixelSize: 14
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Grid {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
columns: 2
|
||||||
|
columnSpacing: 10
|
||||||
|
rowSpacing: 5
|
||||||
|
verticalItemAlignment: Grid.AlignVCenter
|
||||||
|
horizontalItemAlignment: Grid.AlignRight
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: qsTr("Login") + ":";
|
||||||
|
}
|
||||||
|
|
||||||
|
TextField {
|
||||||
|
id: login
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: qsTr("Password") + ":";
|
||||||
|
}
|
||||||
|
|
||||||
|
TextField {
|
||||||
|
id: password
|
||||||
|
echoMode: TextField.Password
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
text: qsTr("Login")
|
||||||
|
onClicked: function () {
|
||||||
|
console.log("Not implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
spacing: 5
|
||||||
|
topPadding: 10
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: qsTr("Don't have account?")
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
text: qsTr("Sign up") + "!"
|
||||||
|
font {
|
||||||
|
italic: true
|
||||||
|
underline: true
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: forms.registering = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
visible: forms.registering === true
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
Label {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
text: qsTr("Please, chose login and password")
|
||||||
|
font {
|
||||||
|
pixelSize: 14
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Grid {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
columns: 2
|
||||||
|
columnSpacing: 10
|
||||||
|
rowSpacing: 5
|
||||||
|
verticalItemAlignment: Grid.AlignVCenter
|
||||||
|
horizontalItemAlignment: Grid.AlignRight
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: qsTr("Login") + ":";
|
||||||
|
}
|
||||||
|
|
||||||
|
TextField {
|
||||||
|
id: newLogin
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: qsTr("Password") + ":";
|
||||||
|
}
|
||||||
|
|
||||||
|
TextField {
|
||||||
|
id: newPassword
|
||||||
|
echoMode: TextField.Password
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
text: qsTr("Register")
|
||||||
|
onClicked: API.sendRegister(newLogin.text, newPassword.text, function (err, result) {
|
||||||
|
if (err)
|
||||||
|
console.error("err")
|
||||||
|
|
||||||
|
console.log(result);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
spacing: 5
|
||||||
|
topPadding: 10
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: qsTr("Already have an account?")
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
text: qsTr("Log in") + "!"
|
||||||
|
font {
|
||||||
|
italic: true
|
||||||
|
underline: true
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: forms.registering = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
10
qml/main.qml
10
qml/main.qml
@ -4,6 +4,7 @@ import QtQuick.Controls
|
|||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import QtCore
|
import QtCore
|
||||||
|
|
||||||
|
import API
|
||||||
|
|
||||||
ApplicationWindow {
|
ApplicationWindow {
|
||||||
property int counter: 0
|
property int counter: 0
|
||||||
@ -27,25 +28,18 @@ ApplicationWindow {
|
|||||||
|
|
||||||
Welcome {
|
Welcome {
|
||||||
id: welcome
|
id: welcome
|
||||||
serverAddress: settings.serverAddress
|
|
||||||
onPickServer: function (address) {
|
onPickServer: function (address) {
|
||||||
pick.address = address;
|
pick.address = address;
|
||||||
stack.push(pick)
|
stack.push(pick)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings {
|
|
||||||
id: settings
|
|
||||||
|
|
||||||
property string serverAddress
|
|
||||||
}
|
|
||||||
|
|
||||||
ServerPick {
|
ServerPick {
|
||||||
visible: false
|
visible: false
|
||||||
id: pick
|
id: pick
|
||||||
onBack: stack.pop()
|
onBack: stack.pop()
|
||||||
onSuccess: function (address) {
|
onSuccess: function (address) {
|
||||||
settings.serverAddress = address;
|
API.address = address
|
||||||
stack.pop();
|
stack.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
19
root.cpp
19
root.cpp
@ -1,5 +1,7 @@
|
|||||||
#include "root.h"
|
#include "root.h"
|
||||||
|
|
||||||
|
#include <QSettings>
|
||||||
|
|
||||||
Root::Root(const QUrl& root, int& argc, char* argv[]) :
|
Root::Root(const QUrl& root, int& argc, char* argv[]) :
|
||||||
QGuiApplication(argc, argv),
|
QGuiApplication(argc, argv),
|
||||||
root(root),
|
root(root),
|
||||||
@ -21,11 +23,19 @@ Root::Root(const QUrl& root, int& argc, char* argv[]) :
|
|||||||
Qt::QueuedConnection
|
Qt::QueuedConnection
|
||||||
);
|
);
|
||||||
|
|
||||||
|
QSettings settings;
|
||||||
|
api.setAddress(settings.value("address").toUrl());
|
||||||
|
|
||||||
|
qRegisterMetaType<API>("API");
|
||||||
|
connect(&api, &API::addressChanged, this, &Root::onAPIAddressChanged);
|
||||||
|
|
||||||
|
qmlRegisterSingletonType<API>("API", 1, 0, "API", [this] (QQmlEngine *engine, QJSEngine *scriptEngine) {
|
||||||
|
return &api;
|
||||||
|
});
|
||||||
|
|
||||||
engine.load(root);
|
engine.load(root);
|
||||||
if (engine.rootObjects().isEmpty())
|
if (engine.rootObjects().isEmpty())
|
||||||
throw std::runtime_error("Couldn't looad root qml object");
|
throw std::runtime_error("Couldn't looad root qml object");
|
||||||
|
|
||||||
context->setContextProperty("API", &api);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Root::~Root() {
|
Root::~Root() {
|
||||||
@ -52,3 +62,8 @@ void Root::onObjectCreated(QObject* obj, const QUrl& objUrl) {
|
|||||||
if (!obj && objUrl == root)
|
if (!obj && objUrl == root)
|
||||||
exit(-2);
|
exit(-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Root::onAPIAddressChanged(const QUrl& url) {
|
||||||
|
QSettings settings;
|
||||||
|
settings.setValue("address", url);
|
||||||
|
}
|
||||||
|
2
root.h
2
root.h
@ -4,6 +4,7 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QUrl>
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QQmlApplicationEngine>
|
#include <QQmlApplicationEngine>
|
||||||
#include <QQmlContext>
|
#include <QQmlContext>
|
||||||
@ -19,6 +20,7 @@ public:
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onObjectCreated(QObject* obj, const QUrl& objUrl);
|
void onObjectCreated(QObject* obj, const QUrl& objUrl);
|
||||||
|
void onAPIAddressChanged(const QUrl& url);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QUrl root;
|
QUrl root;
|
||||||
|
Loading…
Reference in New Issue
Block a user