More work on the user manager

This commit is contained in:
Michael Zanetti 2020-02-04 11:35:25 +01:00
parent 0d41958b5b
commit 1c10ee5334
14 changed files with 282 additions and 270 deletions

View File

@ -38,7 +38,6 @@
#include "connection/awsclient.h"
#include "system/systemcontroller.h"
#include "configuration/networkmanager.h"
#include "usersmanager.h"
#include "connection/tcpsockettransport.h"
#include "connection/websockettransport.h"
@ -55,8 +54,7 @@ Engine::Engine(QObject *parent) :
m_logManager(new LogManager(m_jsonRpcClient, this)),
m_tagsManager(new TagsManager(m_jsonRpcClient, this)),
m_nymeaConfiguration(new NymeaConfiguration(m_jsonRpcClient, this)),
m_systemController(new SystemController(m_jsonRpcClient, this)),
m_usersManager(new UsersManager(m_jsonRpcClient, this))
m_systemController(new SystemController(m_jsonRpcClient, this))
{
m_connection->registerTransport(new TcpSocketTransportFactory());
m_connection->registerTransport(new WebsocketTransportFactory());
@ -124,11 +122,6 @@ SystemController *Engine::systemController() const
return m_systemController;
}
UsersManager *Engine::usersManager() const
{
return m_usersManager;
}
void Engine::deployCertificate()
{
if (!m_jsonRpcClient->connected()) {

View File

@ -45,7 +45,6 @@ class TagsManager;
class NymeaConfiguration;
class SystemController;
class NetworkManager;
class UsersManager;
class Engine : public QObject
{
@ -58,7 +57,6 @@ class Engine : public QObject
Q_PROPERTY(JsonRpcClient* jsonRpcClient READ jsonRpcClient CONSTANT)
Q_PROPERTY(NymeaConfiguration* nymeaConfiguration READ nymeaConfiguration CONSTANT)
Q_PROPERTY(SystemController* systemController READ systemController CONSTANT)
Q_PROPERTY(UsersManager* usersManager READ usersManager CONSTANT)
public:
explicit Engine(QObject *parent = nullptr);
@ -75,7 +73,6 @@ public:
LogManager *logManager() const;
NymeaConfiguration *nymeaConfiguration() const;
SystemController *systemController() const;
UsersManager *usersManager() const;
Q_INVOKABLE void deployCertificate();
@ -89,7 +86,6 @@ private:
TagsManager *m_tagsManager;
NymeaConfiguration *m_nymeaConfiguration;
SystemController *m_systemController;
UsersManager *m_usersManager;
private slots:
void onConnectedChanged();

View File

@ -105,6 +105,9 @@
#include "types/script.h"
#include "types/scripts.h"
#include "types/types.h"
#include "usermanager.h"
#include "types/tokeninfos.h"
#include "types/tokeninfo.h"
#include <QtQml/qqml.h>
@ -281,6 +284,10 @@ void registerQmlTypes() {
qmlRegisterType<ScriptSyntaxHighlighter>(uri, 1, 0, "ScriptSyntaxHighlighter");
qmlRegisterType<CodeCompletion>(uri, 1, 0, "CodeCompletion");
qmlRegisterUncreatableType<CompletionProxyModel>(uri, 1, 0, "CompletionModel", "Get it from ScriptSyntaxHighlighter");
qmlRegisterType<UserManager>(uri, 1, 0, "UserManager");
qmlRegisterUncreatableType<TokenInfos>(uri, 1, 0, "TokenInfos", "Get it from UserManager");
qmlRegisterUncreatableType<TokenInfo>(uri, 1, 0, "TokenInfo", "Get it from TokenInfos");
}
#endif // LIBNYMEAAPPCORE_H

View File

@ -55,6 +55,7 @@ SOURCES += \
scripting/completionmodel.cpp \
scriptmanager.cpp \
scriptsyntaxhighlighter.cpp \
usermanager.cpp \
vendorsproxy.cpp \
pluginsproxy.cpp \
interfacesmodel.cpp \
@ -90,7 +91,6 @@ SOURCES += \
configuration/mqttpolicies.cpp \
models/devicemodel.cpp \
system/systemcontroller.cpp \
usersmanager.cpp \
HEADERS += \
@ -124,6 +124,7 @@ HEADERS += \
scripting/completionmodel.h \
scriptmanager.h \
scriptsyntaxhighlighter.h \
usermanager.h \
vendorsproxy.h \
pluginsproxy.h \
interfacesmodel.h \
@ -159,7 +160,6 @@ HEADERS += \
configuration/mqttpolicies.h \
models/devicemodel.h \
system/systemcontroller.h \
usersmanager.h \
ubports: {
DEFINES += UBPORTS

View File

@ -0,0 +1,64 @@
#include "usermanager.h"
#include "types/tokeninfo.h"
#include <QDebug>
UserManager::UserManager(QObject *parent):
JsonHandler(parent)
{
m_tokenInfos = new TokenInfos(this);
}
Engine *UserManager::engine() const
{
return m_engine;
}
void UserManager::setEngine(Engine *engine)
{
if (m_engine != engine) {
m_engine = engine;
m_engine->jsonRpcClient()->registerNotificationHandler(this, "notificationReceived");
emit engineChanged();
m_loading = true;
emit loadingChanged();
m_engine->jsonRpcClient()->sendCommand("Users.GetTokens", QVariantMap(), this, "getTokensReply");
}
}
bool UserManager::loading() const
{
return m_loading;
}
TokenInfos *UserManager::tokenInfos() const
{
return m_tokenInfos;
}
QString UserManager::nameSpace() const
{
return "Users";
}
void UserManager::notificationReceived(const QVariantMap &data)
{
qDebug() << "Users notification" << data;
}
void UserManager::getTokensReply(const QVariantMap &params)
{
foreach (const QVariant &tokenVariant, params.value("params").toMap().value("tokenInfoList").toList()) {
qDebug() << "Token received" << tokenVariant.toMap();
QVariantMap token = tokenVariant.toMap();
QUuid id = token.value("id").toString();
QString username = token.value("username").toString();
QString deviceName = token.value("deviceName").toString();
QDateTime creationTime = QDateTime::fromSecsSinceEpoch(token.value("creationTime").toInt());
TokenInfo *tokenInfo = new TokenInfo(id, username, deviceName, creationTime);
m_tokenInfos->addToken(tokenInfo);
}
}

View File

@ -0,0 +1,47 @@
#ifndef USERMANAGER_H
#define USERMANAGER_H
#include <QObject>
#include "jsonrpc/jsonrpcclient.h"
#include "engine.h"
#include "types/tokeninfos.h"
class UserManager: public JsonHandler
{
Q_OBJECT
Q_PROPERTY(Engine* engine READ engine WRITE setEngine NOTIFY engineChanged)
Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged)
Q_PROPERTY(TokenInfos* tokenInfos READ tokenInfos CONSTANT)
public:
explicit UserManager(QObject *parent = nullptr);
Engine* engine() const;
void setEngine(Engine* engine);
bool loading() const;
TokenInfos* tokenInfos() const;
QString nameSpace() const override;
signals:
void engineChanged();
void loadingChanged();
private slots:
void notificationReceived(const QVariantMap &data);
void getTokensReply(const QVariantMap &params);
private:
Engine *m_engine = nullptr;
bool m_loading = false;
TokenInfos *m_tokenInfos = nullptr;
};
#endif // USERMANAGER_H

View File

@ -1,20 +0,0 @@
#include "usersmanager.h"
#include <QDebug>
UsersManager::UsersManager(JsonRpcClient *client, QObject *parent):
JsonHandler(parent),
m_jsonRpcClient(client)
{
m_jsonRpcClient->registerNotificationHandler(this, "notificationReceived");
}
QString UsersManager::nameSpace() const
{
return "Users";
}
void UsersManager::notificationReceived(const QVariantMap &data)
{
qDebug() << "Users notification" << data;
}

View File

@ -1,23 +0,0 @@
#ifndef USERSMANAGER_H
#define USERSMANAGER_H
#include <QObject>
#include "jsonrpc/jsonrpcclient.h"
class UsersManager: public JsonHandler
{
Q_OBJECT
public:
explicit UsersManager(JsonRpcClient *client, QObject *parent = nullptr);
QString nameSpace() const override;
private slots:
void notificationReceived(const QVariantMap &data);
private:
JsonRpcClient *m_jsonRpcClient = nullptr;
};
#endif // USERSMANAGER_H

View File

@ -64,6 +64,9 @@ HEADERS += \
types/tags.h \
types/wirelessaccesspoint.h \
types/wirelessaccesspoints.h \
types/tokeninfo.h \
types/tokeninfos.h \
SOURCES += \
types/browseritem.cpp \
@ -122,3 +125,7 @@ SOURCES += \
types/tags.cpp \
types/wirelessaccesspoint.cpp \
types/wirelessaccesspoints.cpp \
types/tokeninfo.cpp \
types/tokeninfos.cpp \

View File

@ -0,0 +1,31 @@
#include "tokeninfo.h"
TokenInfo::TokenInfo(const QUuid &id, const QString &username, const QString &deviceName, const QDateTime &creationTime, QObject *parent):
QObject(parent),
m_id(id),
m_username(username),
m_deviceName(deviceName),
m_creationTime(creationTime)
{
}
QUuid TokenInfo::id() const
{
return m_id;
}
QString TokenInfo::username() const
{
return m_username;
}
QString TokenInfo::deviceName() const
{
return m_deviceName;
}
QDateTime TokenInfo::creationTime() const
{
return m_creationTime;
}

View File

@ -0,0 +1,26 @@
#ifndef TOKENINFO_H
#define TOKENINFO_H
#include <QObject>
#include <QUuid>
#include <QDateTime>
class TokenInfo : public QObject
{
Q_OBJECT
public:
explicit TokenInfo(const QUuid &id, const QString &username, const QString &deviceName, const QDateTime &creationTime, QObject *parent = nullptr);
QUuid id() const;
QString username() const;
QString deviceName() const;
QDateTime creationTime() const;
private:
QUuid m_id;
QString m_username;
QString m_deviceName;
QDateTime m_creationTime;
};
#endif // TOKENINFO_H

View File

@ -0,0 +1,47 @@
#include "tokeninfos.h"
#include "tokeninfo.h"
TokenInfos::TokenInfos(QObject *parent) : QAbstractListModel(parent)
{
}
int TokenInfos::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_list.count();
}
QVariant TokenInfos::data(const QModelIndex &index, int role) const
{
switch (role) {
case RoleId:
return m_list.at(index.row())->id();
case RoleUsername:
return m_list.at(index.row())->username();
case RoleDeviceName:
return m_list.at(index.row())->deviceName();
case RoleCreationTime:
return m_list.at(index.row())->creationTime();
}
return QVariant();
}
QHash<int, QByteArray> TokenInfos::roleNames() const
{
QHash<int, QByteArray> roles;
roles.insert(RoleId, "id");
roles.insert(RoleUsername, "username");
roles.insert(RoleDeviceName, "deviceName");
roles.insert(RoleCreationTime, "creationTime");
return roles;
}
void TokenInfos::addToken(TokenInfo *tokenInfo)
{
tokenInfo->setParent(this);
beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
m_list.append(tokenInfo);
endInsertRows();
emit countChanged();
}

View File

@ -0,0 +1,34 @@
#ifndef TOKENINFOS_H
#define TOKENINFOS_H
#include <QAbstractListModel>
class TokenInfo;
class TokenInfos : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
public:
enum Roles {
RoleId,
RoleUsername,
RoleDeviceName,
RoleCreationTime
};
explicit TokenInfos(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
QHash<int, QByteArray> roleNames() const override;
void addToken(TokenInfo *tokenInfo);
signals:
void countChanged();
private:
QList<TokenInfo*> m_list;
};
#endif // TOKENINFOS_H

View File

@ -8,230 +8,33 @@ import "../components"
Page {
id: root
header: NymeaHeader {
text: qsTr("Authentication")
text: qsTr("Authentication") + userManager.tokenInfos.count
backButtonVisible: true
onBackPressed: pageStack.pop()
}
UserManager {
id: userManager
engine: _engine
}
ColumnLayout {
id: settingsGrid
anchors { horizontalCenter: parent.horizontalCenter; top: parent.top; margins: app.margins }
width: Math.min(500, parent.width - app.margins * 2)
anchors.fill: parent
// width: Math.min(500, parent.width - app.margins * 2)
RowLayout {
ListView {
Layout.fillWidth: true
spacing: app.margins
Label {
text: qsTr("Name")
}
TextField {
id: nameTextField
Layout.fillWidth: true
text: engine.nymeaConfiguration.serverName
}
Button {
text: qsTr("OK")
visible: nameTextField.displayText !== engine.nymeaConfiguration.serverName
onClicked: engine.nymeaConfiguration.serverName = nameTextField.displayText
}
}
Layout.fillHeight: true
model: userManager.tokenInfos
RowLayout {
Layout.fillWidth: true
visible: engine.jsonRpcClient.ensureServerVersion("4.1") && engine.systemController.automaticTimeAvailable
Label {
text: qsTr("Set date and time automatically")
Layout.fillWidth: true
}
CheckBox {
checked: engine.systemController.automaticTime
onClicked: {
engine.systemController.automaticTime = checked
}
}
}
RowLayout {
Layout.fillWidth: true
spacing: app.margins
Layout.preferredHeight: dateButton.implicitHeight
visible: engine.jsonRpcClient.ensureServerVersion("4.1")
Label {
text: qsTr("Date")
Layout.fillWidth: true
}
Label {
text: engine.systemController.serverTime.toLocaleDateString()
Layout.fillWidth: true
horizontalAlignment: Text.AlignRight
}
Button {
id: dateButton
visible: !engine.systemController.automaticTime && engine.systemController.timeManagementAvailable
contentItem: Item {
ColorIcon {
name: "../images/edit.svg"
color: app.foregroundColor
anchors.centerIn: parent
height: parent.height
width: height
}
}
onClicked: {
var popup = datePickerComponent.createObject(root, {dateTime: engine.systemController.serverTime})
popup.accepted.connect(function() {
print("setting new date", popup.dateTime)
engine.systemController.serverTime = popup.dateTime
})
popup.open();
}
}
}
RowLayout {
Layout.fillWidth: true
spacing: app.margins
Layout.preferredHeight: timeButton.implicitHeight
visible: engine.jsonRpcClient.ensureServerVersion("4.1")
Label {
text: qsTr("Time")
Layout.fillWidth: true
}
Label {
text: engine.systemController.serverTime.toLocaleTimeString(/*Locale.ShortTimeString*/)
Layout.fillWidth: true
horizontalAlignment: Text.AlignRight
}
Button {
id: timeButton
visible: !engine.systemController.automaticTime && engine.systemController.timeManagementAvailable
contentItem: Item {
ColorIcon {
name: "../images/edit.svg"
color: app.foregroundColor
anchors.centerIn: parent
height: parent.height
width: height
}
}
onClicked: {
var popup = timePickerComponent.createObject(root, {hour: engine.systemController.serverTime.getHours(), minute: engine.systemController.serverTime.getMinutes()})
popup.accepted.connect(function() {
var date = new Date(engine.systemController.serverTime)
date.setHours(popup.hour);
date.setMinutes(popup.minute)
engine.systemController.serverTime = date;
})
popup.open();
}
}
}
RowLayout {
Layout.fillWidth: true
spacing: app.margins
visible: engine.jsonRpcClient.ensureServerVersion("4.1")
Label {
Layout.fillWidth: true
text: qsTr("Time zone")
}
ComboBox {
Layout.minimumWidth: 200
model: engine.systemController.timeZones
currentIndex: model.indexOf(engine.systemController.serverTimeZone)
onActivated: {
engine.systemController.serverTimeZone = currentText;
}
}
}
Button {
Layout.fillWidth: true
text: qsTr("Reboot %1:core").arg(app.systemName)
visible: engine.systemController.powerManagementAvailable
onClicked: {
var dialog = Qt.createComponent(Qt.resolvedUrl("../components/MeaDialog.qml"));
var text = qsTr("Are you sure you want to reboot your %1:core sytem now?").arg(app.systemName)
var popup = dialog.createObject(app,
{
headerIcon: "../images/dialog-warning-symbolic.svg",
title: qsTr("Reboot %1:core").arg(app.systemName),
text: text,
standardButtons: Dialog.Ok | Dialog.Cancel
});
popup.open();
popup.accepted.connect(function() {
engine.systemController.reboot()
})
}
}
Button {
Layout.fillWidth: true
text: qsTr("Shutdown %1:core").arg(app.systemName)
visible: engine.systemController.powerManagementAvailable
onClicked: {
var dialog = Qt.createComponent(Qt.resolvedUrl("../components/MeaDialog.qml"));
var text = qsTr("Are you sure you want to shut down your %1:core sytem now?").arg(app.systemName)
var popup = dialog.createObject(app,
{
headerIcon: "../images/dialog-warning-symbolic.svg",
title: qsTr("Shut down %1:core").arg(app.systemName),
text: text,
standardButtons: Dialog.Ok | Dialog.Cancel
});
popup.open();
popup.accepted.connect(function() {
engine.systemController.shutdown()
})
}
}
}
Component {
id: timePickerComponent
Dialog {
id: timePicker
property int maxSize: Math.min(parent.width, parent.height)
property int size: Math.min(maxSize, 500)
property alias hour: p.hour
property alias minute: p.minute
width: size - 80
height: size
x: (parent.width - width) / 2
y: (parent.height - height) / 2
TimePicker {
id: p
delegate: NymeaListItemDelegate {
width: parent.width
height: parent.height
text: model.deviceName
subText: qsTr("Created on %1").arg(Qt.formatDateTime(model.creationTime, Qt.DefaultLocaleShortDate))
prominentSubText: false
progressive: false
}
standardButtons: Dialog.Ok | Dialog.Cancel
}
}
Component {
id: datePickerComponent
Dialog {
id: datePicker
property int maxSize: Math.min(parent.width, parent.height)
property int size: Math.min(maxSize, 500)
property alias dateTime: p.date
width: size - 80
height: size
x: (parent.width - width) / 2
y: (parent.height - height) / 2
DatePicker {
id: p
width: parent.width
height: parent.height
date: datePicker.dateTime
}
standardButtons: Dialog.Ok | Dialog.Cancel
}
}
}