chore(cpp): apply clang-format
This commit is contained in:
parent
1dcc3a1f2f
commit
c53264b124
|
@ -2,14 +2,13 @@
|
|||
|
||||
#include <QtQml/QQmlEngine>
|
||||
|
||||
namespace Status::Application {
|
||||
|
||||
ApplicationController::ApplicationController(QObject *parent)
|
||||
: QObject{parent}
|
||||
, m_dataProvider(std::make_unique<DataProvider>())
|
||||
namespace Status::Application
|
||||
{
|
||||
|
||||
}
|
||||
ApplicationController::ApplicationController(QObject* parent)
|
||||
: QObject{parent}
|
||||
, m_dataProvider(std::make_unique<DataProvider>())
|
||||
{ }
|
||||
|
||||
void ApplicationController::initOnLogin()
|
||||
{
|
||||
|
@ -17,23 +16,22 @@ void ApplicationController::initOnLogin()
|
|||
m_dbSettings = std::make_shared<DbSettingsObj>(dbSettings);
|
||||
}
|
||||
|
||||
QObject *ApplicationController::dbSettings() const
|
||||
QObject* ApplicationController::dbSettings() const
|
||||
{
|
||||
return m_dbSettings.get();
|
||||
}
|
||||
|
||||
QObject *ApplicationController::statusAccount() const
|
||||
QObject* ApplicationController::statusAccount() const
|
||||
{
|
||||
QQmlEngine::setObjectOwnership(m_statusAccount, QQmlEngine::CppOwnership);
|
||||
return m_statusAccount;
|
||||
}
|
||||
|
||||
void ApplicationController::setStatusAccount(QObject *newStatusAccount)
|
||||
void ApplicationController::setStatusAccount(QObject* newStatusAccount)
|
||||
{
|
||||
if (m_statusAccount == newStatusAccount)
|
||||
return;
|
||||
if(m_statusAccount == newStatusAccount) return;
|
||||
m_statusAccount = newStatusAccount;
|
||||
emit statusAccountChanged();
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::Application
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "DbSettingsObj.h"
|
||||
#include "DataProvider.h"
|
||||
#include "DbSettingsObj.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QtQml/qqmlregistration.h>
|
||||
|
@ -9,7 +9,8 @@
|
|||
// TODO: investigate. This line breaks qobject_cast in OnboardingController::login
|
||||
//#include <Onboarding/UserAccount.h>
|
||||
|
||||
namespace Status::Application {
|
||||
namespace Status::Application
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Responsible for providing general information and utility components
|
||||
|
@ -23,12 +24,12 @@ class ApplicationController : public QObject
|
|||
Q_PROPERTY(QObject* dbSettings READ dbSettings CONSTANT)
|
||||
|
||||
public:
|
||||
explicit ApplicationController(QObject *parent = nullptr);
|
||||
explicit ApplicationController(QObject* parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void initOnLogin();
|
||||
|
||||
QObject *statusAccount() const;
|
||||
void setStatusAccount(QObject *newStatusAccount);
|
||||
QObject* statusAccount() const;
|
||||
void setStatusAccount(QObject* newStatusAccount);
|
||||
|
||||
QObject* dbSettings() const;
|
||||
|
||||
|
@ -41,4 +42,4 @@ private:
|
|||
std::shared_ptr<DbSettingsObj> m_dbSettings;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Status::Application
|
||||
|
|
|
@ -6,18 +6,20 @@ namespace StatusGo = Status::StatusGo;
|
|||
|
||||
DataProvider::DataProvider()
|
||||
: QObject(nullptr)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
StatusGo::Settings::SettingsDto DataProvider::getSettings() const
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
return StatusGo::Settings::getSettings();
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
catch(std::exception& e)
|
||||
{
|
||||
qWarning() << "DataProvider::getSettings, error: " << e.what();
|
||||
}
|
||||
catch (...) {
|
||||
catch(...)
|
||||
{
|
||||
qWarning() << "DataProvider::getSettings, unknown error";
|
||||
}
|
||||
return StatusGo::Settings::SettingsDto{};
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include <StatusGo/SettingsAPI>
|
||||
#include <QtCore/QtCore>
|
||||
#include <StatusGo/SettingsAPI>
|
||||
|
||||
namespace Status::Application {
|
||||
namespace Status::Application
|
||||
{
|
||||
|
||||
class DataProvider: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
class DataProvider : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DataProvider();
|
||||
public:
|
||||
DataProvider();
|
||||
|
||||
StatusGo::Settings::SettingsDto getSettings() const;
|
||||
};
|
||||
}
|
||||
StatusGo::Settings::SettingsDto getSettings() const;
|
||||
};
|
||||
} // namespace Status::Application
|
||||
|
|
|
@ -5,8 +5,7 @@ using namespace Status::Application;
|
|||
DbSettingsObj::DbSettingsObj(StatusGo::Settings::SettingsDto rawData)
|
||||
: QObject(nullptr)
|
||||
, m_data(std::move(rawData))
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
QString DbSettingsObj::address() const
|
||||
{
|
||||
|
@ -15,8 +14,7 @@ QString DbSettingsObj::address() const
|
|||
|
||||
void DbSettingsObj::setAddress(const QString& value)
|
||||
{
|
||||
if (m_data.address == value)
|
||||
return;
|
||||
if(m_data.address == value) return;
|
||||
m_data.address = value;
|
||||
emit addressChanged();
|
||||
}
|
||||
|
@ -28,8 +26,7 @@ QString DbSettingsObj::displayName() const
|
|||
|
||||
void DbSettingsObj::setDisplayName(const QString& value)
|
||||
{
|
||||
if (m_data.displayName == value)
|
||||
return;
|
||||
if(m_data.displayName == value) return;
|
||||
m_data.displayName = value;
|
||||
emit displayNameChanged();
|
||||
}
|
||||
|
@ -41,8 +38,7 @@ QString DbSettingsObj::preferredName() const
|
|||
|
||||
void DbSettingsObj::setPreferredName(const QString& value)
|
||||
{
|
||||
if (m_data.preferredName == value)
|
||||
return;
|
||||
if(m_data.preferredName == value) return;
|
||||
m_data.preferredName = value;
|
||||
emit preferredNameChanged();
|
||||
}
|
||||
|
@ -54,8 +50,7 @@ QString DbSettingsObj::keyUid() const
|
|||
|
||||
void DbSettingsObj::setKeyUid(const QString& value)
|
||||
{
|
||||
if (m_data.keyUid == value)
|
||||
return;
|
||||
if(m_data.keyUid == value) return;
|
||||
m_data.keyUid = value;
|
||||
emit keyUidChanged();
|
||||
}
|
||||
|
@ -67,8 +62,7 @@ QString DbSettingsObj::publicKey() const
|
|||
|
||||
void DbSettingsObj::setPublicKey(const QString& value)
|
||||
{
|
||||
if (m_data.publicKey == value)
|
||||
return;
|
||||
if(m_data.publicKey == value) return;
|
||||
m_data.publicKey = value;
|
||||
emit publicKeyChanged();
|
||||
}
|
||||
|
|
|
@ -4,46 +4,45 @@
|
|||
|
||||
#include <QtCore/QtCore>
|
||||
|
||||
namespace Status::Application {
|
||||
namespace Status::Application
|
||||
{
|
||||
|
||||
class DbSettingsObj: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
class DbSettingsObj : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString address READ address NOTIFY addressChanged)
|
||||
Q_PROPERTY(QString displayName READ displayName NOTIFY displayNameChanged)
|
||||
Q_PROPERTY(QString preferredName READ preferredName NOTIFY preferredNameChanged)
|
||||
Q_PROPERTY(QString keyUid READ keyUid NOTIFY keyUidChanged)
|
||||
Q_PROPERTY(QString publicKey READ publicKey NOTIFY publicKeyChanged)
|
||||
Q_PROPERTY(QString address READ address NOTIFY addressChanged)
|
||||
Q_PROPERTY(QString displayName READ displayName NOTIFY displayNameChanged)
|
||||
Q_PROPERTY(QString preferredName READ preferredName NOTIFY preferredNameChanged)
|
||||
Q_PROPERTY(QString keyUid READ keyUid NOTIFY keyUidChanged)
|
||||
Q_PROPERTY(QString publicKey READ publicKey NOTIFY publicKeyChanged)
|
||||
|
||||
public:
|
||||
explicit DbSettingsObj(StatusGo::Settings::SettingsDto rawData);
|
||||
|
||||
public:
|
||||
explicit DbSettingsObj(StatusGo::Settings::SettingsDto rawData);
|
||||
[[nodiscard]] QString address() const;
|
||||
void setAddress(const QString& address);
|
||||
|
||||
[[nodiscard]] QString address() const;
|
||||
void setAddress(const QString& address);
|
||||
[[nodiscard]] QString displayName() const;
|
||||
void setDisplayName(const QString& value);
|
||||
|
||||
[[nodiscard]] QString displayName() const;
|
||||
void setDisplayName(const QString& value);
|
||||
[[nodiscard]] QString preferredName() const;
|
||||
void setPreferredName(const QString& value);
|
||||
|
||||
[[nodiscard]] QString preferredName() const;
|
||||
void setPreferredName(const QString& value);
|
||||
[[nodiscard]] QString keyUid() const;
|
||||
void setKeyUid(const QString& value);
|
||||
|
||||
[[nodiscard]] QString keyUid() const;
|
||||
void setKeyUid(const QString& value);
|
||||
[[nodiscard]] QString publicKey() const;
|
||||
void setPublicKey(const QString& value);
|
||||
|
||||
[[nodiscard]] QString publicKey() const;
|
||||
void setPublicKey(const QString& value);
|
||||
signals:
|
||||
void addressChanged();
|
||||
void displayNameChanged();
|
||||
void preferredNameChanged();
|
||||
void keyUidChanged();
|
||||
void publicKeyChanged();
|
||||
|
||||
|
||||
signals:
|
||||
void addressChanged();
|
||||
void displayNameChanged();
|
||||
void preferredNameChanged();
|
||||
void keyUidChanged();
|
||||
void publicKeyChanged();
|
||||
|
||||
private:
|
||||
StatusGo::Settings::SettingsDto m_data;
|
||||
};
|
||||
}
|
||||
private:
|
||||
StatusGo::Settings::SettingsDto m_data;
|
||||
};
|
||||
} // namespace Status::Application
|
||||
|
|
|
@ -7,26 +7,28 @@
|
|||
#include <Helpers/helpers.h>
|
||||
#include <Helpers/logs.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
|
||||
using namespace Status;
|
||||
|
||||
void setApplicationInformation(QGuiApplication& app);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
//qInstallMessageHandler(Helpers::logFormatter);
|
||||
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
|
||||
setApplicationInformation(app);
|
||||
|
||||
QTranslator translator;
|
||||
const QStringList uiLanguages = QLocale::system().uiLanguages();
|
||||
for (const QString &locale : uiLanguages) {
|
||||
for(const QString& locale : uiLanguages)
|
||||
{
|
||||
const QString baseName = BUILD_PROJECT_NAME + QLocale(locale).name();
|
||||
if (translator.load(":/i18n/" + baseName)) {
|
||||
if(translator.load(":/i18n/" + baseName))
|
||||
{
|
||||
app.installTranslator(&translator);
|
||||
break;
|
||||
}
|
||||
|
@ -35,27 +37,31 @@ int main(int argc, char *argv[])
|
|||
QQmlApplicationEngine engine;
|
||||
|
||||
const QUrl url(u"qrc:/Status/Application/qml/main.qml"_qs);
|
||||
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
|
||||
&app, [url](QObject *obj, const QUrl &objUrl) {
|
||||
if (!obj && url == objUrl)
|
||||
QCoreApplication::exit(-1);
|
||||
}, Qt::QueuedConnection);
|
||||
QObject::connect(
|
||||
&engine,
|
||||
&QQmlApplicationEngine::objectCreated,
|
||||
&app,
|
||||
[url](QObject* obj, const QUrl& objUrl) {
|
||||
if(!obj && url == objUrl) QCoreApplication::exit(-1);
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
engine.load(url);
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
void setApplicationInformation(QGuiApplication& app) {
|
||||
void setApplicationInformation(QGuiApplication& app)
|
||||
{
|
||||
#if !defined BUILD_PROJECT_ORGANIZATION_NAME
|
||||
static_assert(false, "Compile-time define missing: BUILD_PROJECT_ORGANIZATION_NAME")
|
||||
#endif
|
||||
app.setOrganizationName(BUILD_PROJECT_ORGANIZATION_NAME);
|
||||
app.setOrganizationName(BUILD_PROJECT_ORGANIZATION_NAME);
|
||||
#if !defined BUILD_PROJECT_ORGANIZATION_DOMAIN
|
||||
static_assert(false, "Compile-time define missing: BUILD_PROJECT_ORGANIZATION_DOMAIN")
|
||||
#endif
|
||||
app.setOrganizationDomain(BUILD_PROJECT_ORGANIZATION_DOMAIN);
|
||||
app.setOrganizationDomain(BUILD_PROJECT_ORGANIZATION_DOMAIN);
|
||||
#if !defined BUILD_PROJECT_APPLICATION_NAME
|
||||
static_assert(false, "Compile-time define missing: BUILD_PROJECT_APPLICATION_NAME")
|
||||
#endif
|
||||
app.setApplicationName(BUILD_PROJECT_APPLICATION_NAME);
|
||||
app.setApplicationName(BUILD_PROJECT_APPLICATION_NAME);
|
||||
}
|
||||
|
|
|
@ -8,14 +8,16 @@
|
|||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace Status::ApplicationCore {
|
||||
namespace Status::ApplicationCore
|
||||
{
|
||||
|
||||
namespace {
|
||||
constexpr auto statusFolder = "Status";
|
||||
constexpr auto dataSubfolder = "data";
|
||||
}
|
||||
namespace
|
||||
{
|
||||
constexpr auto statusFolder = "Status";
|
||||
constexpr auto dataSubfolder = "data";
|
||||
} // namespace
|
||||
|
||||
UserConfiguration::UserConfiguration(QObject *parent)
|
||||
UserConfiguration::UserConfiguration(QObject* parent)
|
||||
: QObject{parent}
|
||||
{
|
||||
generateReleaseConfiguration();
|
||||
|
@ -26,16 +28,15 @@ const QString UserConfiguration::qmlUserDataFolder() const
|
|||
return toQString(m_userDataFolder.string());
|
||||
}
|
||||
|
||||
const fs::path &UserConfiguration::userDataFolder() const
|
||||
const fs::path& UserConfiguration::userDataFolder() const
|
||||
{
|
||||
return m_userDataFolder;
|
||||
}
|
||||
|
||||
void UserConfiguration::setUserDataFolder(const QString &newUserDataFolder)
|
||||
void UserConfiguration::setUserDataFolder(const QString& newUserDataFolder)
|
||||
{
|
||||
auto newVal = Status::toPath(newUserDataFolder);
|
||||
if (m_userDataFolder.compare(newVal) == 0)
|
||||
return;
|
||||
if(m_userDataFolder.compare(newVal) == 0) return;
|
||||
m_userDataFolder = newVal;
|
||||
emit userDataFolderChanged();
|
||||
}
|
||||
|
@ -43,7 +44,8 @@ void UserConfiguration::setUserDataFolder(const QString &newUserDataFolder)
|
|||
void UserConfiguration::generateReleaseConfiguration()
|
||||
{
|
||||
if(!parseFromCommandLineAndReturnTrueIfSet())
|
||||
m_userDataFolder = toPath(QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation))/statusFolder/dataSubfolder;
|
||||
m_userDataFolder =
|
||||
toPath(QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation)) / statusFolder / dataSubfolder;
|
||||
emit userDataFolderChanged();
|
||||
}
|
||||
|
||||
|
@ -55,7 +57,8 @@ bool UserConfiguration::parseFromCommandLineAndReturnTrueIfSet()
|
|||
parser.addPositionalArgument("dataDir", "Data folder");
|
||||
parser.process(*QCoreApplication::instance());
|
||||
auto args = parser.positionalArguments();
|
||||
if (args.size() > 0) {
|
||||
if(args.size() > 0)
|
||||
{
|
||||
m_userDataFolder = toPath(args[0]);
|
||||
emit userDataFolderChanged();
|
||||
return true;
|
||||
|
@ -63,4 +66,4 @@ bool UserConfiguration::parseFromCommandLineAndReturnTrueIfSet()
|
|||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::ApplicationCore
|
||||
|
|
|
@ -5,12 +5,13 @@
|
|||
|
||||
#include <filesystem>
|
||||
|
||||
namespace Status::ApplicationCore {
|
||||
namespace Status::ApplicationCore
|
||||
{
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
/// Contains necessary data for each created account hence this will be the same path for all accounts
|
||||
class UserConfiguration: public QObject
|
||||
class UserConfiguration : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
@ -19,11 +20,11 @@ class UserConfiguration: public QObject
|
|||
Q_PROPERTY(QString userDataFolder READ qmlUserDataFolder WRITE setUserDataFolder NOTIFY userDataFolderChanged)
|
||||
|
||||
public:
|
||||
explicit UserConfiguration(QObject *parent = nullptr);
|
||||
explicit UserConfiguration(QObject* parent = nullptr);
|
||||
|
||||
const QString qmlUserDataFolder() const;
|
||||
const fs::path &userDataFolder() const;
|
||||
void setUserDataFolder(const QString &newUserDataFolder);
|
||||
const fs::path& userDataFolder() const;
|
||||
void setUserDataFolder(const QString& newUserDataFolder);
|
||||
|
||||
signals:
|
||||
void userDataFolderChanged();
|
||||
|
@ -35,4 +36,4 @@ private:
|
|||
fs::path m_userDataFolder;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Status::ApplicationCore
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include <StatusGo/ChatAPI>
|
||||
#include <QtCore/QtCore>
|
||||
#include <StatusGo/ChatAPI>
|
||||
|
||||
namespace Status::ChatSection {
|
||||
namespace Status::ChatSection
|
||||
{
|
||||
|
||||
class ChatDataProvider: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
class ChatDataProvider : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ChatDataProvider();
|
||||
public:
|
||||
ChatDataProvider();
|
||||
|
||||
StatusGo::Chats::ChannelGroupDto getSectionData(const QString& sectionId) const;
|
||||
};
|
||||
}
|
||||
StatusGo::Chats::ChannelGroupDto getSectionData(const QString& sectionId) const;
|
||||
};
|
||||
} // namespace Status::ChatSection
|
||||
|
|
|
@ -4,49 +4,50 @@
|
|||
|
||||
#include <QtCore/QtCore>
|
||||
|
||||
namespace Status::ChatSection {
|
||||
namespace Status::ChatSection
|
||||
{
|
||||
|
||||
class ChatItem: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
class ChatItem : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString id READ id CONSTANT)
|
||||
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
|
||||
Q_PROPERTY(QString description READ description NOTIFY descriptionChanged)
|
||||
Q_PROPERTY(QColor color READ color NOTIFY colorChanged)
|
||||
Q_PROPERTY(bool muted READ muted NOTIFY mutedChanged)
|
||||
Q_PROPERTY(bool active READ active NOTIFY activeChanged)
|
||||
Q_PROPERTY(QString id READ id CONSTANT)
|
||||
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
|
||||
Q_PROPERTY(QString description READ description NOTIFY descriptionChanged)
|
||||
Q_PROPERTY(QColor color READ color NOTIFY colorChanged)
|
||||
Q_PROPERTY(bool muted READ muted NOTIFY mutedChanged)
|
||||
Q_PROPERTY(bool active READ active NOTIFY activeChanged)
|
||||
|
||||
public:
|
||||
explicit ChatItem(StatusGo::Chats::ChatDto rawData);
|
||||
public:
|
||||
explicit ChatItem(StatusGo::Chats::ChatDto rawData);
|
||||
|
||||
[[nodiscard]] QString id() const;
|
||||
[[nodiscard]] QString id() const;
|
||||
|
||||
[[nodiscard]] QString name() const;
|
||||
void setName(const QString& value);
|
||||
[[nodiscard]] QString name() const;
|
||||
void setName(const QString& value);
|
||||
|
||||
[[nodiscard]] QString description() const;
|
||||
void setDescription(const QString& value);
|
||||
[[nodiscard]] QString description() const;
|
||||
void setDescription(const QString& value);
|
||||
|
||||
[[nodiscard]] QColor color() const;
|
||||
void setColor(const QColor& value);
|
||||
[[nodiscard]] QColor color() const;
|
||||
void setColor(const QColor& value);
|
||||
|
||||
[[nodiscard]] bool muted() const;
|
||||
void setMuted(bool value);
|
||||
[[nodiscard]] bool muted() const;
|
||||
void setMuted(bool value);
|
||||
|
||||
[[nodiscard]] bool active() const;
|
||||
void setActive(bool value);
|
||||
[[nodiscard]] bool active() const;
|
||||
void setActive(bool value);
|
||||
|
||||
signals:
|
||||
void nameChanged();
|
||||
void descriptionChanged();
|
||||
void colorChanged();
|
||||
void mutedChanged();
|
||||
void activeChanged();
|
||||
signals:
|
||||
void nameChanged();
|
||||
void descriptionChanged();
|
||||
void colorChanged();
|
||||
void mutedChanged();
|
||||
void activeChanged();
|
||||
|
||||
private:
|
||||
StatusGo::Chats::ChatDto m_data;
|
||||
};
|
||||
private:
|
||||
StatusGo::Chats::ChatDto m_data;
|
||||
};
|
||||
|
||||
using ChatItemPtr = std::shared_ptr<ChatItem>;
|
||||
}
|
||||
using ChatItemPtr = std::shared_ptr<ChatItem>;
|
||||
} // namespace Status::ChatSection
|
||||
|
|
|
@ -1,37 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
#include "ChatItem.h"
|
||||
#include "ChatDataProvider.h"
|
||||
#include "ChatItem.h"
|
||||
|
||||
#include <Helpers/QObjectVectorModel.h>
|
||||
|
||||
namespace Status::ChatSection {
|
||||
namespace Status::ChatSection
|
||||
{
|
||||
|
||||
class ChatSectionController: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
class ChatSectionController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
Q_PROPERTY(QAbstractListModel* chatsModel READ chatsModel NOTIFY chatsModelChanged)
|
||||
Q_PROPERTY(ChatItem* currentChat READ currentChat NOTIFY currentChatChanged)
|
||||
Q_PROPERTY(QAbstractListModel* chatsModel READ chatsModel NOTIFY chatsModelChanged)
|
||||
Q_PROPERTY(ChatItem* currentChat READ currentChat NOTIFY currentChatChanged)
|
||||
|
||||
public:
|
||||
ChatSectionController();
|
||||
public:
|
||||
ChatSectionController();
|
||||
|
||||
QAbstractListModel* chatsModel() const;
|
||||
ChatItem* currentChat() const;
|
||||
QAbstractListModel* chatsModel() const;
|
||||
ChatItem* currentChat() const;
|
||||
|
||||
Q_INVOKABLE void init(const QString& sectionId);
|
||||
Q_INVOKABLE void setCurrentChatIndex(int index);
|
||||
Q_INVOKABLE void init(const QString& sectionId);
|
||||
Q_INVOKABLE void setCurrentChatIndex(int index);
|
||||
|
||||
signals:
|
||||
void chatsModelChanged();
|
||||
void currentChatChanged();
|
||||
signals:
|
||||
void chatsModelChanged();
|
||||
void currentChatChanged();
|
||||
|
||||
private:
|
||||
using ChatsModel = Helpers::QObjectVectorModel<ChatItem>;
|
||||
std::shared_ptr<ChatsModel> m_chats;
|
||||
std::unique_ptr<ChatDataProvider> m_dataProvider;
|
||||
ChatItemPtr m_currentChat;
|
||||
};
|
||||
}
|
||||
private:
|
||||
using ChatsModel = Helpers::QObjectVectorModel<ChatItem>;
|
||||
std::shared_ptr<ChatsModel> m_chats;
|
||||
std::unique_ptr<ChatDataProvider> m_dataProvider;
|
||||
ChatItemPtr m_currentChat;
|
||||
};
|
||||
} // namespace Status::ChatSection
|
||||
|
|
|
@ -6,22 +6,24 @@ namespace StatusGo = Status::StatusGo;
|
|||
|
||||
ChatDataProvider::ChatDataProvider()
|
||||
: QObject(nullptr)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
StatusGo::Chats::ChannelGroupDto ChatDataProvider::getSectionData(const QString& sectionId) const
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
auto result = StatusGo::Chats::getChats();
|
||||
for(auto chGroup : result.allChannelGroups) {
|
||||
if (chGroup.id == sectionId)
|
||||
return chGroup;
|
||||
for(auto chGroup : result.allChannelGroups)
|
||||
{
|
||||
if(chGroup.id == sectionId) return chGroup;
|
||||
}
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
catch(std::exception& e)
|
||||
{
|
||||
qWarning() << "ChatDataProvider::getSectionData, error: " << e.what();
|
||||
}
|
||||
catch (...) {
|
||||
catch(...)
|
||||
{
|
||||
qWarning() << "ChatDataProvider::getSectionData, unknown error";
|
||||
}
|
||||
return StatusGo::Chats::ChannelGroupDto{};
|
||||
|
|
|
@ -5,8 +5,7 @@ using namespace Status::ChatSection;
|
|||
ChatItem::ChatItem(StatusGo::Chats::ChatDto rawData)
|
||||
: QObject(nullptr)
|
||||
, m_data(std::move(rawData))
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
QString ChatItem::id() const
|
||||
{
|
||||
|
@ -20,8 +19,7 @@ QString ChatItem::name() const
|
|||
|
||||
void ChatItem::setName(const QString& value)
|
||||
{
|
||||
if (m_data.name == value)
|
||||
return;
|
||||
if(m_data.name == value) return;
|
||||
m_data.name = value;
|
||||
emit nameChanged();
|
||||
}
|
||||
|
@ -33,8 +31,7 @@ QString ChatItem::description() const
|
|||
|
||||
void ChatItem::setDescription(const QString& value)
|
||||
{
|
||||
if (m_data.description == value)
|
||||
return;
|
||||
if(m_data.description == value) return;
|
||||
m_data.description = value;
|
||||
emit descriptionChanged();
|
||||
}
|
||||
|
@ -46,8 +43,7 @@ QColor ChatItem::color() const
|
|||
|
||||
void ChatItem::setColor(const QColor& value)
|
||||
{
|
||||
if (m_data.color == value)
|
||||
return;
|
||||
if(m_data.color == value) return;
|
||||
m_data.color = value;
|
||||
emit colorChanged();
|
||||
}
|
||||
|
@ -59,8 +55,7 @@ bool ChatItem::muted() const
|
|||
|
||||
void ChatItem::setMuted(bool value)
|
||||
{
|
||||
if (m_data.muted == value)
|
||||
return;
|
||||
if(m_data.muted == value) return;
|
||||
m_data.muted = value;
|
||||
emit mutedChanged();
|
||||
}
|
||||
|
@ -72,8 +67,7 @@ bool ChatItem::active() const
|
|||
|
||||
void ChatItem::setActive(bool value)
|
||||
{
|
||||
if (m_data.active == value)
|
||||
return;
|
||||
if(m_data.active == value) return;
|
||||
m_data.active = value;
|
||||
emit activeChanged();
|
||||
}
|
||||
|
|
|
@ -5,15 +5,15 @@ using namespace Status::ChatSection;
|
|||
ChatSectionController::ChatSectionController()
|
||||
: QObject(nullptr)
|
||||
, m_dataProvider(std::make_unique<ChatDataProvider>())
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
void ChatSectionController::init(const QString& sectionId)
|
||||
{
|
||||
auto chatSectionData = m_dataProvider->getSectionData(sectionId);
|
||||
assert(chatSectionData.chats.size() > 0);
|
||||
std::vector<ChatItemPtr> model;
|
||||
for (auto c : chatSectionData.chats) {
|
||||
for(auto c : chatSectionData.chats)
|
||||
{
|
||||
model.push_back(std::make_shared<ChatItem>(std::move(c)));
|
||||
}
|
||||
m_chats = std::make_shared<ChatsModel>(std::move(model), "chat");
|
||||
|
@ -34,8 +34,7 @@ ChatItem* ChatSectionController::currentChat() const
|
|||
void ChatSectionController::setCurrentChatIndex(int index)
|
||||
{
|
||||
auto chat = index >= 0 && index < m_chats->size() ? m_chats->get(index) : ChatItemPtr();
|
||||
if (m_currentChat == chat)
|
||||
return;
|
||||
if(m_currentChat == chat) return;
|
||||
|
||||
m_currentChat = chat;
|
||||
emit currentChatChanged();
|
||||
|
|
|
@ -2,17 +2,16 @@
|
|||
|
||||
#include "Macros.h"
|
||||
|
||||
#define STATUS_READ_NLOHMAN_JSON_PROPERTY_3_ARGS(FIELD, NAME, REQUIRED) \
|
||||
if(REQUIRED) \
|
||||
j.at(NAME).get_to(d.FIELD); \
|
||||
else if(j.contains(NAME)) \
|
||||
j.at(NAME).get_to(d.FIELD); \
|
||||
#define STATUS_READ_NLOHMAN_JSON_PROPERTY_3_ARGS(FIELD, NAME, REQUIRED) \
|
||||
if(REQUIRED) \
|
||||
j.at(NAME).get_to(d.FIELD); \
|
||||
else if(j.contains(NAME)) \
|
||||
j.at(NAME).get_to(d.FIELD);
|
||||
|
||||
#define STATUS_READ_NLOHMAN_JSON_PROPERTY_2_ARGS(FIELD, NAME) \
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY_3_ARGS(FIELD, NAME, true)
|
||||
#define STATUS_READ_NLOHMAN_JSON_PROPERTY_2_ARGS(FIELD, NAME) \
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY_3_ARGS(FIELD, NAME, true)
|
||||
|
||||
#define STATUS_READ_NLOHMAN_JSON_PROPERTY_1_ARGS(FIELD) \
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY_2_ARGS(FIELD, #FIELD)
|
||||
#define STATUS_READ_NLOHMAN_JSON_PROPERTY_1_ARGS(FIELD) STATUS_READ_NLOHMAN_JSON_PROPERTY_2_ARGS(FIELD, #FIELD)
|
||||
|
||||
// This macro reads prop from the nlohman json object. It implies that nlohman json object is named `j` and the struct
|
||||
// instance that json object should be mapped to is named `d`.
|
||||
|
@ -27,12 +26,8 @@ STATUS_READ_NLOHMAN_JSON_PROPERTY_2_ARGS(FIELD, #FIELD)
|
|||
// STATUS_READ_NLOHMAN_JSON_PROPERTY(field, "realFieldName")
|
||||
// STATUS_READ_NLOHMAN_JSON_PROPERTY(field, "realFieldName", false)
|
||||
//
|
||||
#define STATUS_READ_NLOHMAN_JSON_PROPERTY(...) \
|
||||
STATUS_EXPAND( \
|
||||
STATUS_MACRO_SELECTOR_3_ARGS( \
|
||||
__VA_ARGS__, \
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY_3_ARGS, \
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY_2_ARGS, \
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY_1_ARGS \
|
||||
)(__VA_ARGS__) \
|
||||
)
|
||||
#define STATUS_READ_NLOHMAN_JSON_PROPERTY(...) \
|
||||
STATUS_EXPAND(STATUS_MACRO_SELECTOR_3_ARGS(__VA_ARGS__, \
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY_3_ARGS, \
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY_2_ARGS, \
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY_1_ARGS)(__VA_ARGS__))
|
||||
|
|
|
@ -4,9 +4,7 @@
|
|||
#define STATUS_EXPAND(x) x
|
||||
|
||||
// 2 arguments macro selector.
|
||||
#define STATUS_MACRO_SELECTOR_2_ARGS(_1, _2, selected, ...) \
|
||||
selected
|
||||
#define STATUS_MACRO_SELECTOR_2_ARGS(_1, _2, selected, ...) selected
|
||||
|
||||
// 3 arguments macro selector.
|
||||
#define STATUS_MACRO_SELECTOR_3_ARGS(_1, _2, _3, selected, ...) \
|
||||
selected
|
||||
#define STATUS_MACRO_SELECTOR_3_ARGS(_1, _2, _3, selected, ...) selected
|
||||
|
|
|
@ -7,9 +7,10 @@
|
|||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace Status::Helpers {
|
||||
namespace Status::Helpers
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
using IsNotReference = typename std::enable_if<!std::is_reference<T>::value, void>::type;
|
||||
|
||||
/// Featureless version of https://github.com/joboccara/NamedType that works with nlohmann::json
|
||||
|
@ -19,27 +20,52 @@ class NamedType
|
|||
public:
|
||||
using UnderlyingType = T;
|
||||
|
||||
explicit constexpr NamedType(T const& value) : m_value(value) {}
|
||||
template<typename T_ = T, typename = IsNotReference<T_>>
|
||||
explicit constexpr NamedType(T&& value) : m_value(std::move(value)) {}
|
||||
explicit constexpr NamedType(T const& value)
|
||||
: m_value(value)
|
||||
{ }
|
||||
template <typename T_ = T, typename = IsNotReference<T_>>
|
||||
explicit constexpr NamedType(T&& value)
|
||||
: m_value(std::move(value))
|
||||
{ }
|
||||
explicit constexpr NamedType() = default;
|
||||
|
||||
constexpr T& get() {
|
||||
constexpr T& get()
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
constexpr std::remove_reference_t<T> const& get() const {
|
||||
constexpr std::remove_reference_t<T> const& get() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
bool operator<(const NamedType<T, Parameter> &other) const { return m_value < other.m_value; };
|
||||
bool operator>(const NamedType<T, Parameter> &other) const { return m_value > other.m_value; };
|
||||
bool operator<=(const NamedType<T, Parameter> &other) const { return m_value <= other.m_value; };
|
||||
bool operator>=(const NamedType<T, Parameter> &other) const { return m_value >= other.m_value; };
|
||||
bool operator==(const NamedType<T, Parameter> &other) const { return m_value == other.m_value; };
|
||||
bool operator!=(const NamedType<T, Parameter> &other) const { return m_value != other.m_value; };
|
||||
bool operator<(const NamedType<T, Parameter>& other) const
|
||||
{
|
||||
return m_value < other.m_value;
|
||||
};
|
||||
bool operator>(const NamedType<T, Parameter>& other) const
|
||||
{
|
||||
return m_value > other.m_value;
|
||||
};
|
||||
bool operator<=(const NamedType<T, Parameter>& other) const
|
||||
{
|
||||
return m_value <= other.m_value;
|
||||
};
|
||||
bool operator>=(const NamedType<T, Parameter>& other) const
|
||||
{
|
||||
return m_value >= other.m_value;
|
||||
};
|
||||
bool operator==(const NamedType<T, Parameter>& other) const
|
||||
{
|
||||
return m_value == other.m_value;
|
||||
};
|
||||
bool operator!=(const NamedType<T, Parameter>& other) const
|
||||
{
|
||||
return m_value != other.m_value;
|
||||
};
|
||||
|
||||
T &operator=(NamedType<T, Parameter> const& rhs) {
|
||||
T& operator=(NamedType<T, Parameter> const& rhs)
|
||||
{
|
||||
return m_value = rhs.m_value;
|
||||
};
|
||||
|
||||
|
@ -48,16 +74,18 @@ private:
|
|||
};
|
||||
|
||||
template <typename T, typename P>
|
||||
void to_json(json& j, const NamedType<T, P>& p) {
|
||||
void to_json(json& j, const NamedType<T, P>& p)
|
||||
{
|
||||
j = p.get();
|
||||
}
|
||||
|
||||
template <typename T, typename P>
|
||||
void from_json(const json& j, NamedType<T, P>& p) {
|
||||
void from_json(const json& j, NamedType<T, P>& p)
|
||||
{
|
||||
p = NamedType<T, P>{j.get<T>()};
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::Helpers
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
|
|
@ -2,96 +2,110 @@
|
|||
#include <QAbstractListModel>
|
||||
#include <QQmlEngine>
|
||||
|
||||
namespace Status::Helpers {
|
||||
namespace Status::Helpers
|
||||
{
|
||||
|
||||
/// Generic typed QObject provider model
|
||||
///
|
||||
/// Supports: source model update
|
||||
/// \todo rename it to SharedQObjectVectorModel
|
||||
/// \todo consider "separating class template interface and implementation: move impl to .hpp file and include it at the end of .h file. That's not affect compilation time, but it better to read" propsed by @MishkaRogachev
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
class QObjectVectorModel final : public QAbstractListModel
|
||||
{
|
||||
static_assert(std::is_base_of<QObject, T>::value, "Template parameter (T) not a QObject");
|
||||
|
||||
public:
|
||||
|
||||
using ObjectContainer = std::vector<std::shared_ptr<T>>;
|
||||
|
||||
explicit QObjectVectorModel(ObjectContainer initialObjects, const char* objectRoleName, QObject* parent = nullptr)
|
||||
: QAbstractListModel(parent)
|
||||
, m_objects(std::move(initialObjects))
|
||||
, m_roleName(objectRoleName)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
explicit QObjectVectorModel(const char* objectRoleName, QObject* parent = nullptr)
|
||||
: QObjectVectorModel(ObjectContainer{}, objectRoleName, parent)
|
||||
{}
|
||||
~QObjectVectorModel() {};
|
||||
{ }
|
||||
~QObjectVectorModel(){};
|
||||
|
||||
QHash<int, QByteArray> roleNames() const override {
|
||||
QHash<int, QByteArray> roleNames() const override
|
||||
{
|
||||
return {{ObjectRole, m_roleName}};
|
||||
};
|
||||
|
||||
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override {
|
||||
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return m_objects.size();
|
||||
}
|
||||
|
||||
virtual QVariant data(const QModelIndex& index, int role) const override {
|
||||
if(!QAbstractItemModel::checkIndex(index) || role != ObjectRole)
|
||||
return QVariant();
|
||||
virtual QVariant data(const QModelIndex& index, int role) const override
|
||||
{
|
||||
if(!QAbstractItemModel::checkIndex(index) || role != ObjectRole) return QVariant();
|
||||
|
||||
return QVariant::fromValue<QObject*>(m_objects[index.row()].get());
|
||||
}
|
||||
|
||||
const T* at(size_t pos) const {
|
||||
const T* at(size_t pos) const
|
||||
{
|
||||
return m_objects.at(pos).get();
|
||||
};
|
||||
|
||||
std::shared_ptr<T> get(size_t pos) {
|
||||
std::shared_ptr<T> get(size_t pos)
|
||||
{
|
||||
return m_objects.at(pos);
|
||||
};
|
||||
|
||||
size_t size() const {
|
||||
size_t size() const
|
||||
{
|
||||
return m_objects.size();
|
||||
};
|
||||
|
||||
void reset(const ObjectContainer& objects) {
|
||||
void reset(const ObjectContainer& objects)
|
||||
{
|
||||
beginResetModel();
|
||||
m_objects = objects;
|
||||
endResetModel();
|
||||
};
|
||||
|
||||
void clear() {
|
||||
void clear()
|
||||
{
|
||||
reset({});
|
||||
};
|
||||
|
||||
void push_back(const std::shared_ptr<T>& newValue) {
|
||||
void push_back(const std::shared_ptr<T>& newValue)
|
||||
{
|
||||
beginInsertRows(QModelIndex(), m_objects.size(), m_objects.size());
|
||||
m_objects.push_back(newValue);
|
||||
endInsertRows();
|
||||
};
|
||||
|
||||
void resize(size_t count) {
|
||||
if(count > m_objects.size()) {
|
||||
void resize(size_t count)
|
||||
{
|
||||
if(count > m_objects.size())
|
||||
{
|
||||
beginInsertRows(QModelIndex(), m_objects.size(), count - 1);
|
||||
m_objects.resize(count);
|
||||
endInsertRows();
|
||||
}
|
||||
else if(count < m_objects.size()) {
|
||||
else if(count < m_objects.size())
|
||||
{
|
||||
beginRemoveRows(QModelIndex(), count, m_objects.size() - 1);
|
||||
m_objects.resize(count);
|
||||
endRemoveRows();
|
||||
}
|
||||
};
|
||||
|
||||
void set(size_t row, const std::shared_ptr<T>& newVal) {
|
||||
void set(size_t row, const std::shared_ptr<T>& newVal)
|
||||
{
|
||||
m_objects.at(row) = newVal;
|
||||
emit dataChanged(index(row), index(row), {});
|
||||
};
|
||||
|
||||
const ObjectContainer &objects() const { return m_objects; };
|
||||
const ObjectContainer& objects() const
|
||||
{
|
||||
return m_objects;
|
||||
};
|
||||
|
||||
private:
|
||||
ObjectContainer m_objects;
|
||||
|
@ -101,4 +115,4 @@ private:
|
|||
constexpr static auto ObjectRole = Qt::UserRole + 1;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Status::Helpers
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
namespace Status::Helpers
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
class Singleton
|
||||
{
|
||||
public:
|
||||
|
@ -18,10 +18,10 @@ public:
|
|||
}
|
||||
|
||||
Singleton<T>(const Singleton<T>&) = delete;
|
||||
Singleton<T>& operator = (const Singleton<T>&) = delete;
|
||||
private:
|
||||
Singleton<T>& operator=(const Singleton<T>&) = delete;
|
||||
|
||||
private:
|
||||
Singleton<T>() = default;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Status::Helpers
|
||||
|
|
|
@ -2,14 +2,17 @@
|
|||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace Status {
|
||||
namespace Status
|
||||
{
|
||||
|
||||
QString toQString(const fs::path &path) {
|
||||
QString toQString(const fs::path& path)
|
||||
{
|
||||
return QString::fromStdString(path.string());
|
||||
}
|
||||
|
||||
fs::path toPath(const QString &pathStr) {
|
||||
fs::path toPath(const QString& pathStr)
|
||||
{
|
||||
return fs::path(pathStr.toStdString());
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
#include "helpers.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QByteArray>
|
||||
#include <QColor>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
#include <filesystem>
|
||||
|
@ -13,7 +13,8 @@
|
|||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace Status {
|
||||
namespace Status
|
||||
{
|
||||
|
||||
QString toQString(const std::filesystem::path& path);
|
||||
|
||||
|
@ -21,28 +22,35 @@ std::filesystem::path toPath(const QString& pathStr);
|
|||
|
||||
} // namespace Status
|
||||
|
||||
namespace nlohmann {
|
||||
namespace nlohmann
|
||||
{
|
||||
|
||||
template<>
|
||||
struct adl_serializer<QString> {
|
||||
static void to_json(json& j, const QString& str) {
|
||||
template <>
|
||||
struct adl_serializer<QString>
|
||||
{
|
||||
static void to_json(json& j, const QString& str)
|
||||
{
|
||||
j = str.toStdString();
|
||||
}
|
||||
|
||||
static void from_json(const json& j, QString& str) {
|
||||
static void from_json(const json& j, QString& str)
|
||||
{
|
||||
str = QString::fromStdString(j.get<std::string>());
|
||||
}
|
||||
};
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
template<>
|
||||
struct adl_serializer<QByteArray> {
|
||||
static void to_json(json& j, const QByteArray& data) {
|
||||
template <>
|
||||
struct adl_serializer<QByteArray>
|
||||
{
|
||||
static void to_json(json& j, const QByteArray& data)
|
||||
{
|
||||
j = data.toStdString();
|
||||
}
|
||||
|
||||
static void from_json(const json& j, QByteArray& data) {
|
||||
static void from_json(const json& j, QByteArray& data)
|
||||
{
|
||||
auto str = j.get<std::string>();
|
||||
if(str.size() >= 2 && Status::Helpers::iequals(str, "0x"s, 2))
|
||||
data = QByteArray::fromHex(QByteArray::fromRawData(str.c_str() + 2 * sizeof(str[0]), str.size() - 2));
|
||||
|
@ -51,35 +59,44 @@ struct adl_serializer<QByteArray> {
|
|||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct adl_serializer<QColor> {
|
||||
static void to_json(json& j, const QColor& color) {
|
||||
template <>
|
||||
struct adl_serializer<QColor>
|
||||
{
|
||||
static void to_json(json& j, const QColor& color)
|
||||
{
|
||||
j = color.name();
|
||||
}
|
||||
|
||||
static void from_json(const json& j, QColor& color) {
|
||||
static void from_json(const json& j, QColor& color)
|
||||
{
|
||||
color = QColor(QString::fromStdString(j.get<std::string>()));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct adl_serializer<QUrl> {
|
||||
static void to_json(json& j, const QUrl& url) {
|
||||
template <>
|
||||
struct adl_serializer<QUrl>
|
||||
{
|
||||
static void to_json(json& j, const QUrl& url)
|
||||
{
|
||||
j = url.toString();
|
||||
}
|
||||
|
||||
static void from_json(const json& j, QUrl& url) {
|
||||
static void from_json(const json& j, QUrl& url)
|
||||
{
|
||||
url = QUrl(QString::fromStdString(j.get<std::string>()));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct adl_serializer<std::optional<T>> {
|
||||
static void to_json(json& j, const std::optional<T>& opt) {
|
||||
template <typename T>
|
||||
struct adl_serializer<std::optional<T>>
|
||||
{
|
||||
static void to_json(json& j, const std::optional<T>& opt)
|
||||
{
|
||||
j = opt.value();
|
||||
}
|
||||
|
||||
static void from_json(const json& j, std::optional<T>& opt) {
|
||||
static void from_json(const json& j, std::optional<T>& opt)
|
||||
{
|
||||
opt.emplace(j.get<T>());
|
||||
}
|
||||
};
|
||||
|
|
|
@ -4,53 +4,56 @@
|
|||
|
||||
#include <QObject>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <memory.h>
|
||||
#include <string>
|
||||
|
||||
namespace Status::Helpers {
|
||||
namespace Status::Helpers
|
||||
{
|
||||
|
||||
constexpr bool isDebugBuild()
|
||||
{
|
||||
#if defined BUILD_DEBUG
|
||||
#if defined BUILD_DEBUG
|
||||
return true;
|
||||
#else
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Case insensitive comparision with optional limitation to first \c len characters
|
||||
/// \note \c T entry type must support \c tolower
|
||||
/// \todo test me
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
bool iequals(const T& a, const T& b, size_t len = -1)
|
||||
{
|
||||
return len < a.size() && len < b.size() &&
|
||||
std::equal(a.begin(), len >= 0 ? a.end() : a.begin() + len,
|
||||
b.begin(), len >= 0 ? b.end() : b.begin() + len,
|
||||
[](auto a, auto b) {
|
||||
return tolower(a) == tolower(b);
|
||||
});
|
||||
std::equal(a.begin(),
|
||||
len >= 0 ? a.end() : a.begin() + len,
|
||||
b.begin(),
|
||||
len >= 0 ? b.end() : b.begin() + len,
|
||||
[](auto a, auto b) { return tolower(a) == tolower(b); });
|
||||
}
|
||||
|
||||
template<typename KeyType, typename ValT>
|
||||
template <typename KeyType, typename ValT>
|
||||
std::vector<KeyType> getKeys(const std::map<KeyType, ValT>& map)
|
||||
{
|
||||
std::vector<KeyType> keys;
|
||||
keys.reserve(map.size());
|
||||
for (const auto& [key, _] : map)
|
||||
for(const auto& [key, _] : map)
|
||||
keys.push_back(key);
|
||||
return keys;
|
||||
}
|
||||
|
||||
static void doDeleteLater(QObject *obj) {
|
||||
static void doDeleteLater(QObject* obj)
|
||||
{
|
||||
obj->deleteLater();
|
||||
}
|
||||
|
||||
// TODO: use https://en.cppreference.com/w/cpp/memory/shared_ptr/allocate_shared
|
||||
template<typename T, typename ...Args>
|
||||
std::shared_ptr<T> makeSharedQObject(Args&& ...args) {
|
||||
template <typename T, typename... Args>
|
||||
std::shared_ptr<T> makeSharedQObject(Args&&... args)
|
||||
{
|
||||
return std::shared_ptr<T>(new T(std::forward<Args>(args)...), doDeleteLater);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::Helpers
|
||||
|
|
|
@ -8,14 +8,15 @@
|
|||
|
||||
#include "BuildConfiguration.h"
|
||||
|
||||
namespace Status::Helpers {
|
||||
namespace Status::Helpers
|
||||
{
|
||||
|
||||
void logFormatter(QtMsgType type, const QMessageLogContext& context, const QString& msg)
|
||||
{
|
||||
// TODO: Refactor it into development-tools app
|
||||
//if(isDebugBuild()) {
|
||||
std::cout << msg.toLocal8Bit().data() << std::endl;
|
||||
return;
|
||||
std::cout << msg.toLocal8Bit().data() << std::endl;
|
||||
return;
|
||||
//}
|
||||
|
||||
QByteArray localMsg = msg.toLocal8Bit();
|
||||
|
@ -37,7 +38,12 @@ void logFormatter(QtMsgType type, const QMessageLogContext& context, const QStri
|
|||
case QtFatalMsg: log = "\033[0;31m!!! \033[0m%s \033[1m%s \033[0;33mfile=\033[94m%s:%u %s\n"; break;
|
||||
}
|
||||
fprintf(type == QtCriticalMsg || type == QtFatalMsg ? stderr : stdout,
|
||||
log, timestamp.constData(), localMsg.constData(), file, context.line, function.constData());
|
||||
log,
|
||||
timestamp.constData(),
|
||||
localMsg.constData(),
|
||||
file,
|
||||
context.line,
|
||||
function.constData());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace Status::Helpers
|
||||
|
|
|
@ -4,9 +4,10 @@
|
|||
#include <QDebug>
|
||||
#include <QString>
|
||||
|
||||
namespace Status::Helpers {
|
||||
namespace Status::Helpers
|
||||
{
|
||||
|
||||
/// Formats with colloring output if not a development build
|
||||
void logFormatter(QtMsgType type, const QMessageLogContext& context, const QString& msg);
|
||||
|
||||
}
|
||||
} // namespace Status::Helpers
|
||||
|
|
|
@ -3,16 +3,14 @@
|
|||
#include <StatusGo/Accounts/Accounts.h>
|
||||
#include <StatusGo/Accounts/AccountsAPI.h>
|
||||
#include <StatusGo/General.h>
|
||||
#include <StatusGo/Utils.h>
|
||||
#include <StatusGo/Messenger/Service.h>
|
||||
#include <StatusGo/Utils.h>
|
||||
|
||||
#include <Helpers/conversions.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
|
||||
std::optional<QString>
|
||||
getDataFromFile(const fs::path &path)
|
||||
std::optional<QString> getDataFromFile(const fs::path& path)
|
||||
{
|
||||
QFile jsonFile{Status::toQString(path)};
|
||||
if(!jsonFile.open(QIODevice::ReadOnly))
|
||||
|
@ -34,8 +32,7 @@ namespace Status::Onboarding
|
|||
|
||||
AccountsService::AccountsService()
|
||||
: m_isFirstTimeAccountLogin(false)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
bool AccountsService::init(const fs::path& statusgoDataDir)
|
||||
{
|
||||
|
@ -47,7 +44,7 @@ bool AccountsService::init(const fs::path& statusgoDataDir)
|
|||
return false;
|
||||
}
|
||||
|
||||
for(const auto &genAddressObj : response.result)
|
||||
for(const auto& genAddressObj : response.result)
|
||||
{
|
||||
auto gAcc = GeneratedMultiAccount::toGeneratedMultiAccount(genAddressObj.toObject());
|
||||
gAcc.alias = generateAlias(gAcc.derivedAccounts.whisper.publicKey);
|
||||
|
@ -67,7 +64,7 @@ std::vector<MultiAccount> AccountsService::openAndListAccounts()
|
|||
|
||||
const auto multiAccounts = response.result;
|
||||
std::vector<MultiAccount> result;
|
||||
for(const auto &value : multiAccounts)
|
||||
for(const auto& value : multiAccounts)
|
||||
{
|
||||
result.push_back(MultiAccount::toMultiAccount(value.toObject()));
|
||||
}
|
||||
|
@ -79,13 +76,14 @@ const std::vector<GeneratedMultiAccount>& AccountsService::generatedAccounts() c
|
|||
return m_generatedAccounts;
|
||||
}
|
||||
|
||||
bool AccountsService::setupAccountAndLogin(const QString &accountId, const QString &password, const QString &displayName)
|
||||
bool AccountsService::setupAccountAndLogin(const QString& accountId,
|
||||
const QString& password,
|
||||
const QString& displayName)
|
||||
{
|
||||
const QString installationId(QUuid::createUuid().toString(QUuid::WithoutBraces));
|
||||
const QJsonObject accountData(getAccountDataForAccountId(accountId, displayName));
|
||||
|
||||
if(!setKeyStoreDir(accountData.value("key-uid").toString()))
|
||||
return false;
|
||||
if(!setKeyStoreDir(accountData.value("key-uid").toString())) return false;
|
||||
|
||||
QJsonArray subAccountData(getSubaccountDataForAccountId(accountId, displayName));
|
||||
QJsonObject settings(getAccountSettings(accountId, installationId, displayName));
|
||||
|
@ -94,8 +92,7 @@ bool AccountsService::setupAccountAndLogin(const QString &accountId, const QStri
|
|||
auto hashedPassword(Utils::hashPassword(password));
|
||||
|
||||
// This initialize the DB if first time running. Required for storing accounts
|
||||
if(StatusGo::Accounts::openAccounts(m_statusgoDataDir.c_str()).containsError())
|
||||
return false;
|
||||
if(StatusGo::Accounts::openAccounts(m_statusgoDataDir.c_str()).containsError()) return false;
|
||||
|
||||
AccountsService::storeAccount(accountId, hashedPassword);
|
||||
AccountsService::storeDerivedAccounts(accountId, hashedPassword, Constants::General::AccountDefaultPaths);
|
||||
|
@ -120,7 +117,7 @@ bool AccountsService::isFirstTimeAccountLogin() const
|
|||
return m_isFirstTimeAccountLogin;
|
||||
}
|
||||
|
||||
bool AccountsService::setKeyStoreDir(const QString &key)
|
||||
bool AccountsService::setKeyStoreDir(const QString& key)
|
||||
{
|
||||
m_keyStoreDir = m_statusgoDataDir / m_keyStoreDirName / key.toStdString();
|
||||
const auto response = StatusGo::General::initKeystore(m_keyStoreDir.c_str());
|
||||
|
@ -130,8 +127,7 @@ bool AccountsService::setKeyStoreDir(const QString &key)
|
|||
QString AccountsService::login(MultiAccount account, const QString& password)
|
||||
{
|
||||
// This is a requirement. Make it more explicit into the status go module
|
||||
if(!setKeyStoreDir(account.keyUid))
|
||||
return QString("Failed to initialize keystore before logging in");
|
||||
if(!setKeyStoreDir(account.keyUid)) return QString("Failed to initialize keystore before logging in");
|
||||
|
||||
// This initialize the DB if first time running. Required before logging in
|
||||
if(StatusGo::Accounts::openAccounts(m_statusgoDataDir.c_str()).containsError())
|
||||
|
@ -141,8 +137,8 @@ QString AccountsService::login(MultiAccount account, const QString& password)
|
|||
|
||||
const QString thumbnailImage;
|
||||
const QString largeImage;
|
||||
const auto response = StatusGo::Accounts::login(account.name, account.keyUid, hashedPassword,
|
||||
thumbnailImage, largeImage);
|
||||
const auto response =
|
||||
StatusGo::Accounts::login(account.name, account.keyUid, hashedPassword, thumbnailImage, largeImage);
|
||||
if(response.containsError())
|
||||
{
|
||||
qWarning() << response.error.message;
|
||||
|
@ -174,13 +170,14 @@ QString AccountsService::generateAlias(const QString& publicKey)
|
|||
return response.result;
|
||||
}
|
||||
|
||||
void AccountsService::deleteMultiAccount(const MultiAccount &account)
|
||||
void AccountsService::deleteMultiAccount(const MultiAccount& account)
|
||||
{
|
||||
StatusGo::Accounts::deleteMultiaccount(account.keyUid, m_keyStoreDir);
|
||||
}
|
||||
|
||||
DerivedAccounts AccountsService::storeDerivedAccounts(const QString& accountId, const StatusGo::HashedPassword& password,
|
||||
const std::vector<Accounts::DerivationPath> &paths)
|
||||
DerivedAccounts AccountsService::storeDerivedAccounts(const QString& accountId,
|
||||
const StatusGo::HashedPassword& password,
|
||||
const std::vector<Accounts::DerivationPath>& paths)
|
||||
{
|
||||
const auto response = StatusGo::Accounts::storeDerivedAccounts(accountId, password, paths);
|
||||
if(response.containsError())
|
||||
|
@ -202,11 +199,14 @@ StoredMultiAccount AccountsService::storeAccount(const QString& accountId, const
|
|||
return toStoredMultiAccount(response.result);
|
||||
}
|
||||
|
||||
MultiAccount AccountsService::saveAccountAndLogin(const StatusGo::HashedPassword& password, const QJsonObject& account,
|
||||
const QJsonArray& subaccounts, const QJsonObject& settings,
|
||||
const QJsonObject& config)
|
||||
MultiAccount AccountsService::saveAccountAndLogin(const StatusGo::HashedPassword& password,
|
||||
const QJsonObject& account,
|
||||
const QJsonArray& subaccounts,
|
||||
const QJsonObject& settings,
|
||||
const QJsonObject& config)
|
||||
{
|
||||
if(!StatusGo::Accounts::saveAccountAndLogin(password, account, subaccounts, settings, config)) {
|
||||
if(!StatusGo::Accounts::saveAccountAndLogin(password, account, subaccounts, settings, config))
|
||||
{
|
||||
qWarning() << "Failed saving acccount" << account.value("name");
|
||||
return MultiAccount();
|
||||
}
|
||||
|
@ -215,17 +215,18 @@ MultiAccount AccountsService::saveAccountAndLogin(const StatusGo::HashedPassword
|
|||
return MultiAccount::toMultiAccount(account);
|
||||
}
|
||||
|
||||
QJsonObject AccountsService::prepareAccountJsonObject(const GeneratedMultiAccount& account, const QString &displayName) const
|
||||
QJsonObject AccountsService::prepareAccountJsonObject(const GeneratedMultiAccount& account,
|
||||
const QString& displayName) const
|
||||
{
|
||||
return QJsonObject{{"name", displayName.isEmpty() ? account.alias : displayName},
|
||||
{"address", account.address},
|
||||
{"key-uid", account.keyUid},
|
||||
{"keycard-pairing", QJsonValue()}};
|
||||
{"address", account.address},
|
||||
{"key-uid", account.keyUid},
|
||||
{"keycard-pairing", QJsonValue()}};
|
||||
}
|
||||
|
||||
QJsonObject AccountsService::getAccountDataForAccountId(const QString &accountId, const QString &displayName) const
|
||||
QJsonObject AccountsService::getAccountDataForAccountId(const QString& accountId, const QString& displayName) const
|
||||
{
|
||||
for(const GeneratedMultiAccount &acc : m_generatedAccounts)
|
||||
for(const GeneratedMultiAccount& acc : m_generatedAccounts)
|
||||
{
|
||||
if(acc.id == accountId)
|
||||
{
|
||||
|
@ -245,33 +246,28 @@ QJsonObject AccountsService::getAccountDataForAccountId(const QString &accountId
|
|||
return QJsonObject();
|
||||
}
|
||||
|
||||
QJsonArray AccountsService::prepareSubaccountJsonObject(const GeneratedMultiAccount& account, const QString &displayName) const
|
||||
QJsonArray AccountsService::prepareSubaccountJsonObject(const GeneratedMultiAccount& account,
|
||||
const QString& displayName) const
|
||||
{
|
||||
return {
|
||||
QJsonObject{
|
||||
{"public-key", account.derivedAccounts.defaultWallet.publicKey},
|
||||
{"address", account.derivedAccounts.defaultWallet.address},
|
||||
{"color", "#4360df"},
|
||||
{"wallet", true},
|
||||
{"path", Constants::General::PathDefaultWallet.get()},
|
||||
{"name", "Status account"},
|
||||
{"derived-from", account.address}
|
||||
},
|
||||
QJsonObject{
|
||||
{"public-key", account.derivedAccounts.whisper.publicKey},
|
||||
{"address", account.derivedAccounts.whisper.address},
|
||||
{"name", displayName.isEmpty() ? account.alias : displayName},
|
||||
{"path", Constants::General::PathWhisper.get()},
|
||||
{"chat", true},
|
||||
{"derived-from", ""}
|
||||
}
|
||||
};
|
||||
return {QJsonObject{{"public-key", account.derivedAccounts.defaultWallet.publicKey},
|
||||
{"address", account.derivedAccounts.defaultWallet.address},
|
||||
{"color", "#4360df"},
|
||||
{"wallet", true},
|
||||
{"path", Constants::General::PathDefaultWallet.get()},
|
||||
{"name", "Status account"},
|
||||
{"derived-from", account.address}},
|
||||
QJsonObject{{"public-key", account.derivedAccounts.whisper.publicKey},
|
||||
{"address", account.derivedAccounts.whisper.address},
|
||||
{"name", displayName.isEmpty() ? account.alias : displayName},
|
||||
{"path", Constants::General::PathWhisper.get()},
|
||||
{"chat", true},
|
||||
{"derived-from", ""}}};
|
||||
}
|
||||
|
||||
QJsonArray AccountsService::getSubaccountDataForAccountId(const QString& accountId, const QString &displayName) const
|
||||
QJsonArray AccountsService::getSubaccountDataForAccountId(const QString& accountId, const QString& displayName) const
|
||||
{
|
||||
// "All these for loops with a nested if cry for a std::find_if :)"
|
||||
for(const GeneratedMultiAccount &acc : m_generatedAccounts)
|
||||
for(const GeneratedMultiAccount& acc : m_generatedAccounts)
|
||||
{
|
||||
if(acc.id == accountId)
|
||||
{
|
||||
|
@ -297,42 +293,42 @@ QString AccountsService::generateSigningPhrase(int count) const
|
|||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
words.append(Constants::SigningPhrases[QRandomGenerator::global()->bounded(
|
||||
static_cast<int>(Constants::SigningPhrases.size()))]);
|
||||
static_cast<int>(Constants::SigningPhrases.size()))]);
|
||||
}
|
||||
return words.join(" ");
|
||||
}
|
||||
|
||||
QJsonObject AccountsService::prepareAccountSettingsJsonObject(const GeneratedMultiAccount& account,
|
||||
const QString& installationId,
|
||||
const QString& displayName) const
|
||||
const QString& installationId,
|
||||
const QString& displayName) const
|
||||
{
|
||||
return QJsonObject{
|
||||
{"key-uid", account.keyUid},
|
||||
{"mnemonic", account.mnemonic},
|
||||
{"public-key", account.derivedAccounts.whisper.publicKey},
|
||||
{"name", account.alias},
|
||||
{"display-name", displayName},
|
||||
{"address", account.address},
|
||||
{"eip1581-address", account.derivedAccounts.eip1581.address},
|
||||
{"dapps-address", account.derivedAccounts.defaultWallet.address},
|
||||
{"wallet-root-address", account.derivedAccounts.walletRoot.address},
|
||||
{"preview-privacy?", true},
|
||||
{"signing-phrase", generateSigningPhrase(3)},
|
||||
{"log-level", "INFO"},
|
||||
{"latest-derived-path", 0},
|
||||
{"currency", "usd"},
|
||||
{"networks/networks", QJsonArray()},
|
||||
{"networks/current-network", ""},
|
||||
{"wallet/visible-tokens", QJsonObject()},
|
||||
{"waku-enabled", true},
|
||||
{"appearance", 0},
|
||||
{"installation-id", installationId}
|
||||
};
|
||||
return QJsonObject{{"key-uid", account.keyUid},
|
||||
{"mnemonic", account.mnemonic},
|
||||
{"public-key", account.derivedAccounts.whisper.publicKey},
|
||||
{"name", account.alias},
|
||||
{"display-name", displayName},
|
||||
{"address", account.address},
|
||||
{"eip1581-address", account.derivedAccounts.eip1581.address},
|
||||
{"dapps-address", account.derivedAccounts.defaultWallet.address},
|
||||
{"wallet-root-address", account.derivedAccounts.walletRoot.address},
|
||||
{"preview-privacy?", true},
|
||||
{"signing-phrase", generateSigningPhrase(3)},
|
||||
{"log-level", "INFO"},
|
||||
{"latest-derived-path", 0},
|
||||
{"currency", "usd"},
|
||||
{"networks/networks", QJsonArray()},
|
||||
{"networks/current-network", ""},
|
||||
{"wallet/visible-tokens", QJsonObject()},
|
||||
{"waku-enabled", true},
|
||||
{"appearance", 0},
|
||||
{"installation-id", installationId}};
|
||||
}
|
||||
|
||||
QJsonObject AccountsService::getAccountSettings(const QString& accountId, const QString& installationId, const QString &displayName) const
|
||||
QJsonObject AccountsService::getAccountSettings(const QString& accountId,
|
||||
const QString& installationId,
|
||||
const QString& displayName) const
|
||||
{
|
||||
for(const GeneratedMultiAccount &acc : m_generatedAccounts)
|
||||
for(const GeneratedMultiAccount& acc : m_generatedAccounts)
|
||||
|
||||
if(acc.id == accountId)
|
||||
{
|
||||
|
@ -363,7 +359,8 @@ QJsonArray getNodes(const QJsonObject& fleet, const QString& nodeType)
|
|||
|
||||
QJsonObject AccountsService::getDefaultNodeConfig(const QString& installationId) const
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
auto templateNodeConfigJsonStr = getDataFromFile(":/Status/StaticConfig/node-config.json").value();
|
||||
auto fleetJson = getDataFromFile(":/Status/StaticConfig/fleets.json").value();
|
||||
auto infuraKey = getDataFromFile(":/Status/StaticConfig/infura_key").value();
|
||||
|
@ -376,8 +373,8 @@ QJsonObject AccountsService::getDefaultNodeConfig(const QString& installationId)
|
|||
auto DEFAULT_TORRENT_CONFIG_DATADIR = m_statusgoDataDir / "archivedata";
|
||||
auto DEFAULT_TORRENT_CONFIG_TORRENTDIR = m_statusgoDataDir / "torrents";
|
||||
|
||||
auto nodeConfigJsonStr = templateNodeConfigJsonStr
|
||||
.replace("%INSTALLATIONID%", installationId)
|
||||
auto nodeConfigJsonStr =
|
||||
templateNodeConfigJsonStr.replace("%INSTALLATIONID%", installationId)
|
||||
.replace("%INFURA_TOKEN_RESOLVED%", infuraKey)
|
||||
.replace("%DEFAULT_TORRENT_CONFIG_PORT%", QString::number(DEFAULT_TORRENT_CONFIG_PORT))
|
||||
.replace("%DEFAULT_TORRENT_CONFIG_DATADIR%", DEFAULT_TORRENT_CONFIG_DATADIR.c_str())
|
||||
|
@ -413,9 +410,11 @@ QJsonObject AccountsService::getDefaultNodeConfig(const QString& installationId)
|
|||
|
||||
nodeConfigJson["KeyStoreDir"] = toQString(fs::relative(m_keyStoreDir, m_statusgoDataDir));
|
||||
return nodeConfigJson;
|
||||
} catch (std::bad_optional_access) {
|
||||
}
|
||||
catch(std::bad_optional_access)
|
||||
{
|
||||
return QJsonObject();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::Onboarding
|
||||
|
|
|
@ -44,7 +44,7 @@ public:
|
|||
[[nodiscard]] bool isFirstTimeAccountLogin() const override;
|
||||
|
||||
/// \see ServiceInterface
|
||||
bool setKeyStoreDir(const QString &key) override;
|
||||
bool setKeyStoreDir(const QString& key) override;
|
||||
|
||||
/// \todo login@src/app_service/service/accounts/service.nim adds custom configuration for defaults
|
||||
/// to account for legacy user DBs. See if this is required to replicate or add proper migration logic
|
||||
|
@ -54,18 +54,21 @@ public:
|
|||
|
||||
QString generateAlias(const QString& publicKey) override;
|
||||
|
||||
void deleteMultiAccount(const MultiAccount &account) override;
|
||||
void deleteMultiAccount(const MultiAccount& account) override;
|
||||
|
||||
private:
|
||||
QJsonObject prepareAccountJsonObject(const GeneratedMultiAccount& account, const QString& displayName) const;
|
||||
|
||||
DerivedAccounts storeDerivedAccounts(const QString& accountId, const StatusGo::HashedPassword& password,
|
||||
DerivedAccounts storeDerivedAccounts(const QString& accountId,
|
||||
const StatusGo::HashedPassword& password,
|
||||
const std::vector<Accounts::DerivationPath>& paths);
|
||||
StoredMultiAccount storeAccount(const QString& accountId, const StatusGo::HashedPassword& password);
|
||||
|
||||
MultiAccount saveAccountAndLogin(const StatusGo::HashedPassword& password, const QJsonObject& account,
|
||||
const QJsonArray& subaccounts, const QJsonObject& settings,
|
||||
const QJsonObject& config);
|
||||
MultiAccount saveAccountAndLogin(const StatusGo::HashedPassword& password,
|
||||
const QJsonObject& account,
|
||||
const QJsonArray& subaccounts,
|
||||
const QJsonObject& settings,
|
||||
const QJsonObject& config);
|
||||
|
||||
QJsonObject getAccountDataForAccountId(const QString& accountId, const QString& displayName) const;
|
||||
|
||||
|
@ -79,7 +82,8 @@ private:
|
|||
const QString& installationId,
|
||||
const QString& displayName) const;
|
||||
|
||||
QJsonObject getAccountSettings(const QString& accountId, const QString& installationId, const QString& displayName) const;
|
||||
QJsonObject
|
||||
getAccountSettings(const QString& accountId, const QString& installationId, const QString& displayName) const;
|
||||
|
||||
QJsonObject getDefaultNodeConfig(const QString& installationId) const;
|
||||
|
||||
|
@ -97,4 +101,4 @@ private:
|
|||
static constexpr auto m_keyStoreDirName = "keystore";
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Status::Onboarding
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "MultiAccount.h"
|
||||
#include "GeneratedMultiAccount.h"
|
||||
#include "MultiAccount.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
|
@ -13,7 +13,6 @@ namespace Status::Onboarding
|
|||
class AccountsServiceInterface
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~AccountsServiceInterface() = default;
|
||||
|
||||
/// Generates and cache addresses accessible by \c generatedAccounts
|
||||
|
@ -26,7 +25,8 @@ public:
|
|||
[[nodiscard]] virtual const std::vector<GeneratedMultiAccount>& generatedAccounts() const = 0;
|
||||
|
||||
/// Configure an generated account. \a accountID must be sourced from \c generatedAccounts
|
||||
virtual bool setupAccountAndLogin(const QString& accountID, const QString& password, const QString& displayName) = 0;
|
||||
virtual bool
|
||||
setupAccountAndLogin(const QString& accountID, const QString& password, const QString& displayName) = 0;
|
||||
|
||||
/// Account that is currently logged-in
|
||||
[[nodiscard]] virtual const MultiAccount& getLoggedInAccount() const = 0;
|
||||
|
@ -37,7 +37,7 @@ public:
|
|||
[[nodiscard]] virtual bool isFirstTimeAccountLogin() const = 0;
|
||||
|
||||
/// Set and initializes the keystore directory. \see StatusGo::General::initKeystore
|
||||
virtual bool setKeyStoreDir(const QString &key) = 0;
|
||||
virtual bool setKeyStoreDir(const QString& key) = 0;
|
||||
|
||||
virtual QString login(MultiAccount account, const QString& password) = 0;
|
||||
|
||||
|
@ -45,9 +45,9 @@ public:
|
|||
|
||||
virtual QString generateAlias(const QString& publicKey) = 0;
|
||||
|
||||
virtual void deleteMultiAccount(const MultiAccount &account) = 0;
|
||||
virtual void deleteMultiAccount(const MultiAccount& account) = 0;
|
||||
};
|
||||
|
||||
using AccountsServiceInterfacePtr = std::shared_ptr<AccountsServiceInterface>;
|
||||
|
||||
}
|
||||
} // namespace Status::Onboarding
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "Common/Constants.h"
|
||||
#include "Common/SigningPhrases.h"
|
||||
#include "Common/Json.h"
|
||||
#include "Common/SigningPhrases.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
|
@ -27,7 +27,7 @@ struct DerivedAccountDetails
|
|||
result.publicKey = Json::getMandatoryProp(jsonObj, "publicKey")->toString();
|
||||
result.address = Json::getMandatoryProp(jsonObj, "address")->toString();
|
||||
}
|
||||
catch (std::exception e)
|
||||
catch(std::exception e)
|
||||
{
|
||||
qWarning() << QString("Mapping DerivedAccountDetails failed: %1").arg(e.what());
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ struct DerivedAccounts
|
|||
{
|
||||
auto result = DerivedAccounts();
|
||||
|
||||
for(const auto &derivationPath : jsonObj.keys())
|
||||
for(const auto& derivationPath : jsonObj.keys())
|
||||
{
|
||||
auto derivedObj = jsonObj.value(derivationPath).toObject();
|
||||
if(derivationPath == Constants::General::PathWhisper.get())
|
||||
|
@ -76,17 +76,19 @@ struct StoredMultiAccount
|
|||
{
|
||||
QString publicKey;
|
||||
QString address;
|
||||
|
||||
};
|
||||
|
||||
static StoredMultiAccount toStoredMultiAccount(const QJsonObject& jsonObj)
|
||||
{
|
||||
auto result = StoredMultiAccount();
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
result.address = Json::getMandatoryProp(jsonObj, "address")->toString();
|
||||
result.publicKey = Json::getMandatoryProp(jsonObj, "publicKey")->toString();
|
||||
} catch (std::exception e) {
|
||||
}
|
||||
catch(std::exception e)
|
||||
{
|
||||
qWarning() << QString("Mapping StoredMultiAccount failed: %1").arg(e.what());
|
||||
}
|
||||
|
||||
|
@ -128,7 +130,7 @@ struct GeneratedMultiAccount
|
|||
result.derivedAccounts = DerivedAccounts::toDerivedAccounts(derivedObj);
|
||||
}
|
||||
}
|
||||
catch (std::exception e)
|
||||
catch(std::exception e)
|
||||
{
|
||||
qWarning() << QString("Mapping GeneratedMultiAccount failed: %1").arg(e.what());
|
||||
}
|
||||
|
@ -137,4 +139,4 @@ struct GeneratedMultiAccount
|
|||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Status::Onboarding
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "Common/Constants.h"
|
||||
#include "Common/SigningPhrases.h"
|
||||
#include "Common/Json.h"
|
||||
#include "Common/SigningPhrases.h"
|
||||
|
||||
#include <StatusGo/Accounts/accounts_types.h>
|
||||
|
||||
|
@ -39,11 +39,11 @@ struct MultiAccount
|
|||
{
|
||||
result.name = Json::getMandatoryProp(jsonObj, "name")->toString();
|
||||
auto timestampIt = Json::getProp(jsonObj, "timestamp");
|
||||
if(timestampIt != jsonObj.constEnd()) {
|
||||
if(timestampIt != jsonObj.constEnd())
|
||||
{
|
||||
bool ok = false;
|
||||
auto t = timestampIt->toString().toLong(&ok);
|
||||
if(ok)
|
||||
result.timestamp = t;
|
||||
if(ok) result.timestamp = t;
|
||||
}
|
||||
result.keycardPairing = Json::getMandatoryProp(jsonObj, "keycard-pairing")->toString();
|
||||
result.keyUid = Json::getMandatoryProp(jsonObj, "key-uid")->toString();
|
||||
|
@ -51,7 +51,7 @@ struct MultiAccount
|
|||
|
||||
/// TODO: investigate unhandled `photo-path` value
|
||||
}
|
||||
catch (std::exception e)
|
||||
catch(std::exception e)
|
||||
{
|
||||
qWarning() << QString("Mapping MultiAccount failed: %1").arg(e.what());
|
||||
}
|
||||
|
@ -60,4 +60,4 @@ struct MultiAccount
|
|||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Status::Onboarding
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
#include <StatusGo/Accounts/accounts_types.h>
|
||||
|
||||
#include <QtCore>
|
||||
#include <QStringLiteral>
|
||||
#include <QtCore>
|
||||
|
||||
namespace GoAccounts = Status::StatusGo::Accounts;
|
||||
|
||||
|
@ -12,41 +12,42 @@ namespace Status::Constants
|
|||
|
||||
namespace Fleet
|
||||
{
|
||||
inline const auto Prod = u"eth.prod"_qs;
|
||||
inline const auto Staging = u"eth.staging"_qs;
|
||||
inline const auto Test = u"eth.test"_qs;
|
||||
inline const auto WakuV2Prod = u"wakuv2.prod"_qs;
|
||||
inline const auto WakuV2Test = u"wakuv2.test"_qs;
|
||||
inline const auto GoWakuTest = u"go-waku.test"_qs;
|
||||
}
|
||||
inline const auto Prod = u"eth.prod"_qs;
|
||||
inline const auto Staging = u"eth.staging"_qs;
|
||||
inline const auto Test = u"eth.test"_qs;
|
||||
inline const auto WakuV2Prod = u"wakuv2.prod"_qs;
|
||||
inline const auto WakuV2Test = u"wakuv2.test"_qs;
|
||||
inline const auto GoWakuTest = u"go-waku.test"_qs;
|
||||
} // namespace Fleet
|
||||
|
||||
namespace FleetNodes
|
||||
{
|
||||
inline const auto Bootnodes = u"boot"_qs;
|
||||
inline const auto Mailservers = u"mail"_qs;
|
||||
inline const auto Rendezvous = u"rendezvous"_qs;
|
||||
inline const auto Whisper = u"whisper"_qs;
|
||||
inline const auto Waku = u"waku"_qs;
|
||||
inline const auto LibP2P = u"libp2p"_qs;
|
||||
inline const auto Websocket = u"websocket"_qs;
|
||||
}
|
||||
inline const auto Bootnodes = u"boot"_qs;
|
||||
inline const auto Mailservers = u"mail"_qs;
|
||||
inline const auto Rendezvous = u"rendezvous"_qs;
|
||||
inline const auto Whisper = u"whisper"_qs;
|
||||
inline const auto Waku = u"waku"_qs;
|
||||
inline const auto LibP2P = u"libp2p"_qs;
|
||||
inline const auto Websocket = u"websocket"_qs;
|
||||
} // namespace FleetNodes
|
||||
|
||||
namespace General
|
||||
{
|
||||
inline const auto DefaultNetworkName = u"mainnet_rpc"_qs;
|
||||
//const DEFAULT_NETWORKS_IDS* = @["mainnet_rpc", "testnet_rpc", "rinkeby_rpc", "goerli_rpc", "xdai_rpc", "poa_rpc" ]
|
||||
inline const auto DefaultNetworkName = u"mainnet_rpc"_qs;
|
||||
//const DEFAULT_NETWORKS_IDS* = @["mainnet_rpc", "testnet_rpc", "rinkeby_rpc", "goerli_rpc", "xdai_rpc", "poa_rpc" ]
|
||||
|
||||
inline const auto ZeroAddress = u"0x0000000000000000000000000000000000000000"_qs;
|
||||
inline const auto ZeroAddress = u"0x0000000000000000000000000000000000000000"_qs;
|
||||
|
||||
inline const GoAccounts::DerivationPath PathWalletRoot{u"m/44'/60'/0'/0"_qs};
|
||||
// EIP1581 Root Key, the extended key from which any whisper key/encryption key can be derived
|
||||
inline const GoAccounts::DerivationPath PathEIP1581{u"m/43'/60'/1581'"_qs};
|
||||
// BIP44-0 Wallet key, the default wallet key
|
||||
inline const GoAccounts::DerivationPath PathDefaultWallet{PathWalletRoot.get() + u"/0"_qs};
|
||||
// EIP1581 Chat Key 0, the default whisper key
|
||||
inline const GoAccounts::DerivationPath PathWhisper{PathEIP1581.get() + u"/0'/0"_qs};
|
||||
inline const GoAccounts::DerivationPath PathWalletRoot{u"m/44'/60'/0'/0"_qs};
|
||||
// EIP1581 Root Key, the extended key from which any whisper key/encryption key can be derived
|
||||
inline const GoAccounts::DerivationPath PathEIP1581{u"m/43'/60'/1581'"_qs};
|
||||
// BIP44-0 Wallet key, the default wallet key
|
||||
inline const GoAccounts::DerivationPath PathDefaultWallet{PathWalletRoot.get() + u"/0"_qs};
|
||||
// EIP1581 Chat Key 0, the default whisper key
|
||||
inline const GoAccounts::DerivationPath PathWhisper{PathEIP1581.get() + u"/0'/0"_qs};
|
||||
|
||||
inline const std::vector<GoAccounts::DerivationPath> AccountDefaultPaths {PathWalletRoot, PathEIP1581, PathWhisper, PathDefaultWallet};
|
||||
}
|
||||
inline const std::vector<GoAccounts::DerivationPath> AccountDefaultPaths{
|
||||
PathWalletRoot, PathEIP1581, PathWhisper, PathDefaultWallet};
|
||||
} // namespace General
|
||||
|
||||
}
|
||||
} // namespace Status::Constants
|
||||
|
|
|
@ -20,7 +20,7 @@ public:
|
|||
{
|
||||
const auto it = getProp(object, field);
|
||||
|
||||
if (it == object.constEnd())
|
||||
if(it == object.constEnd())
|
||||
{
|
||||
throw std::logic_error(QString("No field `%1`").arg(field).toStdString());
|
||||
}
|
||||
|
@ -29,4 +29,4 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Status
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
namespace Status::Constants
|
||||
{
|
||||
|
||||
constexpr std::array SigningPhrases {
|
||||
constexpr std::array SigningPhrases{
|
||||
"area", "army", "atom", "aunt", "babe", "baby", "back", "bail", "bait", "bake", "ball", "band", "bank", "barn",
|
||||
"base", "bass", "bath", "bead", "beak", "beam", "bean", "bear", "beat", "beef", "beer", "beet", "bell", "belt",
|
||||
"bend", "bike", "bill", "bird", "bite", "blow", "blue", "boar", "boat", "body", "bolt", "bomb", "bone", "book",
|
||||
|
@ -50,7 +50,6 @@ constexpr std::array SigningPhrases {
|
|||
"veal", "veil", "vein", "vest", "vibe", "view", "vise", "wait", "wake", "walk", "wall", "wash", "wasp", "wave",
|
||||
"wear", "weed", "week", "well", "west", "whip", "wife", "will", "wind", "wine", "wing", "wire", "wish", "wolf",
|
||||
"wood", "wool", "word", "work", "worm", "wrap", "wren", "yard", "yarn", "yawl", "year", "yoga", "yoke", "yurt",
|
||||
"zinc", "zone"
|
||||
};
|
||||
"zinc", "zone"};
|
||||
|
||||
}
|
||||
|
|
|
@ -15,70 +15,70 @@ NewAccountController::NewAccountController(AccountsServiceInterfacePtr accountsS
|
|||
: m_accountsService(accountsService)
|
||||
{
|
||||
connect(this, &NewAccountController::passwordChanged, this, &NewAccountController::checkAndUpdateDataValidity);
|
||||
connect(this, &NewAccountController::confirmationPasswordChanged, this, &NewAccountController::checkAndUpdateDataValidity);
|
||||
connect(this,
|
||||
&NewAccountController::confirmationPasswordChanged,
|
||||
this,
|
||||
&NewAccountController::checkAndUpdateDataValidity);
|
||||
connect(this, &NewAccountController::nameChanged, this, &NewAccountController::checkAndUpdateDataValidity);
|
||||
}
|
||||
|
||||
void NewAccountController::createAccount()
|
||||
{
|
||||
// TODO: fix this after moving SingalManager to StatusGo wrapper lib
|
||||
QObject::connect(StatusGo::SignalsManager::instance(), &StatusGo::SignalsManager::nodeLogin, this, &NewAccountController::onNodeLogin);
|
||||
QObject::connect(StatusGo::SignalsManager::instance(),
|
||||
&StatusGo::SignalsManager::nodeLogin,
|
||||
this,
|
||||
&NewAccountController::onNodeLogin);
|
||||
|
||||
auto setupAccountFn = [this]() {
|
||||
if(m_nameIsValid && m_passwordIsValid && m_confirmationPasswordIsValid) {
|
||||
if(m_nameIsValid && m_passwordIsValid && m_confirmationPasswordIsValid)
|
||||
{
|
||||
auto genAccounts = m_accountsService->generatedAccounts();
|
||||
if(genAccounts.size() > 0) {
|
||||
if(m_accountsService->setupAccountAndLogin(genAccounts[0].id, m_password, m_name))
|
||||
return;
|
||||
if(genAccounts.size() > 0)
|
||||
{
|
||||
if(m_accountsService->setupAccountAndLogin(genAccounts[0].id, m_password, m_name)) return;
|
||||
}
|
||||
}
|
||||
};
|
||||
// TODO: refactor StatusGo wrapper to work with futures instead of SignalManager
|
||||
m_createAccountFuture = QtConcurrent::run(setupAccountFn)
|
||||
.then([]{ /*Nothing, we expect status-go events*/ })
|
||||
.onFailed([this] {
|
||||
emit accountCreationError();
|
||||
})
|
||||
.onCanceled([this] {
|
||||
emit accountCreationError();
|
||||
});
|
||||
.then([] { /*Nothing, we expect status-go events*/ })
|
||||
.onFailed([this] { emit accountCreationError(); })
|
||||
.onCanceled([this] { emit accountCreationError(); });
|
||||
}
|
||||
|
||||
const QString &NewAccountController::password() const
|
||||
const QString& NewAccountController::password() const
|
||||
{
|
||||
return m_password;
|
||||
}
|
||||
|
||||
void NewAccountController::setPassword(const QString &newPassword)
|
||||
void NewAccountController::setPassword(const QString& newPassword)
|
||||
{
|
||||
if (m_password == newPassword)
|
||||
return;
|
||||
if(m_password == newPassword) return;
|
||||
m_password = newPassword;
|
||||
emit passwordChanged();
|
||||
}
|
||||
|
||||
const QString &NewAccountController::confirmationPassword() const
|
||||
const QString& NewAccountController::confirmationPassword() const
|
||||
{
|
||||
return m_confirmationPassword;
|
||||
}
|
||||
|
||||
void NewAccountController::setConfirmationPassword(const QString &newConfirmationPassword)
|
||||
void NewAccountController::setConfirmationPassword(const QString& newConfirmationPassword)
|
||||
{
|
||||
if (m_confirmationPassword == newConfirmationPassword)
|
||||
return;
|
||||
if(m_confirmationPassword == newConfirmationPassword) return;
|
||||
m_confirmationPassword = newConfirmationPassword;
|
||||
emit confirmationPasswordChanged();
|
||||
}
|
||||
|
||||
const QString &NewAccountController::name() const
|
||||
const QString& NewAccountController::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void NewAccountController::setName(const QString &newName)
|
||||
void NewAccountController::setName(const QString& newName)
|
||||
{
|
||||
if (m_name == newName)
|
||||
return;
|
||||
if(m_name == newName) return;
|
||||
m_name = newName;
|
||||
emit nameChanged();
|
||||
}
|
||||
|
@ -109,19 +109,22 @@ void NewAccountController::onNodeLogin(const QString& error)
|
|||
void NewAccountController::checkAndUpdateDataValidity()
|
||||
{
|
||||
auto passwordValid = m_password.length() >= 6;
|
||||
if(passwordValid != m_passwordIsValid) {
|
||||
if(passwordValid != m_passwordIsValid)
|
||||
{
|
||||
m_passwordIsValid = passwordValid;
|
||||
emit passwordIsValidChanged();
|
||||
}
|
||||
|
||||
auto confirmationPasswordValid = m_password == m_confirmationPassword;
|
||||
if(confirmationPasswordValid != m_confirmationPasswordIsValid) {
|
||||
if(confirmationPasswordValid != m_confirmationPasswordIsValid)
|
||||
{
|
||||
m_confirmationPasswordIsValid = confirmationPasswordValid;
|
||||
emit confirmationPasswordIsValidChanged();
|
||||
}
|
||||
|
||||
auto nameValid = m_name.length() >= 10;
|
||||
if(nameValid != m_nameIsValid) {
|
||||
if(nameValid != m_nameIsValid)
|
||||
{
|
||||
m_nameIsValid = nameValid;
|
||||
emit nameIsValidChanged();
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ class ServiceInterface;
|
|||
*
|
||||
* \todo shared functionality should be moved to Common library (e.g. Name/Picture Validation)
|
||||
*/
|
||||
class NewAccountController: public QObject
|
||||
class NewAccountController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -28,10 +28,12 @@ class NewAccountController: public QObject
|
|||
QML_UNCREATABLE("Created and owned externally")
|
||||
|
||||
Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged)
|
||||
Q_PROPERTY(QString confirmationPassword READ confirmationPassword WRITE setConfirmationPassword NOTIFY confirmationPasswordChanged)
|
||||
Q_PROPERTY(QString confirmationPassword READ confirmationPassword WRITE setConfirmationPassword NOTIFY
|
||||
confirmationPasswordChanged)
|
||||
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
|
||||
Q_PROPERTY(bool passwordIsValid READ passwordIsValid NOTIFY passwordIsValidChanged)
|
||||
Q_PROPERTY(bool confirmationPasswordIsValid READ confirmationPasswordIsValid NOTIFY confirmationPasswordIsValidChanged)
|
||||
Q_PROPERTY(
|
||||
bool confirmationPasswordIsValid READ confirmationPasswordIsValid NOTIFY confirmationPasswordIsValidChanged)
|
||||
Q_PROPERTY(bool nameIsValid READ nameIsValid NOTIFY nameIsValidChanged)
|
||||
|
||||
public:
|
||||
|
@ -39,14 +41,14 @@ public:
|
|||
|
||||
Q_INVOKABLE void createAccount();
|
||||
|
||||
const QString &password() const;
|
||||
void setPassword(const QString &newPassword);
|
||||
const QString& password() const;
|
||||
void setPassword(const QString& newPassword);
|
||||
|
||||
const QString &confirmationPassword() const;
|
||||
void setConfirmationPassword(const QString &newConfirmationPassword);
|
||||
const QString& confirmationPassword() const;
|
||||
void setConfirmationPassword(const QString& newConfirmationPassword);
|
||||
|
||||
const QString &name() const;
|
||||
void setName(const QString &newName);
|
||||
const QString& name() const;
|
||||
void setName(const QString& newName);
|
||||
|
||||
bool passwordIsValid() const;
|
||||
bool confirmationPasswordIsValid() const;
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
|
||||
#include <Helpers/helpers.h>
|
||||
|
||||
namespace Status::Onboarding {
|
||||
namespace Status::Onboarding
|
||||
{
|
||||
|
||||
namespace StatusGo = Status::StatusGo;
|
||||
|
||||
|
@ -16,15 +17,20 @@ OnboardingController::OnboardingController(AccountsServiceInterfacePtr accountsS
|
|||
: QObject(nullptr)
|
||||
, m_accountsService(std::move(accountsService))
|
||||
{
|
||||
{ // Init accounts
|
||||
{ // Init accounts
|
||||
std::vector<std::shared_ptr<UserAccount>> accounts;
|
||||
for(auto &account : getOpenedAccounts()) {
|
||||
accounts.push_back(Helpers::makeSharedQObject<UserAccount>(std::make_unique<MultiAccount>(std::move(account))));
|
||||
for(auto& account : getOpenedAccounts())
|
||||
{
|
||||
accounts.push_back(
|
||||
Helpers::makeSharedQObject<UserAccount>(std::make_unique<MultiAccount>(std::move(account))));
|
||||
}
|
||||
m_accounts = Helpers::makeSharedQObject<UserAccountsModel>(std::move(accounts));
|
||||
}
|
||||
|
||||
connect(StatusGo::SignalsManager::instance(), &StatusGo::SignalsManager::nodeLogin, this, &OnboardingController::onLogin);
|
||||
connect(StatusGo::SignalsManager::instance(),
|
||||
&StatusGo::SignalsManager::nodeLogin,
|
||||
this,
|
||||
&OnboardingController::onLogin);
|
||||
}
|
||||
|
||||
OnboardingController::~OnboardingController()
|
||||
|
@ -50,16 +56,15 @@ void OnboardingController::login(QObject* user, const QString& password)
|
|||
auto account = qobject_cast<UserAccount*>(user);
|
||||
assert(account != nullptr);
|
||||
auto error = m_accountsService->login(account->accountData(), password);
|
||||
if(!error.isEmpty())
|
||||
emit accountLoginError(error);
|
||||
if(!error.isEmpty()) emit accountLoginError(error);
|
||||
}
|
||||
|
||||
UserAccountsModel *OnboardingController::accounts() const
|
||||
UserAccountsModel* OnboardingController::accounts() const
|
||||
{
|
||||
return m_accounts.get();
|
||||
}
|
||||
|
||||
NewAccountController *OnboardingController::initNewAccountController()
|
||||
NewAccountController* OnboardingController::initNewAccountController()
|
||||
{
|
||||
m_newAccountController = std::make_unique<NewAccountController>(m_accountsService);
|
||||
emit newAccountControllerChanged();
|
||||
|
@ -72,7 +77,7 @@ void OnboardingController::terminateNewAccountController()
|
|||
emit newAccountControllerChanged();
|
||||
}
|
||||
|
||||
NewAccountController *OnboardingController::newAccountController() const
|
||||
NewAccountController* OnboardingController::newAccountController() const
|
||||
{
|
||||
return m_newAccountController.get();
|
||||
}
|
||||
|
@ -82,4 +87,4 @@ AccountsServiceInterfacePtr OnboardingController::accountsService() const
|
|||
return m_accountsService;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::Onboarding
|
||||
|
|
|
@ -22,8 +22,7 @@ class NewAccountController;
|
|||
* \todo don't use DTOs in controllers, use QObjects directly
|
||||
* \todo make dependency on SignalManager explicit. Now it is hidden.
|
||||
*/
|
||||
class OnboardingController final : public QObject
|
||||
, public std::enable_shared_from_this<OnboardingController>
|
||||
class OnboardingController final : public QObject, public std::enable_shared_from_this<OnboardingController>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -44,11 +43,11 @@ public:
|
|||
/// TODO: \a user should be of type \c UserAccount but this doesn't work with Qt6 CMake API. Investigate and fix later on
|
||||
Q_INVOKABLE void login(QObject* user, const QString& password);
|
||||
|
||||
UserAccountsModel *accounts() const;
|
||||
UserAccountsModel* accounts() const;
|
||||
|
||||
Q_INVOKABLE Status::Onboarding::NewAccountController *initNewAccountController();
|
||||
Q_INVOKABLE Status::Onboarding::NewAccountController* initNewAccountController();
|
||||
Q_INVOKABLE void terminateNewAccountController();
|
||||
NewAccountController *newAccountController() const;
|
||||
NewAccountController* newAccountController() const;
|
||||
std::shared_ptr<AccountsServiceInterface> accountsService() const;
|
||||
|
||||
signals:
|
||||
|
@ -72,4 +71,4 @@ private:
|
|||
std::unique_ptr<NewAccountController> m_newAccountController;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Status::Onboarding
|
||||
|
|
|
@ -10,20 +10,20 @@ namespace AppCore = Status::ApplicationCore;
|
|||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace Status::Onboarding {
|
||||
namespace Status::Onboarding
|
||||
{
|
||||
|
||||
OnboardingModule::OnboardingModule(const fs::path& userDataPath, QObject *parent)
|
||||
OnboardingModule::OnboardingModule(const fs::path& userDataPath, QObject* parent)
|
||||
: OnboardingModule{parent}
|
||||
{
|
||||
m_userDataPath = userDataPath;
|
||||
initWithUserDataPath(m_userDataPath);
|
||||
}
|
||||
|
||||
OnboardingModule::OnboardingModule(QObject *parent)
|
||||
OnboardingModule::OnboardingModule(QObject* parent)
|
||||
: QObject{parent}
|
||||
, m_accountsService(std::make_shared<AccountsService>())
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
OnboardingController* OnboardingModule::controller() const
|
||||
{
|
||||
|
@ -32,20 +32,21 @@ OnboardingController* OnboardingModule::controller() const
|
|||
|
||||
void OnboardingModule::componentComplete()
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
initWithUserDataPath(m_userDataPath);
|
||||
} catch(const std::exception &e) {
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
qCritical() << "OnboardingModule: failed to initialize";
|
||||
}
|
||||
}
|
||||
|
||||
void OnboardingModule::initWithUserDataPath(const fs::path &path)
|
||||
void OnboardingModule::initWithUserDataPath(const fs::path& path)
|
||||
{
|
||||
auto result = m_accountsService->init(path);
|
||||
if(!result)
|
||||
throw std::runtime_error(std::string("Failed to initialize OnboadingService") + path.string());
|
||||
m_controller = Helpers::makeSharedQObject<OnboardingController>(
|
||||
m_accountsService);
|
||||
if(!result) throw std::runtime_error(std::string("Failed to initialize OnboadingService") + path.string());
|
||||
m_controller = Helpers::makeSharedQObject<OnboardingController>(m_accountsService);
|
||||
emit controllerChanged();
|
||||
}
|
||||
|
||||
|
@ -54,13 +55,12 @@ const QString OnboardingModule::userDataPath() const
|
|||
return QString::fromStdString(m_userDataPath.string());
|
||||
}
|
||||
|
||||
void OnboardingModule::setUserDataPath(const QString &newUserDataPath)
|
||||
void OnboardingModule::setUserDataPath(const QString& newUserDataPath)
|
||||
{
|
||||
auto newVal = newUserDataPath.toStdString();
|
||||
if (m_userDataPath.compare(newVal) == 0)
|
||||
return;
|
||||
if(m_userDataPath.compare(newVal) == 0) return;
|
||||
m_userDataPath = newVal;
|
||||
emit userDataPathChanged();
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::Onboarding
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace Status::Onboarding {
|
||||
namespace Status::Onboarding
|
||||
{
|
||||
|
||||
class AccountsService;
|
||||
|
||||
|
@ -31,16 +32,16 @@ class OnboardingModule : public QObject, public QQmlParserStatus
|
|||
Q_PROPERTY(QString userDataPath READ userDataPath WRITE setUserDataPath NOTIFY userDataPathChanged REQUIRED)
|
||||
|
||||
public:
|
||||
explicit OnboardingModule(const fs::path& userDataPath, QObject *parent = nullptr);
|
||||
explicit OnboardingModule(QObject *parent = nullptr);
|
||||
explicit OnboardingModule(const fs::path& userDataPath, QObject* parent = nullptr);
|
||||
explicit OnboardingModule(QObject* parent = nullptr);
|
||||
|
||||
OnboardingController* controller() const;
|
||||
|
||||
const QString userDataPath() const;
|
||||
void setUserDataPath(const QString &newUserDataPath);
|
||||
void setUserDataPath(const QString& newUserDataPath);
|
||||
|
||||
/// QML inteface
|
||||
void classBegin() override {};
|
||||
void classBegin() override{};
|
||||
void componentComplete() override;
|
||||
|
||||
signals:
|
||||
|
@ -48,9 +49,8 @@ signals:
|
|||
void userDataPathChanged();
|
||||
|
||||
private:
|
||||
|
||||
/// Throws exceptions
|
||||
void initWithUserDataPath(const fs::path &path);
|
||||
void initWithUserDataPath(const fs::path& path);
|
||||
|
||||
// TODO: plain object after refactoring shared_ptr requirement for now
|
||||
std::shared_ptr<AccountsService> m_accountsService;
|
||||
|
@ -59,4 +59,4 @@ private:
|
|||
fs::path m_userDataPath;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Status::Onboarding
|
||||
|
|
|
@ -8,15 +8,14 @@ namespace Status::Onboarding
|
|||
UserAccount::UserAccount(std::unique_ptr<MultiAccount> data)
|
||||
: QObject()
|
||||
, m_data(std::move(data))
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
const QString &UserAccount::name() const
|
||||
const QString& UserAccount::name() const
|
||||
{
|
||||
return m_data->name;
|
||||
}
|
||||
|
||||
const MultiAccount &UserAccount::accountData() const
|
||||
const MultiAccount& UserAccount::accountData() const
|
||||
{
|
||||
return *m_data;
|
||||
}
|
||||
|
@ -27,9 +26,7 @@ void UserAccount::updateAccountData(const MultiAccount& newData)
|
|||
|
||||
*m_data = newData;
|
||||
|
||||
if(newData.name != m_data->name)
|
||||
notifyUpdates.push_back([this]() { emit nameChanged(); });
|
||||
|
||||
if(newData.name != m_data->name) notifyUpdates.push_back([this]() { emit nameChanged(); });
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::Onboarding
|
||||
|
|
|
@ -13,7 +13,7 @@ class MultiAccount;
|
|||
* @see OnboardingController
|
||||
* @see UserAccountsModel
|
||||
*/
|
||||
class UserAccount: public QObject
|
||||
class UserAccount : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
@ -23,7 +23,7 @@ class UserAccount: public QObject
|
|||
public:
|
||||
explicit UserAccount(std::unique_ptr<MultiAccount> data);
|
||||
|
||||
const QString &name() const;
|
||||
const QString& name() const;
|
||||
|
||||
const MultiAccount& accountData() const;
|
||||
void updateAccountData(const MultiAccount& newData);
|
||||
|
@ -35,4 +35,4 @@ private:
|
|||
std::unique_ptr<MultiAccount> m_data;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Status::Onboarding
|
||||
|
|
|
@ -2,25 +2,19 @@
|
|||
|
||||
#include <QObject>
|
||||
|
||||
namespace Status::Onboarding {
|
||||
|
||||
namespace Status::Onboarding
|
||||
{
|
||||
|
||||
UserAccountsModel::UserAccountsModel(const std::vector<std::shared_ptr<UserAccount>> accounts, QObject* parent)
|
||||
: QAbstractListModel(parent)
|
||||
, m_accounts(std::move(accounts))
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
UserAccountsModel::~UserAccountsModel()
|
||||
{
|
||||
}
|
||||
UserAccountsModel::~UserAccountsModel() { }
|
||||
|
||||
QHash<int, QByteArray> UserAccountsModel::roleNames() const
|
||||
{
|
||||
static QHash<int, QByteArray> roles{
|
||||
{Name, "name"},
|
||||
{Account, "account"}
|
||||
};
|
||||
static QHash<int, QByteArray> roles{{Name, "name"}, {Account, "account"}};
|
||||
return roles;
|
||||
}
|
||||
|
||||
|
@ -32,14 +26,14 @@ int UserAccountsModel::rowCount(const QModelIndex& parent) const
|
|||
|
||||
QVariant UserAccountsModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if(!QAbstractItemModel::checkIndex(index))
|
||||
return QVariant();
|
||||
if(!QAbstractItemModel::checkIndex(index)) return QVariant();
|
||||
|
||||
switch(static_cast<ModelRole>(role)) {
|
||||
case Name: return QVariant::fromValue(m_accounts[index.row()].get()->name());
|
||||
case Account: return QVariant::fromValue<QObject*>(m_accounts[index.row()].get());
|
||||
default: return QVariant();
|
||||
switch(static_cast<ModelRole>(role))
|
||||
{
|
||||
case Name: return QVariant::fromValue(m_accounts[index.row()].get()->name());
|
||||
case Account: return QVariant::fromValue<QObject*>(m_accounts[index.row()].get());
|
||||
default: return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::Onboarding
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
|
||||
#include <QAbstractListModel>
|
||||
|
||||
namespace Status::Onboarding {
|
||||
namespace Status::Onboarding
|
||||
{
|
||||
|
||||
/// \todo Replace it with \c QObjectVectorModel
|
||||
class UserAccountsModel : public QAbstractListModel
|
||||
|
@ -14,12 +15,13 @@ class UserAccountsModel : public QAbstractListModel
|
|||
QML_ELEMENT
|
||||
QML_UNCREATABLE("Created by OnboardingController")
|
||||
|
||||
enum ModelRole {
|
||||
enum ModelRole
|
||||
{
|
||||
Name = Qt::UserRole + 1,
|
||||
Account
|
||||
};
|
||||
public:
|
||||
|
||||
public:
|
||||
explicit UserAccountsModel(const std::vector<std::shared_ptr<UserAccount>> accounts, QObject* parent = nullptr);
|
||||
~UserAccountsModel();
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
@ -30,4 +32,4 @@ private:
|
|||
const std::vector<std::shared_ptr<UserAccount>> m_accounts;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Status::Onboarding
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
namespace Status::Testing::Constants {
|
||||
namespace Status::Testing::Constants
|
||||
{
|
||||
|
||||
inline constexpr auto userDataDirName = "StatusTest";
|
||||
inline constexpr auto statusGoDataDirName = "data";
|
||||
|
@ -12,4 +13,4 @@ inline constexpr auto qtDataDirName = "qt";
|
|||
inline constexpr auto keystoreDataDirName = "keystore";
|
||||
inline constexpr auto globalSettingsFileName = "global";
|
||||
|
||||
}
|
||||
} // namespace Status::Testing::Constants
|
||||
|
|
|
@ -20,11 +20,12 @@ namespace Accounts = Status::StatusGo::Accounts;
|
|||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace Status::Testing {
|
||||
namespace Status::Testing
|
||||
{
|
||||
|
||||
ScopedTestAccount::ScopedTestAccount(const std::string &tempTestSubfolderName,
|
||||
const QString &accountName,
|
||||
const QString &accountPassword)
|
||||
ScopedTestAccount::ScopedTestAccount(const std::string& tempTestSubfolderName,
|
||||
const QString& accountName,
|
||||
const QString& accountPassword)
|
||||
: m_fusedTestFolder{std::make_unique<AutoCleanTempTestDir>(tempTestSubfolderName)}
|
||||
, m_accountName(accountName)
|
||||
, m_accountPassword(accountPassword)
|
||||
|
@ -41,7 +42,9 @@ ScopedTestAccount::ScopedTestAccount(const std::string &tempTestSubfolderName,
|
|||
auto accountsService = std::make_shared<Onboarding::AccountsService>();
|
||||
auto result = accountsService->init(m_testFolderPath);
|
||||
if(!result)
|
||||
{
|
||||
throw std::runtime_error("ScopedTestAccount - Failed to create temporary test account");
|
||||
}
|
||||
|
||||
// TODO refactor and merge account creation events with login into Onboarding controller
|
||||
//
|
||||
|
@ -51,41 +54,59 @@ ScopedTestAccount::ScopedTestAccount(const std::string &tempTestSubfolderName,
|
|||
// Beware, smartpointer is a requirement
|
||||
m_onboarding = Helpers::makeSharedQObject<Onboarding::OnboardingController>(accountsService);
|
||||
if(m_onboarding->getOpenedAccounts().size() != 0)
|
||||
{
|
||||
throw std::runtime_error("ScopedTestAccount - already have opened account");
|
||||
}
|
||||
|
||||
int accountLoggedInCount = 0;
|
||||
QObject::connect(m_onboarding.get(), &Onboarding::OnboardingController::accountLoggedIn, [&accountLoggedInCount]() {
|
||||
accountLoggedInCount++;
|
||||
});
|
||||
bool accountLoggedInError = false;
|
||||
QObject::connect(m_onboarding.get(), &Onboarding::OnboardingController::accountLoginError, [&accountLoggedInError]() {
|
||||
accountLoggedInError = true;
|
||||
});
|
||||
QObject::connect(m_onboarding.get(),
|
||||
&Onboarding::OnboardingController::accountLoginError,
|
||||
[&accountLoggedInError]() { accountLoggedInError = true; });
|
||||
|
||||
// Create Accounts
|
||||
auto genAccounts = accountsService->generatedAccounts();
|
||||
if(genAccounts.size() == 0)
|
||||
{
|
||||
throw std::runtime_error("ScopedTestAccount - missing generated accounts");
|
||||
}
|
||||
|
||||
if(accountsService->isFirstTimeAccountLogin())
|
||||
{
|
||||
throw std::runtime_error("ScopedTestAccount - Service::isFirstTimeAccountLogin returned true");
|
||||
}
|
||||
|
||||
if(!accountsService->setupAccountAndLogin(genAccounts[0].id, m_accountPassword, m_accountName))
|
||||
{
|
||||
throw std::runtime_error("ScopedTestAccount - Service::setupAccountAndLogin failed");
|
||||
}
|
||||
|
||||
if(!accountsService->isFirstTimeAccountLogin())
|
||||
{
|
||||
throw std::runtime_error("ScopedTestAccount - Service::isFirstTimeAccountLogin returned false");
|
||||
}
|
||||
if(!accountsService->getLoggedInAccount().isValid())
|
||||
{
|
||||
throw std::runtime_error("ScopedTestAccount - newly created account is not valid");
|
||||
}
|
||||
if(accountsService->getLoggedInAccount().name != accountName)
|
||||
{
|
||||
throw std::runtime_error("ScopedTestAccount - newly created account has a wrong name");
|
||||
processMessages(2000, [accountLoggedInCount]() {
|
||||
return accountLoggedInCount == 0;
|
||||
});
|
||||
}
|
||||
|
||||
processMessages(2000, [accountLoggedInCount]() { return accountLoggedInCount == 0; });
|
||||
|
||||
if(accountLoggedInCount != 1)
|
||||
{
|
||||
throw std::runtime_error("ScopedTestAccount - missing confirmation of account creation");
|
||||
}
|
||||
if(accountLoggedInError)
|
||||
{
|
||||
throw std::runtime_error("ScopedTestAccount - account loggedin error");
|
||||
}
|
||||
}
|
||||
|
||||
ScopedTestAccount::~ScopedTestAccount()
|
||||
|
@ -94,12 +115,14 @@ ScopedTestAccount::~ScopedTestAccount()
|
|||
m_onboarding->accountsService()->deleteMultiAccount(rootAccount);
|
||||
}
|
||||
|
||||
void ScopedTestAccount::processMessages(size_t maxWaitTimeMillis, std::function<bool()> shouldWaitUntilTimeout) {
|
||||
void ScopedTestAccount::processMessages(size_t maxWaitTimeMillis, std::function<bool()> shouldWaitUntilTimeout)
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
std::chrono::milliseconds maxWaitTime{maxWaitTimeMillis};
|
||||
auto iterationSleepTime = 2ms;
|
||||
auto remainingIterations = maxWaitTime/iterationSleepTime;
|
||||
while (remainingIterations-- > 0 && shouldWaitUntilTimeout()) {
|
||||
auto remainingIterations = maxWaitTime / iterationSleepTime;
|
||||
while(remainingIterations-- > 0 && shouldWaitUntilTimeout())
|
||||
{
|
||||
std::this_thread::sleep_for(iterationSleepTime);
|
||||
|
||||
QCoreApplication::sendPostedEvents();
|
||||
|
@ -109,44 +132,46 @@ void ScopedTestAccount::processMessages(size_t maxWaitTimeMillis, std::function<
|
|||
void ScopedTestAccount::logOut()
|
||||
{
|
||||
if(Status::StatusGo::Accounts::logout().containsError())
|
||||
{
|
||||
throw std::runtime_error("ScopedTestAccount - failed logging out");
|
||||
}
|
||||
}
|
||||
|
||||
Accounts::ChatOrWalletAccount ScopedTestAccount::firstChatAccount()
|
||||
{
|
||||
auto accounts = Accounts::getAccounts();
|
||||
auto chatIt = std::find_if(accounts.begin(), accounts.end(), [](const auto& a) {
|
||||
return a.isChat;
|
||||
});
|
||||
auto chatIt = std::find_if(accounts.begin(), accounts.end(), [](const auto& a) { return a.isChat; });
|
||||
if(chatIt == accounts.end())
|
||||
{
|
||||
throw std::runtime_error("ScopedTestAccount::chatAccount: account not found");
|
||||
}
|
||||
return *chatIt;
|
||||
}
|
||||
|
||||
Accounts::ChatOrWalletAccount ScopedTestAccount::firstWalletAccount()
|
||||
{
|
||||
auto accounts = Accounts::getAccounts();
|
||||
auto walletIt = std::find_if(accounts.begin(), accounts.end(), [](const auto& a) {
|
||||
return a.isWallet;
|
||||
});
|
||||
auto walletIt = std::find_if(accounts.begin(), accounts.end(), [](const auto& a) { return a.isWallet; });
|
||||
if(walletIt == accounts.end())
|
||||
{
|
||||
throw std::runtime_error("ScopedTestAccount::firstWalletAccount: account not found");
|
||||
}
|
||||
return *walletIt;
|
||||
}
|
||||
|
||||
const Onboarding::MultiAccount &ScopedTestAccount::loggedInAccount() const
|
||||
const Onboarding::MultiAccount& ScopedTestAccount::loggedInAccount() const
|
||||
{
|
||||
return m_onboarding->accountsService()->getLoggedInAccount();
|
||||
}
|
||||
|
||||
Onboarding::OnboardingController *ScopedTestAccount::onboardingController() const
|
||||
Onboarding::OnboardingController* ScopedTestAccount::onboardingController() const
|
||||
{
|
||||
return m_onboarding.get();
|
||||
}
|
||||
|
||||
const std::filesystem::path &ScopedTestAccount::fusedTestFolder() const
|
||||
const std::filesystem::path& ScopedTestAccount::fusedTestFolder() const
|
||||
{
|
||||
return m_testFolderPath;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::Testing
|
||||
|
|
|
@ -4,36 +4,39 @@
|
|||
|
||||
#include <StatusGo/Utils.h>
|
||||
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
#include <QString>
|
||||
|
||||
class QCoreApplication;
|
||||
|
||||
namespace Status::Onboarding {
|
||||
class OnboardingController;
|
||||
class MultiAccount;
|
||||
}
|
||||
namespace Status::Onboarding
|
||||
{
|
||||
class OnboardingController;
|
||||
class MultiAccount;
|
||||
} // namespace Status::Onboarding
|
||||
|
||||
namespace Wallet = Status::StatusGo::Wallet;
|
||||
namespace Accounts = Status::StatusGo::Accounts;
|
||||
namespace GoUtils = Status::StatusGo::Utils;
|
||||
|
||||
namespace Status::Testing {
|
||||
namespace Status::Testing
|
||||
{
|
||||
|
||||
class AutoCleanTempTestDir;
|
||||
|
||||
class ScopedTestAccount final {
|
||||
class ScopedTestAccount final
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Create and logs in a new test account
|
||||
* \param tempTestSubfolderName subfolder name of the temporary test folder where to initalize user data \see AutoCleanTempTestDir
|
||||
* \todo make it more flexible by splitting into create account, login and wait for events
|
||||
*/
|
||||
explicit ScopedTestAccount(const std::string &tempTestSubfolderName,
|
||||
const QString &accountName = defaultAccountName,
|
||||
const QString &accountPassword = defaultAccountPassword);
|
||||
explicit ScopedTestAccount(const std::string& tempTestSubfolderName,
|
||||
const QString& accountName = defaultAccountName,
|
||||
const QString& accountPassword = defaultAccountPassword);
|
||||
~ScopedTestAccount();
|
||||
|
||||
void processMessages(size_t millis, std::function<bool()> shouldWaitUntilTimeout);
|
||||
|
@ -42,10 +45,16 @@ public:
|
|||
static Accounts::ChatOrWalletAccount firstChatAccount();
|
||||
static Accounts::ChatOrWalletAccount firstWalletAccount();
|
||||
/// Root account
|
||||
const Status::Onboarding::MultiAccount &loggedInAccount() const;
|
||||
const Status::Onboarding::MultiAccount& loggedInAccount() const;
|
||||
|
||||
QString password() const { return m_accountPassword; };
|
||||
StatusGo::HashedPassword hashedPassword() const { return GoUtils::hashPassword(m_accountPassword); };
|
||||
QString password() const
|
||||
{
|
||||
return m_accountPassword;
|
||||
};
|
||||
StatusGo::HashedPassword hashedPassword() const
|
||||
{
|
||||
return GoUtils::hashPassword(m_accountPassword);
|
||||
};
|
||||
|
||||
Status::Onboarding::OnboardingController* onboardingController() const;
|
||||
|
||||
|
@ -65,4 +74,4 @@ private:
|
|||
static constexpr auto defaultAccountPassword = "test_pwd*";
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Status::Testing
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace Status::Testing
|
|||
class AccountsServiceMock final : public Onboarding::AccountsServiceInterface
|
||||
{
|
||||
public:
|
||||
virtual ~AccountsServiceMock() override {};
|
||||
virtual ~AccountsServiceMock() override{};
|
||||
|
||||
MOCK_METHOD(bool, init, (const fs::path&), (override));
|
||||
MOCK_METHOD(std::vector<Onboarding::MultiAccount>, openAndListAccounts, (), (override));
|
||||
|
@ -34,4 +34,4 @@ public:
|
|||
MOCK_METHOD(void, deleteMultiAccount, (const Onboarding::MultiAccount&), (override));
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Status::Testing
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "ServiceMock.h"
|
||||
|
||||
#include <IOTestHelpers.h>
|
||||
#include <Constants.h>
|
||||
#include <IOTestHelpers.h>
|
||||
|
||||
#include <StatusGo/Accounts/Accounts.h>
|
||||
|
||||
|
@ -15,7 +15,8 @@ namespace Onboarding = Status::Onboarding;
|
|||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace Status::Testing {
|
||||
namespace Status::Testing
|
||||
{
|
||||
|
||||
class AccountsService : public ::testing::Test
|
||||
{
|
||||
|
@ -23,19 +24,20 @@ protected:
|
|||
std::unique_ptr<Onboarding::AccountsService> m_accountsService;
|
||||
std::unique_ptr<Testing::AutoCleanTempTestDir> m_fusedTestFolder;
|
||||
|
||||
void SetUp() override {
|
||||
void SetUp() override
|
||||
{
|
||||
m_fusedTestFolder = std::make_unique<Testing::AutoCleanTempTestDir>("TestAccountsService");
|
||||
m_accountsService = std::make_unique<Onboarding::AccountsService>();
|
||||
m_accountsService->init(m_fusedTestFolder->tempFolder() / Constants::statusGoDataDirName);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
void TearDown() override
|
||||
{
|
||||
m_fusedTestFolder.reset();
|
||||
m_accountsService.reset();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TEST_F(AccountsService, GeneratedAccounts)
|
||||
{
|
||||
auto genAccounts = m_accountsService->generatedAccounts();
|
||||
|
@ -51,13 +53,16 @@ TEST_F(AccountsService, GeneratedAccounts)
|
|||
}
|
||||
}
|
||||
|
||||
TEST_F(AccountsService, DISABLED_GenerateAlias) // temporary disabled till we see what's happening on the status-go side since it doesn't return aliases for any pk
|
||||
TEST_F(
|
||||
AccountsService,
|
||||
DISABLED_GenerateAlias) // temporary disabled till we see what's happening on the status-go side since it doesn't return aliases for any pk
|
||||
{
|
||||
QString testPubKey = "0x04487f44bac3e90825bfa9720148308cb64835bebb7e888f519cebc127223187067629f8b70d0661a35d4af6516b225286";
|
||||
QString testPubKey =
|
||||
"0x04487f44bac3e90825bfa9720148308cb64835bebb7e888f519cebc127223187067629f8b70d0661a35d4af6516b225286";
|
||||
|
||||
auto alias = m_accountsService->generateAlias(testPubKey);
|
||||
|
||||
ASSERT_NE(alias, QString(""));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace Status::Testing
|
||||
|
|
|
@ -17,7 +17,8 @@ namespace Onboarding = Status::Onboarding;
|
|||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace Status::Testing {
|
||||
namespace Status::Testing
|
||||
{
|
||||
|
||||
class LoginTest : public ::testing::Test
|
||||
{
|
||||
|
@ -27,20 +28,24 @@ protected:
|
|||
std::unique_ptr<Onboarding::AccountsService> m_accountsService;
|
||||
std::unique_ptr<Testing::AutoCleanTempTestDir> m_fusedTestFolder;
|
||||
|
||||
static void SetUpTestSuite() {
|
||||
static void SetUpTestSuite()
|
||||
{
|
||||
m_accountsServiceMock = std::make_shared<AccountsServiceMock>();
|
||||
}
|
||||
static void TearDownTestSuite() {
|
||||
static void TearDownTestSuite()
|
||||
{
|
||||
m_accountsServiceMock.reset();
|
||||
}
|
||||
|
||||
void SetUp() override {
|
||||
void SetUp() override
|
||||
{
|
||||
m_fusedTestFolder = std::make_unique<Testing::AutoCleanTempTestDir>("LoginTest");
|
||||
m_accountsService = std::make_unique<Onboarding::AccountsService>();
|
||||
m_accountsService->init(m_fusedTestFolder->tempFolder() / Constants::statusGoDataDirName);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
void TearDown() override
|
||||
{
|
||||
m_fusedTestFolder.release();
|
||||
m_accountsService.release();
|
||||
}
|
||||
|
@ -54,4 +59,4 @@ TEST_F(LoginTest, DISABLED_TestLoginController)
|
|||
auto controller = Helpers::makeSharedQObject<Onboarding::OnboardingController>(m_accountsServiceMock);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace Status::Testing
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
#include <Onboarding/Accounts/AccountsService.h>
|
||||
#include <Onboarding/OnboardingController.h>
|
||||
|
||||
#include <StatusGo/SignalsManager.h>
|
||||
#include <StatusGo/Accounts/Accounts.h>
|
||||
#include <StatusGo/SignalsManager.h>
|
||||
|
||||
#include <ScopedTestAccount.h>
|
||||
|
||||
|
@ -21,7 +21,8 @@ namespace Onboarding = Status::Onboarding;
|
|||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace Status::Testing {
|
||||
namespace Status::Testing
|
||||
{
|
||||
|
||||
static std::unique_ptr<Onboarding::AccountsService> m_accountsServiceMock;
|
||||
|
||||
|
@ -89,8 +90,9 @@ TEST(OnboardingModule, TestCreateAndLoginAccountEndToEnd)
|
|||
using namespace std::chrono_literals;
|
||||
auto maxWaitTime = 2000ms;
|
||||
auto iterationSleepTime = 2ms;
|
||||
auto remainingIterations = maxWaitTime/iterationSleepTime;
|
||||
while (remainingIterations-- > 0 && accountLoggedInCount == 0) {
|
||||
auto remainingIterations = maxWaitTime / iterationSleepTime;
|
||||
while(remainingIterations-- > 0 && accountLoggedInCount == 0)
|
||||
{
|
||||
std::this_thread::sleep_for(iterationSleepTime);
|
||||
|
||||
QCoreApplication::sendPostedEvents();
|
||||
|
@ -110,20 +112,23 @@ TEST(OnboardingModule, TestLoginEndToEnd)
|
|||
// Create test account and login
|
||||
//
|
||||
bool createAndLogin = false;
|
||||
QObject::connect(StatusGo::SignalsManager::instance(), &StatusGo::SignalsManager::nodeLogin, [&createAndLogin](const QString& error) {
|
||||
if(error.isEmpty()) {
|
||||
if(createAndLogin) {
|
||||
createAndLogin = false;
|
||||
} else
|
||||
createAndLogin = true;
|
||||
}
|
||||
});
|
||||
QObject::connect(StatusGo::SignalsManager::instance(),
|
||||
&StatusGo::SignalsManager::nodeLogin,
|
||||
[&createAndLogin](const QString& error) {
|
||||
if(error.isEmpty())
|
||||
{
|
||||
if(createAndLogin)
|
||||
{
|
||||
createAndLogin = false;
|
||||
}
|
||||
else
|
||||
createAndLogin = true;
|
||||
}
|
||||
});
|
||||
|
||||
constexpr auto accountName = "TestLoginAccountName";
|
||||
ScopedTestAccount testAccount(test_info_->name(), accountName);
|
||||
testAccount.processMessages(1000, [createAndLogin]() {
|
||||
return !createAndLogin;
|
||||
});
|
||||
testAccount.processMessages(1000, [createAndLogin]() { return !createAndLogin; });
|
||||
ASSERT_TRUE(createAndLogin);
|
||||
|
||||
testAccount.logOut();
|
||||
|
@ -148,14 +153,15 @@ TEST(OnboardingModule, TestLoginEndToEnd)
|
|||
accountLoggedInCount++;
|
||||
});
|
||||
bool accountLoggedInError = false;
|
||||
QObject::connect(onboarding.get(), &Onboarding::OnboardingController::accountLoginError,
|
||||
QObject::connect(onboarding.get(),
|
||||
&Onboarding::OnboardingController::accountLoginError,
|
||||
[&accountLoggedInError](const QString& error) {
|
||||
accountLoggedInError = true;
|
||||
qDebug() << "Failed logging in in test" << test_info_->name() << "with error:" << error;
|
||||
}
|
||||
);
|
||||
accountLoggedInError = true;
|
||||
qDebug() << "Failed logging in in test" << test_info_->name() << "with error:" << error;
|
||||
});
|
||||
|
||||
auto ourAccountRes = std::find_if(accounts.begin(), accounts.end(), [accountName](const auto &a) { return a.name == accountName; });
|
||||
auto ourAccountRes =
|
||||
std::find_if(accounts.begin(), accounts.end(), [accountName](const auto& a) { return a.name == accountName; });
|
||||
auto errorString = accountsService->login(*ourAccountRes, testAccount.password());
|
||||
ASSERT_EQ(errorString.length(), 0);
|
||||
|
||||
|
@ -186,13 +192,16 @@ TEST(OnboardingModule, TestLoginEndToEnd_WrongPassword)
|
|||
});
|
||||
bool accountLoggedInError = false;
|
||||
QString loginErrorMessage;
|
||||
QObject::connect(onboarding.get(), &Onboarding::OnboardingController::accountLoginError,
|
||||
QObject::connect(onboarding.get(),
|
||||
&Onboarding::OnboardingController::accountLoginError,
|
||||
[&loginErrorMessage, &accountLoggedInError](const QString& error) {
|
||||
accountLoggedInError = true;
|
||||
loginErrorMessage = error;
|
||||
});
|
||||
accountLoggedInError = true;
|
||||
loginErrorMessage = error;
|
||||
});
|
||||
|
||||
auto ourAccountRes = std::find_if(accounts.begin(), accounts.end(), [testRootAccountName](const auto &a) { return a.name == testRootAccountName; });
|
||||
auto ourAccountRes = std::find_if(accounts.begin(), accounts.end(), [testRootAccountName](const auto& a) {
|
||||
return a.name == testRootAccountName;
|
||||
});
|
||||
auto errorString = accountsService->login(*ourAccountRes, testAccount.password() + "extra");
|
||||
ASSERT_EQ(errorString.length(), 0);
|
||||
|
||||
|
@ -204,4 +213,4 @@ TEST(OnboardingModule, TestLoginEndToEnd_WrongPassword)
|
|||
ASSERT_EQ(loginErrorMessage, "file is not a database");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace Status::Testing
|
||||
|
|
|
@ -7,16 +7,15 @@
|
|||
const int NUMBER_OF_ADDRESSES_TO_GENERATE = 5;
|
||||
const int MNEMONIC_PHRASE_LENGTH = 12;
|
||||
|
||||
namespace Status::StatusGo::Accounts {
|
||||
namespace Status::StatusGo::Accounts
|
||||
{
|
||||
|
||||
RpcResponse<QJsonArray> generateAddresses(const std::vector<Accounts::DerivationPath>& paths)
|
||||
{
|
||||
QJsonObject payload{
|
||||
{"n", NUMBER_OF_ADDRESSES_TO_GENERATE},
|
||||
{"mnemonicPhraseLength", MNEMONIC_PHRASE_LENGTH},
|
||||
{"bip32Passphrase", ""},
|
||||
{"paths", Utils::toJsonArray(paths)}
|
||||
};
|
||||
QJsonObject payload{{"n", NUMBER_OF_ADDRESSES_TO_GENERATE},
|
||||
{"mnemonicPhraseLength", MNEMONIC_PHRASE_LENGTH},
|
||||
{"bip32Passphrase", ""},
|
||||
{"paths", Utils::toJsonArray(paths)}};
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -30,13 +29,13 @@ RpcResponse<QJsonArray> generateAddresses(const std::vector<Accounts::Derivation
|
|||
|
||||
return Utils::buildPrivateRPCResponse(jsonResult);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
catch(std::exception& e)
|
||||
{
|
||||
auto response = RpcResponse<QJsonArray>(QJsonArray());
|
||||
response.error.message = QObject::tr("an error generating address occurred, msg: %1").arg(e.what());
|
||||
return response;
|
||||
}
|
||||
catch (...)
|
||||
catch(...)
|
||||
{
|
||||
auto response = RpcResponse<QJsonArray>(QJsonArray());
|
||||
response.error.message = QObject::tr("an error generating address occurred");
|
||||
|
@ -56,7 +55,7 @@ RpcResponse<QString> generateAlias(const QString& publicKey)
|
|||
|
||||
return Utils::buildPrivateRPCResponse(alias);
|
||||
}
|
||||
catch (...)
|
||||
catch(...)
|
||||
{
|
||||
auto response = RpcResponse<QString>(QString());
|
||||
response.error.message = QObject::tr("an error generating alias occurred");
|
||||
|
@ -64,13 +63,11 @@ RpcResponse<QString> generateAlias(const QString& publicKey)
|
|||
}
|
||||
}
|
||||
|
||||
RpcResponse<QJsonObject> storeDerivedAccounts(const QString& id, const HashedPassword& password, const std::vector<Accounts::DerivationPath>& paths)
|
||||
RpcResponse<QJsonObject> storeDerivedAccounts(const QString& id,
|
||||
const HashedPassword& password,
|
||||
const std::vector<Accounts::DerivationPath>& paths)
|
||||
{
|
||||
QJsonObject payload{
|
||||
{"accountID", id},
|
||||
{"paths", Utils::toJsonArray(paths)},
|
||||
{"password", password.get()}
|
||||
};
|
||||
QJsonObject payload{{"accountID", id}, {"paths", Utils::toJsonArray(paths)}, {"password", password.get()}};
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -86,13 +83,13 @@ RpcResponse<QJsonObject> storeDerivedAccounts(const QString& id, const HashedPas
|
|||
rpcResponse.error = Utils::getRPCErrorInJson(jsonResult).value_or(RpcError());
|
||||
return rpcResponse;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
catch(std::exception& e)
|
||||
{
|
||||
auto response = RpcResponse<QJsonObject>(QJsonObject());
|
||||
response.error.message = QObject::tr("an error storing derived accounts occurred, msg: %1").arg(e.what());
|
||||
return response;
|
||||
}
|
||||
catch (...)
|
||||
catch(...)
|
||||
{
|
||||
auto response = RpcResponse<QJsonObject>(QJsonObject());
|
||||
response.error.message = QObject::tr("an error storing derived accounts occurred");
|
||||
|
@ -102,10 +99,7 @@ RpcResponse<QJsonObject> storeDerivedAccounts(const QString& id, const HashedPas
|
|||
|
||||
RpcResponse<QJsonObject> storeAccount(const QString& id, const HashedPassword& password)
|
||||
{
|
||||
QJsonObject payload{
|
||||
{"accountID", id},
|
||||
{"password", password.get()}
|
||||
};
|
||||
QJsonObject payload{{"accountID", id}, {"password", password.get()}};
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -121,13 +115,13 @@ RpcResponse<QJsonObject> storeAccount(const QString& id, const HashedPassword& p
|
|||
rpcResponse.error = Utils::getRPCErrorInJson(jsonResult).value_or(RpcError());
|
||||
return rpcResponse;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
catch(std::exception& e)
|
||||
{
|
||||
auto response = RpcResponse<QJsonObject>(QJsonObject());
|
||||
response.error.message = QObject::tr("an error storing account occurred, msg: %1").arg(e.what());
|
||||
return response;
|
||||
}
|
||||
catch (...)
|
||||
catch(...)
|
||||
{
|
||||
auto response = RpcResponse<QJsonObject>(QJsonObject());
|
||||
response.error.message = QObject::tr("an error storing account occurred");
|
||||
|
@ -135,8 +129,10 @@ RpcResponse<QJsonObject> storeAccount(const QString& id, const HashedPassword& p
|
|||
}
|
||||
}
|
||||
|
||||
bool saveAccountAndLogin(const HashedPassword& password, const QJsonObject& account,
|
||||
const QJsonArray& subaccounts, const QJsonObject& settings,
|
||||
bool saveAccountAndLogin(const HashedPassword& password,
|
||||
const QJsonObject& account,
|
||||
const QJsonArray& subaccounts,
|
||||
const QJsonObject& settings,
|
||||
const QJsonObject& nodeConfig)
|
||||
{
|
||||
try
|
||||
|
@ -154,9 +150,13 @@ bool saveAccountAndLogin(const HashedPassword& password, const QJsonObject& acco
|
|||
}
|
||||
|
||||
return !Utils::getRPCErrorInJson(jsonResult).has_value();
|
||||
} catch (std::exception& e) {
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
qWarning() << QString("an error saving account and login occurred, msg: %1").arg(e.what());
|
||||
} catch (...) {
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
qWarning() << "an error saving account and login occurred";
|
||||
}
|
||||
return false;
|
||||
|
@ -167,24 +167,24 @@ RpcResponse<QJsonArray> openAccounts(const char* dataDirPath)
|
|||
try
|
||||
{
|
||||
auto result = QString(OpenAccounts(const_cast<char*>(dataDirPath)));
|
||||
if(result == "null")
|
||||
return RpcResponse<QJsonArray>(QJsonArray());
|
||||
if(result == "null") return RpcResponse<QJsonArray>(QJsonArray());
|
||||
|
||||
QJsonArray jsonResult;
|
||||
if(!Utils::checkReceivedResponse(result, jsonResult)) {
|
||||
if(!Utils::checkReceivedResponse(result, jsonResult))
|
||||
{
|
||||
throw std::domain_error("parsing response failed");
|
||||
}
|
||||
|
||||
return Utils::buildPrivateRPCResponse(jsonResult);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
catch(std::exception& e)
|
||||
{
|
||||
auto response = RpcResponse<QJsonArray>(QJsonArray());
|
||||
// TODO: don't translate exception messages. Exceptions are for developers and should never reach users
|
||||
response.error.message = QObject::tr("an error opening accounts occurred, msg: %1").arg(e.what());
|
||||
return response;
|
||||
}
|
||||
catch (...)
|
||||
catch(...)
|
||||
{
|
||||
auto response = RpcResponse<QJsonArray>(QJsonArray());
|
||||
response.error.message = QObject::tr("an error opening accounts occurred");
|
||||
|
@ -192,14 +192,13 @@ RpcResponse<QJsonArray> openAccounts(const char* dataDirPath)
|
|||
}
|
||||
}
|
||||
|
||||
RpcResponse<QJsonObject> login(const QString& name, const QString& keyUid, const HashedPassword& password,
|
||||
const QString& thumbnail, const QString& large)
|
||||
RpcResponse<QJsonObject> login(const QString& name,
|
||||
const QString& keyUid,
|
||||
const HashedPassword& password,
|
||||
const QString& thumbnail,
|
||||
const QString& large)
|
||||
{
|
||||
QJsonObject payload{
|
||||
{"name", name},
|
||||
{"key-uid", keyUid},
|
||||
{"identityImage", QJsonValue()}
|
||||
};
|
||||
QJsonObject payload{{"name", name}, {"key-uid", keyUid}, {"identityImage", QJsonValue()}};
|
||||
|
||||
if(!thumbnail.isEmpty() && !large.isEmpty())
|
||||
{
|
||||
|
@ -219,13 +218,13 @@ RpcResponse<QJsonObject> login(const QString& name, const QString& keyUid, const
|
|||
|
||||
return Utils::buildPrivateRPCResponse(jsonResult);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
catch(std::exception& e)
|
||||
{
|
||||
auto response = RpcResponse<QJsonObject>(QJsonObject());
|
||||
response.error.message = QObject::tr("an error logining in account occurred, msg: %1").arg(e.what());
|
||||
return response;
|
||||
}
|
||||
catch (...)
|
||||
catch(...)
|
||||
{
|
||||
auto response = RpcResponse<QJsonObject>(QJsonObject());
|
||||
response.error.message = QObject::tr("an error logining in account occurred");
|
||||
|
@ -233,8 +232,12 @@ RpcResponse<QJsonObject> login(const QString& name, const QString& keyUid, const
|
|||
}
|
||||
}
|
||||
|
||||
RpcResponse<QJsonObject> loginWithConfig(const QString& name, const QString& keyUid, const HashedPassword& password,
|
||||
const QString& thumbnail, const QString& large, const QJsonObject& nodeConfig)
|
||||
RpcResponse<QJsonObject> loginWithConfig(const QString& name,
|
||||
const QString& keyUid,
|
||||
const HashedPassword& password,
|
||||
const QString& thumbnail,
|
||||
const QString& large,
|
||||
const QJsonObject& nodeConfig)
|
||||
{
|
||||
QJsonObject payload{
|
||||
{"name", name},
|
||||
|
@ -261,13 +264,13 @@ RpcResponse<QJsonObject> loginWithConfig(const QString& name, const QString& key
|
|||
|
||||
return Utils::buildPrivateRPCResponse(jsonResult);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
catch(std::exception& e)
|
||||
{
|
||||
auto response = RpcResponse<QJsonObject>(QJsonObject());
|
||||
response.error.message = QObject::tr("an error logining in account occurred, msg: %1").arg(e.what());
|
||||
return response;
|
||||
}
|
||||
catch (...)
|
||||
catch(...)
|
||||
{
|
||||
auto response = RpcResponse<QJsonObject>(QJsonObject());
|
||||
response.error.message = QObject::tr("an error logining in account occurred");
|
||||
|
@ -291,13 +294,13 @@ RpcResponse<QJsonObject> logout()
|
|||
rpcResponse.error = Utils::getRPCErrorInJson(jsonResult).value_or(RpcError());
|
||||
return rpcResponse;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
catch(std::exception& e)
|
||||
{
|
||||
auto response = RpcResponse<QJsonObject>(QJsonObject());
|
||||
response.error.message = QObject::tr("an error logging out account occurred, msg: %1").arg(e.what());
|
||||
return response;
|
||||
}
|
||||
catch (...)
|
||||
catch(...)
|
||||
{
|
||||
auto response = RpcResponse<QJsonObject>(QJsonObject());
|
||||
response.error.message = QObject::tr("an error logging out account occurred");
|
||||
|
@ -305,4 +308,4 @@ RpcResponse<QJsonObject> logout()
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::StatusGo::Accounts
|
||||
|
|
|
@ -7,25 +7,35 @@
|
|||
|
||||
namespace Status::StatusGo::Accounts
|
||||
{
|
||||
RpcResponse<QJsonArray> generateAddresses(const std::vector<Accounts::DerivationPath> &paths);
|
||||
RpcResponse<QJsonArray> generateAddresses(const std::vector<Accounts::DerivationPath>& paths);
|
||||
|
||||
RpcResponse<QString> generateAlias(const QString& publicKey);
|
||||
RpcResponse<QString> generateAlias(const QString& publicKey);
|
||||
|
||||
RpcResponse<QJsonObject> storeDerivedAccounts(const QString& accountId, const HashedPassword& password,
|
||||
const std::vector<Accounts::DerivationPath>& paths);
|
||||
RpcResponse<QJsonObject> storeDerivedAccounts(const QString& accountId,
|
||||
const HashedPassword& password,
|
||||
const std::vector<Accounts::DerivationPath>& paths);
|
||||
|
||||
RpcResponse<QJsonObject> storeAccount(const QString& id, const HashedPassword& password);
|
||||
RpcResponse<QJsonObject> storeAccount(const QString& id, const HashedPassword& password);
|
||||
|
||||
bool saveAccountAndLogin(const StatusGo::HashedPassword& password, const QJsonObject& account,
|
||||
const QJsonArray& subaccounts, const QJsonObject& settings,
|
||||
const QJsonObject& nodeConfig);
|
||||
bool saveAccountAndLogin(const StatusGo::HashedPassword& password,
|
||||
const QJsonObject& account,
|
||||
const QJsonArray& subaccounts,
|
||||
const QJsonObject& settings,
|
||||
const QJsonObject& nodeConfig);
|
||||
|
||||
/// opens database and returns accounts list.
|
||||
RpcResponse<QJsonArray> openAccounts(const char* dataDirPath);
|
||||
/// opens database and returns accounts list.
|
||||
RpcResponse<QJsonArray> openAccounts(const char* dataDirPath);
|
||||
|
||||
RpcResponse<QJsonObject> login(const QString& name, const QString& keyUid, const HashedPassword& password,
|
||||
const QString& thumbnail, const QString& large);
|
||||
RpcResponse<QJsonObject> loginWithConfig(const QString& name, const QString& keyUid, const HashedPassword& password,
|
||||
const QString& thumbnail, const QString& large, const QJsonObject& nodeConfig);
|
||||
RpcResponse<QJsonObject> logout();
|
||||
}
|
||||
RpcResponse<QJsonObject> login(const QString& name,
|
||||
const QString& keyUid,
|
||||
const HashedPassword& password,
|
||||
const QString& thumbnail,
|
||||
const QString& large);
|
||||
RpcResponse<QJsonObject> loginWithConfig(const QString& name,
|
||||
const QString& keyUid,
|
||||
const HashedPassword& password,
|
||||
const QString& thumbnail,
|
||||
const QString& large,
|
||||
const QJsonObject& nodeConfig);
|
||||
RpcResponse<QJsonObject> logout();
|
||||
} // namespace Status::StatusGo::Accounts
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "AccountsAPI.h"
|
||||
|
||||
#include "Utils.h"
|
||||
#include "Metadata/api_response.h"
|
||||
#include "Utils.h"
|
||||
|
||||
#include <libstatus.h>
|
||||
|
||||
|
@ -14,13 +14,10 @@ using json = nlohmann::json;
|
|||
namespace Status::StatusGo::Accounts
|
||||
{
|
||||
|
||||
Accounts::ChatOrWalletAccounts getAccounts() {
|
||||
Accounts::ChatOrWalletAccounts getAccounts()
|
||||
{
|
||||
// or even nicer with a raw string literal
|
||||
json inputJson = {
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "accounts_getAccounts"},
|
||||
{"params", json::array()}
|
||||
};
|
||||
json inputJson = {{"jsonrpc", "2.0"}, {"method", "accounts_getAccounts"}, {"params", json::array()}};
|
||||
|
||||
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
|
||||
auto resultJson = json::parse(result);
|
||||
|
@ -29,71 +26,63 @@ Accounts::ChatOrWalletAccounts getAccounts() {
|
|||
return resultJson.get<CallPrivateRpcResponse>().result;
|
||||
}
|
||||
|
||||
void generateAccountWithDerivedPath(const HashedPassword &password, const QString &name, const QColor &color, const QString &emoji,
|
||||
const DerivationPath &path, const EOAddress &derivedFrom)
|
||||
void generateAccountWithDerivedPath(const HashedPassword& password,
|
||||
const QString& name,
|
||||
const QColor& color,
|
||||
const QString& emoji,
|
||||
const DerivationPath& path,
|
||||
const EOAddress& derivedFrom)
|
||||
{
|
||||
std::vector<json> params = {password, name, color, emoji, path, derivedFrom};
|
||||
json inputJson = {
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "accounts_generateAccountWithDerivedPath"},
|
||||
{"params", params}
|
||||
};
|
||||
json inputJson = {{"jsonrpc", "2.0"}, {"method", "accounts_generateAccountWithDerivedPath"}, {"params", params}};
|
||||
|
||||
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
|
||||
auto resultJson = json::parse(result);
|
||||
checkPrivateRpcCallResultAndReportError(resultJson);
|
||||
|
||||
}
|
||||
|
||||
void addAccountWithMnemonicAndPath(const QString &mnemonic, const HashedPassword &password, const QString &name,
|
||||
const QColor &color, const QString &emoji, const DerivationPath &path)
|
||||
void addAccountWithMnemonicAndPath(const QString& mnemonic,
|
||||
const HashedPassword& password,
|
||||
const QString& name,
|
||||
const QColor& color,
|
||||
const QString& emoji,
|
||||
const DerivationPath& path)
|
||||
{
|
||||
std::vector<json> params = {mnemonic, password, name, color, emoji, path};
|
||||
json inputJson = {
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "accounts_addAccountWithMnemonicAndPath"},
|
||||
{"params", params}
|
||||
};
|
||||
json inputJson = {{"jsonrpc", "2.0"}, {"method", "accounts_addAccountWithMnemonicAndPath"}, {"params", params}};
|
||||
|
||||
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
|
||||
auto resultJson = json::parse(result);
|
||||
checkPrivateRpcCallResultAndReportError(resultJson);
|
||||
}
|
||||
|
||||
void addAccountWatch(const EOAddress &address, const QString &name, const QColor &color, const QString &emoji)
|
||||
void addAccountWatch(const EOAddress& address, const QString& name, const QColor& color, const QString& emoji)
|
||||
{
|
||||
std::vector<json> params = {address, name, color, emoji};
|
||||
json inputJson = {
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "accounts_addAccountWatch"},
|
||||
{"params", params}
|
||||
};
|
||||
json inputJson = {{"jsonrpc", "2.0"}, {"method", "accounts_addAccountWatch"}, {"params", params}};
|
||||
|
||||
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
|
||||
auto resultJson = json::parse(result);
|
||||
checkPrivateRpcCallResultAndReportError(resultJson);
|
||||
}
|
||||
|
||||
void deleteAccount(const EOAddress &address)
|
||||
void deleteAccount(const EOAddress& address)
|
||||
{
|
||||
std::vector<json> params = {address};
|
||||
json inputJson = {
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "accounts_deleteAccount"},
|
||||
{"params", params}
|
||||
};
|
||||
json inputJson = {{"jsonrpc", "2.0"}, {"method", "accounts_deleteAccount"}, {"params", params}};
|
||||
|
||||
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
|
||||
auto resultJson = json::parse(result);
|
||||
checkPrivateRpcCallResultAndReportError(resultJson);
|
||||
}
|
||||
|
||||
void deleteMultiaccount(const QString &keyUID, const fs::path &keyStoreDir)
|
||||
void deleteMultiaccount(const QString& keyUID, const fs::path& keyStoreDir)
|
||||
{
|
||||
// We know go bridge won't misbehave with the input arguments
|
||||
auto result = DeleteMultiaccount(const_cast<char*>(keyUID.toStdString().c_str()), const_cast<char*>(keyStoreDir.string().c_str()));
|
||||
auto result = DeleteMultiaccount(const_cast<char*>(keyUID.toStdString().c_str()),
|
||||
const_cast<char*>(keyStoreDir.string().c_str()));
|
||||
auto resultJson = json::parse(result);
|
||||
checkApiError(resultJson);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::StatusGo::Accounts
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
#include "Accounts/ChatOrWalletAccount.h"
|
||||
#include "Accounts/accounts_types.h"
|
||||
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
|
||||
namespace Accounts = Status::StatusGo::Accounts;
|
||||
|
||||
|
@ -28,33 +28,40 @@ Accounts::ChatOrWalletAccounts getAccounts();
|
|||
/// \note the underlying status-go API, SaveAccounts@accounts.go, returns `nil` for \c CallPrivateRpcResponse.result
|
||||
/// \see \c getAccounts
|
||||
/// \throws \c CallPrivateRpcError
|
||||
void generateAccountWithDerivedPath(const HashedPassword &password, const QString &name,
|
||||
const QColor &color, const QString &emoji,
|
||||
const DerivationPath &path, const Accounts::EOAddress &derivedFrom);
|
||||
void generateAccountWithDerivedPath(const HashedPassword& password,
|
||||
const QString& name,
|
||||
const QColor& color,
|
||||
const QString& emoji,
|
||||
const DerivationPath& path,
|
||||
const Accounts::EOAddress& derivedFrom);
|
||||
|
||||
/// \brief Add a new account from an existing mnemonic
|
||||
/// \note the underlying status-go api, SaveAccounts@accounts.go, returns `nil` for \c CallPrivateRpcResponse.result
|
||||
/// \see \c getAccounts
|
||||
/// \throws \c CallPrivateRpcError
|
||||
void addAccountWithMnemonicAndPath(const QString &mnemonic, const HashedPassword &password, const QString &name,
|
||||
const QColor &color, const QString &emoji, const DerivationPath &path);
|
||||
void addAccountWithMnemonicAndPath(const QString& mnemonic,
|
||||
const HashedPassword& password,
|
||||
const QString& name,
|
||||
const QColor& color,
|
||||
const QString& emoji,
|
||||
const DerivationPath& path);
|
||||
|
||||
/// \brief Add a watch only account
|
||||
/// \note the underlying status-go api, SaveAccounts@accounts.go, returns `nil` for \c CallPrivateRpcResponse.result
|
||||
/// \see \c getAccounts
|
||||
/// \throws \c CallPrivateRpcError
|
||||
void addAccountWatch(const EOAddress &address, const QString &name, const QColor &color, const QString &emoji);
|
||||
void addAccountWatch(const EOAddress& address, const QString& name, const QColor& color, const QString& emoji);
|
||||
|
||||
/// \brief Delete an existing account
|
||||
/// \note the underlying status-go api, DeleteAccount@accounts.go, returns `os.Remove(keyFile)`
|
||||
/// \see \c getAccounts
|
||||
/// \throws \c CallPrivateRpcError
|
||||
void deleteAccount(const EOAddress &address);
|
||||
void deleteAccount(const EOAddress& address);
|
||||
|
||||
/// \brief Delete an existing account
|
||||
/// \note the underlying status-go api, DeleteAccount@accounts.go, returns `os.Remove(keyFile)`
|
||||
/// \see \c getAccounts
|
||||
/// \throws \c CallPrivateRpcError
|
||||
void deleteMultiaccount(const QString &keyUID, const fs::path &keyStoreDir);
|
||||
void deleteMultiaccount(const QString& keyUID, const fs::path& keyStoreDir);
|
||||
|
||||
} // namespaces
|
||||
} // namespace Status::StatusGo::Accounts
|
||||
|
|
|
@ -1,27 +1,30 @@
|
|||
#include "ChatOrWalletAccount.h"
|
||||
|
||||
namespace Status::StatusGo::Accounts {
|
||||
namespace Status::StatusGo::Accounts
|
||||
{
|
||||
|
||||
void to_json(json& j, const ChatOrWalletAccount& d) {
|
||||
j = {{"address", d.address},
|
||||
{"chat", d.isChat},
|
||||
{"clock", d.clock},
|
||||
{"color", d.color},
|
||||
{"emoji", d.emoji},
|
||||
{"hidden", d.isHidden},
|
||||
{"mixedcase-address", d.mixedcaseAddress},
|
||||
{"name", d.name},
|
||||
{"path", d.path},
|
||||
{"public-key", d.publicKey},
|
||||
{"removed", d.isRemoved},
|
||||
{"wallet", d.isWallet},
|
||||
void to_json(json& j, const ChatOrWalletAccount& d)
|
||||
{
|
||||
j = {
|
||||
{"address", d.address},
|
||||
{"chat", d.isChat},
|
||||
{"clock", d.clock},
|
||||
{"color", d.color},
|
||||
{"emoji", d.emoji},
|
||||
{"hidden", d.isHidden},
|
||||
{"mixedcase-address", d.mixedcaseAddress},
|
||||
{"name", d.name},
|
||||
{"path", d.path},
|
||||
{"public-key", d.publicKey},
|
||||
{"removed", d.isRemoved},
|
||||
{"wallet", d.isWallet},
|
||||
};
|
||||
|
||||
if(d.derivedFrom != std::nullopt)
|
||||
j["derived-from"] = d.derivedFrom.value();
|
||||
if(d.derivedFrom != std::nullopt) j["derived-from"] = d.derivedFrom.value();
|
||||
}
|
||||
|
||||
void from_json(const json& j, ChatOrWalletAccount& d) {
|
||||
void from_json(const json& j, ChatOrWalletAccount& d)
|
||||
{
|
||||
j.at("address").get_to(d.address);
|
||||
j.at("chat").get_to(d.isChat);
|
||||
j.at("clock").get_to(d.clock);
|
||||
|
@ -34,13 +37,11 @@ void from_json(const json& j, ChatOrWalletAccount& d) {
|
|||
j.at("wallet").get_to(d.isWallet);
|
||||
|
||||
constexpr auto pathKey = "path";
|
||||
if(j.contains(pathKey))
|
||||
j.at(pathKey).get_to(d.path);
|
||||
if(j.contains(pathKey)) j.at(pathKey).get_to(d.path);
|
||||
constexpr auto publicKeyKey = "public-key";
|
||||
if(j.contains(publicKeyKey))
|
||||
j.at(publicKeyKey).get_to(d.publicKey);
|
||||
if(j.contains(publicKeyKey)) j.at(publicKeyKey).get_to(d.publicKey);
|
||||
if(d.isWallet && !j.at("derived-from").get<std::string>().empty())
|
||||
d.derivedFrom = j.at("derived-from").get<std::optional<EOAddress>>();
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::StatusGo::Accounts
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace Status::StatusGo::Accounts {
|
||||
|
||||
namespace Status::StatusGo::Accounts
|
||||
{
|
||||
|
||||
/// \brief Unique wallet account entity
|
||||
/// \note equivalent of status-go's accounts.Account@multiaccounts/accounts/database.go
|
||||
|
@ -39,4 +39,4 @@ using ChatOrWalletAccounts = std::vector<ChatOrWalletAccount>;
|
|||
void to_json(json& j, const ChatOrWalletAccount& d);
|
||||
void from_json(const json& j, ChatOrWalletAccount& d);
|
||||
|
||||
}
|
||||
} // namespace Status::StatusGo::Accounts
|
||||
|
|
|
@ -7,10 +7,11 @@
|
|||
using json = nlohmann::json;
|
||||
|
||||
/// Defines phantom types for strong typing
|
||||
namespace Status::StatusGo::Accounts {
|
||||
namespace Status::StatusGo::Accounts
|
||||
{
|
||||
|
||||
/// The 20 byte address of an Ethereum account prefixed with 0x
|
||||
using EOAddress = Helpers::NamedType<QString, struct EOAddressTag>;
|
||||
using DerivationPath = Helpers::NamedType<QString, struct DerivationPathTag>;
|
||||
|
||||
}
|
||||
} // namespace Status::StatusGo::Accounts
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "ChatAPI.h"
|
||||
|
||||
#include "Utils.h"
|
||||
#include "Metadata/api_response.h"
|
||||
#include "Utils.h"
|
||||
|
||||
#include <libstatus.h>
|
||||
|
||||
|
@ -13,11 +13,7 @@ using namespace Status::StatusGo;
|
|||
|
||||
Chats::AllChannelGroupsDto Chats::getChats()
|
||||
{
|
||||
json inputJson = {
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "chat_getChats"},
|
||||
{"params", json::array()}
|
||||
};
|
||||
json inputJson = {{"jsonrpc", "2.0"}, {"method", "chat_getChats"}, {"params", json::array()}};
|
||||
|
||||
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
|
||||
const auto resultJson = json::parse(result);
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
|
||||
namespace Status::StatusGo::Chats
|
||||
{
|
||||
/// \brief Retrieve all available channel groups
|
||||
AllChannelGroupsDto getChats();
|
||||
}
|
||||
/// \brief Retrieve all available channel groups
|
||||
AllChannelGroupsDto getChats();
|
||||
} // namespace Status::StatusGo::Chats
|
||||
|
|
|
@ -1,105 +1,118 @@
|
|||
#include "ChatDto.h"
|
||||
|
||||
#include <Helpers/conversions.h>
|
||||
#include <Helpers/JsonMacros.h>
|
||||
#include <Helpers/conversions.h>
|
||||
|
||||
using namespace Status::StatusGo;
|
||||
|
||||
void Chats::to_json(json& j, const Category& d) {
|
||||
j = {{"id", d.id},
|
||||
{"name", d.name},
|
||||
{"position", d.position},
|
||||
};
|
||||
void Chats::to_json(json& j, const Category& d)
|
||||
{
|
||||
j = {
|
||||
{"id", d.id},
|
||||
{"name", d.name},
|
||||
{"position", d.position},
|
||||
};
|
||||
}
|
||||
|
||||
void Chats::from_json(const json& j, Category& d) {
|
||||
void Chats::from_json(const json& j, Category& d)
|
||||
{
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY(name)
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY(position)
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY(id, "category_id", false)
|
||||
if (!j.contains("category_id")){
|
||||
if(!j.contains("category_id"))
|
||||
{
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY(id, "id", false)
|
||||
}
|
||||
}
|
||||
|
||||
void Chats::to_json(json& j, const Permission& d) {
|
||||
j = {{"access", d.access},
|
||||
{"ens_only", d.ensOnly},
|
||||
};
|
||||
void Chats::to_json(json& j, const Permission& d)
|
||||
{
|
||||
j = {
|
||||
{"access", d.access},
|
||||
{"ens_only", d.ensOnly},
|
||||
};
|
||||
}
|
||||
|
||||
void Chats::from_json(const json& j, Permission& d) {
|
||||
void Chats::from_json(const json& j, Permission& d)
|
||||
{
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY(access, "access", false)
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY(ensOnly, "ens_only", false)
|
||||
}
|
||||
|
||||
void Chats::to_json(json& j, const Images& d) {
|
||||
j = {{"large", d.large},
|
||||
{"thumbnail", d.thumbnail},
|
||||
{"banner", d.banner},
|
||||
};
|
||||
void Chats::to_json(json& j, const Images& d)
|
||||
{
|
||||
j = {
|
||||
{"large", d.large},
|
||||
{"thumbnail", d.thumbnail},
|
||||
{"banner", d.banner},
|
||||
};
|
||||
}
|
||||
|
||||
void Chats::from_json(const json& j, Images& d) {
|
||||
void Chats::from_json(const json& j, Images& d)
|
||||
{
|
||||
constexpr auto large = "large";
|
||||
if(j.contains(large))
|
||||
j[large].at("uri").get_to(d.large);
|
||||
if(j.contains(large)) j[large].at("uri").get_to(d.large);
|
||||
|
||||
constexpr auto thumbnail = "thumbnail";
|
||||
if(j.contains(thumbnail))
|
||||
j[thumbnail].at("uri").get_to(d.thumbnail);
|
||||
if(j.contains(thumbnail)) j[thumbnail].at("uri").get_to(d.thumbnail);
|
||||
|
||||
constexpr auto banner = "banner";
|
||||
if(j.contains(banner))
|
||||
j[banner].at("uri").get_to(d.banner);
|
||||
if(j.contains(banner)) j[banner].at("uri").get_to(d.banner);
|
||||
}
|
||||
|
||||
void Chats::to_json(json& j, const ChatMember& d) {
|
||||
j = {{"id", d.id},
|
||||
{"admin", d.admin},
|
||||
{"joined", d.joined},
|
||||
{"roles", d.roles},
|
||||
};
|
||||
void Chats::to_json(json& j, const ChatMember& d)
|
||||
{
|
||||
j = {
|
||||
{"id", d.id},
|
||||
{"admin", d.admin},
|
||||
{"joined", d.joined},
|
||||
{"roles", d.roles},
|
||||
};
|
||||
}
|
||||
|
||||
void Chats::from_json(const json& j, ChatMember& d) {
|
||||
void Chats::from_json(const json& j, ChatMember& d)
|
||||
{
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY(id)
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY(joined)
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY(roles)
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY(admin, "admin", false)
|
||||
}
|
||||
|
||||
void Chats::to_json(json& j, const ChatDto& d) {
|
||||
j = {{"id", d.id},
|
||||
{"name", d.name},
|
||||
{"description", d.description},
|
||||
{"color", d.color},
|
||||
{"emoji", d.emoji},
|
||||
{"active", d.active},
|
||||
{"timestamp", d.timestamp},
|
||||
{"lastClockValue", d.lastClockValue},
|
||||
{"deletedAtClockValue", d.deletedAtClockValue},
|
||||
{"readMessagesAtClockValue", d.readMessagesAtClockValue},
|
||||
{"unviewedMessagesCount", d.unviewedMessagesCount},
|
||||
{"unviewedMentionsCount", d.unviewedMentionsCount},
|
||||
{"canPost", d.canPost},
|
||||
{"alias", d.alias},
|
||||
{"identicon", d.icon},
|
||||
{"muted", d.muted},
|
||||
{"position", d.position},
|
||||
{"communityId", d.communityId},
|
||||
{"profile", d.profile},
|
||||
{"joined", d.joined},
|
||||
{"syncedTo", d.syncedTo},
|
||||
{"syncedFrom", d.syncedFrom},
|
||||
{"highlight", d.highlight},
|
||||
{"categoryId", d.categoryId},
|
||||
{"permissions", d.permissions},
|
||||
{"chatType", d.chatType},
|
||||
{"members", d.members},
|
||||
};
|
||||
void Chats::to_json(json& j, const ChatDto& d)
|
||||
{
|
||||
j = {
|
||||
{"id", d.id},
|
||||
{"name", d.name},
|
||||
{"description", d.description},
|
||||
{"color", d.color},
|
||||
{"emoji", d.emoji},
|
||||
{"active", d.active},
|
||||
{"timestamp", d.timestamp},
|
||||
{"lastClockValue", d.lastClockValue},
|
||||
{"deletedAtClockValue", d.deletedAtClockValue},
|
||||
{"readMessagesAtClockValue", d.readMessagesAtClockValue},
|
||||
{"unviewedMessagesCount", d.unviewedMessagesCount},
|
||||
{"unviewedMentionsCount", d.unviewedMentionsCount},
|
||||
{"canPost", d.canPost},
|
||||
{"alias", d.alias},
|
||||
{"identicon", d.icon},
|
||||
{"muted", d.muted},
|
||||
{"position", d.position},
|
||||
{"communityId", d.communityId},
|
||||
{"profile", d.profile},
|
||||
{"joined", d.joined},
|
||||
{"syncedTo", d.syncedTo},
|
||||
{"syncedFrom", d.syncedFrom},
|
||||
{"highlight", d.highlight},
|
||||
{"categoryId", d.categoryId},
|
||||
{"permissions", d.permissions},
|
||||
{"chatType", d.chatType},
|
||||
{"members", d.members},
|
||||
};
|
||||
}
|
||||
|
||||
void Chats::from_json(const json& j, ChatDto& d) {
|
||||
void Chats::from_json(const json& j, ChatDto& d)
|
||||
{
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY(id)
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY(name)
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY(description)
|
||||
|
@ -127,25 +140,31 @@ void Chats::from_json(const json& j, ChatDto& d) {
|
|||
STATUS_READ_NLOHMAN_JSON_PROPERTY(chatType)
|
||||
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY(categoryId, "categoryId", false)
|
||||
if (!j.contains("categoryId")) {
|
||||
if(!j.contains("categoryId"))
|
||||
{
|
||||
// Communities have `categoryID` and chats have `categoryId`
|
||||
// This should be fixed in status-go, but would be a breaking change
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY(categoryId, "categoryID", false)
|
||||
}
|
||||
|
||||
// Add community ID if needed
|
||||
if (!d.communityId.isEmpty() && !d.id.contains(d.communityId)) {
|
||||
if(!d.communityId.isEmpty() && !d.id.contains(d.communityId))
|
||||
{
|
||||
d.id = d.communityId + d.id;
|
||||
}
|
||||
|
||||
constexpr auto membersKey = "members";
|
||||
if (j.contains(membersKey)) {
|
||||
if (j[membersKey].is_array()) {
|
||||
if(j.contains(membersKey))
|
||||
{
|
||||
if(j[membersKey].is_array())
|
||||
{
|
||||
j.at(membersKey).get_to(d.members);
|
||||
}
|
||||
else if (j[membersKey].is_object()) {
|
||||
else if(j[membersKey].is_object())
|
||||
{
|
||||
auto obj = j[membersKey];
|
||||
for (json::const_iterator it = obj.cbegin(); it != obj.cend(); ++it) {
|
||||
for(json::const_iterator it = obj.cbegin(); it != obj.cend(); ++it)
|
||||
{
|
||||
ChatMember chatMember;
|
||||
it.value().get_to(chatMember);
|
||||
chatMember.id = it.key().c_str();
|
||||
|
@ -155,27 +174,30 @@ void Chats::from_json(const json& j, ChatDto& d) {
|
|||
}
|
||||
}
|
||||
|
||||
void Chats::to_json(json& j, const ChannelGroupDto& d) {
|
||||
j = {{"id", d.id},
|
||||
{"admin", d.admin},
|
||||
{"verified", d.verified},
|
||||
{"name", d.name},
|
||||
{"description", d.description},
|
||||
{"introMessage", d.introMessage},
|
||||
{"outroMessage", d.outroMessage},
|
||||
{"canManageUsers", d.canManageUsers},
|
||||
{"color", d.color},
|
||||
{"muted", d.muted},
|
||||
{"images", d.images},
|
||||
{"permissions", d.permissions},
|
||||
{"channelGroupType", d.channelGroupType},
|
||||
{"chats", d.chats},
|
||||
{"categories", d.categories},
|
||||
{"members", d.members},
|
||||
};
|
||||
void Chats::to_json(json& j, const ChannelGroupDto& d)
|
||||
{
|
||||
j = {
|
||||
{"id", d.id},
|
||||
{"admin", d.admin},
|
||||
{"verified", d.verified},
|
||||
{"name", d.name},
|
||||
{"description", d.description},
|
||||
{"introMessage", d.introMessage},
|
||||
{"outroMessage", d.outroMessage},
|
||||
{"canManageUsers", d.canManageUsers},
|
||||
{"color", d.color},
|
||||
{"muted", d.muted},
|
||||
{"images", d.images},
|
||||
{"permissions", d.permissions},
|
||||
{"channelGroupType", d.channelGroupType},
|
||||
{"chats", d.chats},
|
||||
{"categories", d.categories},
|
||||
{"members", d.members},
|
||||
};
|
||||
}
|
||||
|
||||
void Chats::from_json(const json& j, ChannelGroupDto& d) {
|
||||
void Chats::from_json(const json& j, ChannelGroupDto& d)
|
||||
{
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY(admin)
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY(verified)
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY(name)
|
||||
|
@ -189,13 +211,14 @@ void Chats::from_json(const json& j, ChannelGroupDto& d) {
|
|||
STATUS_READ_NLOHMAN_JSON_PROPERTY(permissions, "permissions", false)
|
||||
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY(channelGroupType)
|
||||
if (d.channelGroupType.isEmpty())
|
||||
d.channelGroupType = ChannelGroupTypeUnknown;
|
||||
if(d.channelGroupType.isEmpty()) d.channelGroupType = ChannelGroupTypeUnknown;
|
||||
|
||||
constexpr auto chats = "chats";
|
||||
if (j.contains(chats)) {
|
||||
if(j.contains(chats))
|
||||
{
|
||||
auto obj = j[chats];
|
||||
for (json::const_iterator it = obj.cbegin(); it != obj.cend(); ++it) {
|
||||
for(json::const_iterator it = obj.cbegin(); it != obj.cend(); ++it)
|
||||
{
|
||||
ChatDto chatDto;
|
||||
it.value().get_to(chatDto);
|
||||
d.chats.emplace_back(std::move(chatDto));
|
||||
|
@ -203,9 +226,11 @@ void Chats::from_json(const json& j, ChannelGroupDto& d) {
|
|||
}
|
||||
|
||||
constexpr auto categories = "categories";
|
||||
if (j.contains(categories)) {
|
||||
if(j.contains(categories))
|
||||
{
|
||||
auto obj = j[categories];
|
||||
for (json::const_iterator it = obj.cbegin(); it != obj.cend(); ++it) {
|
||||
for(json::const_iterator it = obj.cbegin(); it != obj.cend(); ++it)
|
||||
{
|
||||
Category category;
|
||||
it.value().get_to(category);
|
||||
d.categories.emplace_back(std::move(category));
|
||||
|
@ -213,10 +238,13 @@ void Chats::from_json(const json& j, ChannelGroupDto& d) {
|
|||
}
|
||||
|
||||
constexpr auto membersKey = "members";
|
||||
if (j.contains(membersKey)) {
|
||||
if (j[membersKey].is_object()) {
|
||||
if(j.contains(membersKey))
|
||||
{
|
||||
if(j[membersKey].is_object())
|
||||
{
|
||||
auto obj = j[membersKey];
|
||||
for (json::const_iterator it = obj.cbegin(); it != obj.cend(); ++it) {
|
||||
for(json::const_iterator it = obj.cbegin(); it != obj.cend(); ++it)
|
||||
{
|
||||
ChatMember chatMember;
|
||||
it.value().get_to(chatMember);
|
||||
chatMember.id = it.key().c_str();
|
||||
|
@ -226,16 +254,18 @@ void Chats::from_json(const json& j, ChannelGroupDto& d) {
|
|||
}
|
||||
}
|
||||
|
||||
void Chats::to_json(json& j, const AllChannelGroupsDto& d) {
|
||||
void Chats::to_json(json& j, const AllChannelGroupsDto& d)
|
||||
{
|
||||
j = {{"id", d.allChannelGroups}};
|
||||
}
|
||||
|
||||
void Chats::from_json(const json& j, AllChannelGroupsDto& d) {
|
||||
for (json::const_iterator it = j.cbegin(); it != j.cend(); ++it) {
|
||||
void Chats::from_json(const json& j, AllChannelGroupsDto& d)
|
||||
{
|
||||
for(json::const_iterator it = j.cbegin(); it != j.cend(); ++it)
|
||||
{
|
||||
ChannelGroupDto channelGroupDto;
|
||||
it.value().get_to(channelGroupDto);
|
||||
channelGroupDto.id = it.key().c_str();
|
||||
d.allChannelGroups.emplace_back(std::move(channelGroupDto));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,125 +8,135 @@
|
|||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace Status::StatusGo::Chats {
|
||||
namespace Status::StatusGo::Chats
|
||||
{
|
||||
|
||||
constexpr auto ChannelGroupTypeUnknown = "unknown";
|
||||
constexpr auto ChannelGroupTypePersonal = "personal";
|
||||
constexpr auto ChannelGroupTypeCommunity = "community";
|
||||
constexpr auto ChannelGroupTypeUnknown = "unknown";
|
||||
constexpr auto ChannelGroupTypePersonal = "personal";
|
||||
constexpr auto ChannelGroupTypeCommunity = "community";
|
||||
|
||||
enum ChatType
|
||||
{
|
||||
Unknown = 0,
|
||||
OneToOne = 1,
|
||||
Public = 2,
|
||||
PrivateGroupChat = 3,
|
||||
Profile = 4,
|
||||
CommunityChat = 6
|
||||
};
|
||||
enum ChatType
|
||||
{
|
||||
Unknown = 0,
|
||||
OneToOne = 1,
|
||||
Public = 2,
|
||||
PrivateGroupChat = 3,
|
||||
Profile = 4,
|
||||
CommunityChat = 6
|
||||
};
|
||||
|
||||
struct Category {
|
||||
QString id;
|
||||
QString name;
|
||||
int position;
|
||||
};
|
||||
struct Category
|
||||
{
|
||||
QString id;
|
||||
QString name;
|
||||
int position;
|
||||
};
|
||||
|
||||
struct Permission {
|
||||
int access;
|
||||
bool ensOnly;
|
||||
};
|
||||
struct Permission
|
||||
{
|
||||
int access;
|
||||
bool ensOnly;
|
||||
};
|
||||
|
||||
struct Images {
|
||||
QString thumbnail;
|
||||
QString large;
|
||||
QString banner;
|
||||
};
|
||||
struct Images
|
||||
{
|
||||
QString thumbnail;
|
||||
QString large;
|
||||
QString banner;
|
||||
};
|
||||
|
||||
struct ChatMember {
|
||||
QString id;
|
||||
bool admin;
|
||||
bool joined;
|
||||
std::vector<int> roles;
|
||||
};
|
||||
struct ChatMember
|
||||
{
|
||||
QString id;
|
||||
bool admin;
|
||||
bool joined;
|
||||
std::vector<int> roles;
|
||||
};
|
||||
|
||||
struct ChatDto {
|
||||
QString id; // ID is the id of the chat, for public chats it is the name e.g. status,
|
||||
// for one-to-one is the hex encoded public key and for group chats is a random
|
||||
// uuid appended with the hex encoded pk of the creator of the chat
|
||||
QString name;
|
||||
QString description;
|
||||
QColor color;
|
||||
QString emoji;
|
||||
bool active; // indicates whether the chat has been soft deleted
|
||||
ChatType chatType;
|
||||
quint64 timestamp; // indicates the last time this chat has received/sent a message
|
||||
quint64 lastClockValue; // indicates the last clock value to be used when sending messages
|
||||
quint64 deletedAtClockValue; // indicates the clock value at time of deletion, messages with lower clock value of this should be discarded
|
||||
quint64 readMessagesAtClockValue;
|
||||
int unviewedMessagesCount;
|
||||
int unviewedMentionsCount;
|
||||
std::vector<ChatMember> members;
|
||||
QString alias;
|
||||
QString icon;
|
||||
bool muted;
|
||||
QString communityId; // set if chat belongs to a community
|
||||
QString profile;
|
||||
quint64 joined; // indicates when the user joined the chat last time
|
||||
quint64 syncedTo;
|
||||
quint64 syncedFrom;
|
||||
bool canPost;
|
||||
int position;
|
||||
QString categoryId;
|
||||
bool highlight;
|
||||
Permission permissions;
|
||||
};
|
||||
struct ChatDto
|
||||
{
|
||||
QString id; // ID is the id of the chat, for public chats it is the name e.g. status,
|
||||
// for one-to-one is the hex encoded public key and for group chats is a random
|
||||
// uuid appended with the hex encoded pk of the creator of the chat
|
||||
QString name;
|
||||
QString description;
|
||||
QColor color;
|
||||
QString emoji;
|
||||
bool active; // indicates whether the chat has been soft deleted
|
||||
ChatType chatType;
|
||||
quint64 timestamp; // indicates the last time this chat has received/sent a message
|
||||
quint64 lastClockValue; // indicates the last clock value to be used when sending messages
|
||||
quint64
|
||||
deletedAtClockValue; // indicates the clock value at time of deletion, messages with lower clock value of this should be discarded
|
||||
quint64 readMessagesAtClockValue;
|
||||
int unviewedMessagesCount;
|
||||
int unviewedMentionsCount;
|
||||
std::vector<ChatMember> members;
|
||||
QString alias;
|
||||
QString icon;
|
||||
bool muted;
|
||||
QString communityId; // set if chat belongs to a community
|
||||
QString profile;
|
||||
quint64 joined; // indicates when the user joined the chat last time
|
||||
quint64 syncedTo;
|
||||
quint64 syncedFrom;
|
||||
bool canPost;
|
||||
int position;
|
||||
QString categoryId;
|
||||
bool highlight;
|
||||
Permission permissions;
|
||||
};
|
||||
|
||||
struct ChannelGroupDto {
|
||||
QString id;
|
||||
QString channelGroupType;
|
||||
bool admin;
|
||||
bool verified;
|
||||
QString name;
|
||||
QString ensName;
|
||||
QString description;
|
||||
QString introMessage;
|
||||
QString outroMessage;
|
||||
std::vector<ChatDto> chats;
|
||||
std::vector<Category> categories;
|
||||
Images images;
|
||||
Permission permissions;
|
||||
std::vector<ChatMember> members;
|
||||
bool canManageUsers;
|
||||
QColor color;
|
||||
bool muted;
|
||||
bool historyArchiveSupportEnabled;
|
||||
bool pinMessageAllMembersEnabled;
|
||||
};
|
||||
struct ChannelGroupDto
|
||||
{
|
||||
QString id;
|
||||
QString channelGroupType;
|
||||
bool admin;
|
||||
bool verified;
|
||||
QString name;
|
||||
QString ensName;
|
||||
QString description;
|
||||
QString introMessage;
|
||||
QString outroMessage;
|
||||
std::vector<ChatDto> chats;
|
||||
std::vector<Category> categories;
|
||||
Images images;
|
||||
Permission permissions;
|
||||
std::vector<ChatMember> members;
|
||||
bool canManageUsers;
|
||||
QColor color;
|
||||
bool muted;
|
||||
bool historyArchiveSupportEnabled;
|
||||
bool pinMessageAllMembersEnabled;
|
||||
};
|
||||
|
||||
struct AllChannelGroupsDto {
|
||||
std::vector<ChannelGroupDto> allChannelGroups;
|
||||
};
|
||||
struct AllChannelGroupsDto
|
||||
{
|
||||
std::vector<ChannelGroupDto> allChannelGroups;
|
||||
};
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(ChatType, {
|
||||
{Unknown, "Unknown"},
|
||||
{OneToOne, "OneToOne"},
|
||||
{Public, "Public"},
|
||||
{PrivateGroupChat, "PrivateGroupChat"},
|
||||
{Profile, "Profile"},
|
||||
{CommunityChat, "CommunityChat"},
|
||||
})
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(ChatType,
|
||||
{
|
||||
{Unknown, "Unknown"},
|
||||
{OneToOne, "OneToOne"},
|
||||
{Public, "Public"},
|
||||
{PrivateGroupChat, "PrivateGroupChat"},
|
||||
{Profile, "Profile"},
|
||||
{CommunityChat, "CommunityChat"},
|
||||
})
|
||||
|
||||
void to_json(json& j, const Category& d);
|
||||
void from_json(const json& j, Category& d);
|
||||
void to_json(json& j, const Permission& d);
|
||||
void from_json(const json& j, Permission& d);
|
||||
void to_json(json& j, const Images& d);
|
||||
void from_json(const json& j, Images& d);
|
||||
void to_json(json& j, const ChatMember& d);
|
||||
void from_json(const json& j, ChatMember& d);
|
||||
void to_json(json& j, const ChatDto& d);
|
||||
void from_json(const json& j, ChatDto& d);
|
||||
void to_json(json& j, const ChannelGroupDto& d);
|
||||
void from_json(const json& j, ChannelGroupDto& d);
|
||||
void to_json(json& j, const AllChannelGroupsDto& d);
|
||||
void from_json(const json& j, AllChannelGroupsDto& d);
|
||||
}
|
||||
void to_json(json& j, const Category& d);
|
||||
void from_json(const json& j, Category& d);
|
||||
void to_json(json& j, const Permission& d);
|
||||
void from_json(const json& j, Permission& d);
|
||||
void to_json(json& j, const Images& d);
|
||||
void from_json(const json& j, Images& d);
|
||||
void to_json(json& j, const ChatMember& d);
|
||||
void from_json(const json& j, ChatMember& d);
|
||||
void to_json(json& j, const ChatDto& d);
|
||||
void from_json(const json& j, ChatDto& d);
|
||||
void to_json(json& j, const ChannelGroupDto& d);
|
||||
void from_json(const json& j, ChannelGroupDto& d);
|
||||
void to_json(json& j, const AllChannelGroupsDto& d);
|
||||
void from_json(const json& j, AllChannelGroupsDto& d);
|
||||
} // namespace Status::StatusGo::Chats
|
||||
|
|
|
@ -13,13 +13,14 @@ RpcResponse<QJsonObject> initKeystore(const char* keystoreDir)
|
|||
{
|
||||
auto result = InitKeystore(const_cast<char*>(keystoreDir));
|
||||
QJsonObject jsonResult;
|
||||
if(!Utils::checkReceivedResponse(result, jsonResult)) {
|
||||
if(!Utils::checkReceivedResponse(result, jsonResult))
|
||||
{
|
||||
throw std::domain_error("parsing response failed");
|
||||
}
|
||||
|
||||
return Utils::buildPrivateRPCResponse(jsonResult);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
catch(std::exception& e)
|
||||
{
|
||||
// TODO: either use optional/smartpointers or exceptions instead of plain objects
|
||||
auto response = RpcResponse<QJsonObject>(QJsonObject());
|
||||
|
@ -27,7 +28,7 @@ RpcResponse<QJsonObject> initKeystore(const char* keystoreDir)
|
|||
response.error.message = QObject::tr("an error opening accounts occurred, msg: %1").arg(e.what());
|
||||
return response;
|
||||
}
|
||||
catch (...)
|
||||
catch(...)
|
||||
{
|
||||
auto response = RpcResponse<QJsonObject>(QJsonObject());
|
||||
response.error.message = QObject::tr("an error opening accounts occurred");
|
||||
|
@ -35,4 +36,4 @@ RpcResponse<QJsonObject> initKeystore(const char* keystoreDir)
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::StatusGo::General
|
||||
|
|
|
@ -7,11 +7,7 @@ namespace Status::StatusGo::Messenger
|
|||
|
||||
bool startMessenger()
|
||||
{
|
||||
QJsonObject payload{
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "wakuext_startMessenger"},
|
||||
{"params", QJsonArray()}
|
||||
};
|
||||
QJsonObject payload{{"jsonrpc", "2.0"}, {"method", "wakuext_startMessenger"}, {"params", QJsonArray()}};
|
||||
|
||||
auto callResult = Utils::callPrivateRpc<QJsonObject>(Utils::jsonToByteArray(payload));
|
||||
if(callResult.containsError())
|
||||
|
@ -19,4 +15,4 @@ bool startMessenger()
|
|||
return !callResult.containsError();
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::StatusGo::Messenger
|
||||
|
|
|
@ -1,25 +1,28 @@
|
|||
#include "api_response.h"
|
||||
|
||||
namespace Status::StatusGo {
|
||||
namespace Status::StatusGo
|
||||
{
|
||||
|
||||
void checkApiError(const json &response) {
|
||||
if(response.contains("error")) {
|
||||
const auto &error = response["error"];
|
||||
if(error.is_object()) {
|
||||
void checkApiError(const json& response)
|
||||
{
|
||||
if(response.contains("error"))
|
||||
{
|
||||
const auto& error = response["error"];
|
||||
if(error.is_object())
|
||||
{
|
||||
const auto apiErr = response["error"].get<ApiErrorResponseWithCode>();
|
||||
throw CallGenericPrepareJsonError(apiErr);
|
||||
}
|
||||
assert(error.is_string());
|
||||
const auto apiError = response.get<ApiErrorResponse>();
|
||||
if(!apiError.error.empty())
|
||||
throw CallGenericMakeJsonError(response.get<ApiErrorResponse>());
|
||||
if(!apiError.error.empty()) throw CallGenericMakeJsonError(response.get<ApiErrorResponse>());
|
||||
}
|
||||
}
|
||||
|
||||
/// \throws \c CallPrivateRpcError, \c nlohmann::exception
|
||||
void checkPrivateRpcCallResultAndReportError(const json &response) {
|
||||
if(response.contains("error"))
|
||||
throw CallPrivateRpcError(response.get<CallPrivateRpcErrorResponse>());
|
||||
void checkPrivateRpcCallResultAndReportError(const json& response)
|
||||
{
|
||||
if(response.contains("error")) throw CallPrivateRpcError(response.get<CallPrivateRpcErrorResponse>());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace Status::StatusGo
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace Status::StatusGo {
|
||||
namespace Status::StatusGo
|
||||
{
|
||||
|
||||
/*!
|
||||
* \brief General API response if an internal status-go error occured
|
||||
|
@ -18,7 +19,8 @@ namespace Status::StatusGo {
|
|||
*
|
||||
* \note update NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE when changing structure's content
|
||||
*/
|
||||
struct ApiErrorResponse {
|
||||
struct ApiErrorResponse
|
||||
{
|
||||
std::string error;
|
||||
};
|
||||
|
||||
|
@ -31,7 +33,8 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ApiErrorResponse, error)
|
|||
*
|
||||
* \note update NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE when changing structure's content
|
||||
*/
|
||||
struct JsonError {
|
||||
struct JsonError
|
||||
{
|
||||
int code{0};
|
||||
std::string message;
|
||||
};
|
||||
|
@ -45,7 +48,8 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(JsonError, code, message)
|
|||
* \see jsonrpcSuccessfulResponse@response.go
|
||||
* \note update NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE when changing structure's content
|
||||
*/
|
||||
struct ApiErrorResponseWithCode {
|
||||
struct ApiErrorResponseWithCode
|
||||
{
|
||||
JsonError error;
|
||||
};
|
||||
|
||||
|
@ -60,7 +64,8 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ApiErrorResponseWithCode, error)
|
|||
*
|
||||
* \note update NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE when changing structure's content
|
||||
*/
|
||||
struct ApiResponse {
|
||||
struct ApiResponse
|
||||
{
|
||||
json result;
|
||||
};
|
||||
|
||||
|
@ -116,38 +121,53 @@ void checkApiError(const json& response);
|
|||
|
||||
constexpr int defaultErrorCode = -32000;
|
||||
|
||||
class CallGenericMakeJsonError: public std::runtime_error {
|
||||
class CallGenericMakeJsonError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
CallGenericMakeJsonError(const ApiErrorResponse error)
|
||||
: std::runtime_error("CallGenericMakeJsonError@status-go failed")
|
||||
, m_error(std::move(error))
|
||||
{}
|
||||
{ }
|
||||
|
||||
const ApiErrorResponse& errorResponse() const
|
||||
{
|
||||
return m_error;
|
||||
};
|
||||
|
||||
const ApiErrorResponse &errorResponse() const { return m_error; };
|
||||
private:
|
||||
const ApiErrorResponse m_error;
|
||||
};
|
||||
|
||||
class CallGenericPrepareJsonError: public std::runtime_error {
|
||||
class CallGenericPrepareJsonError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
CallGenericPrepareJsonError(const ApiErrorResponseWithCode error)
|
||||
: std::runtime_error("CallGenericPrepareJsonError@status-go failed")
|
||||
, m_error(std::move(error))
|
||||
{}
|
||||
{ }
|
||||
|
||||
const ApiErrorResponseWithCode& errorResponse() const
|
||||
{
|
||||
return m_error;
|
||||
};
|
||||
|
||||
const ApiErrorResponseWithCode &errorResponse() const { return m_error; };
|
||||
private:
|
||||
const ApiErrorResponseWithCode m_error;
|
||||
};
|
||||
|
||||
class CallPrivateRpcError: public std::runtime_error {
|
||||
class CallPrivateRpcError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
CallPrivateRpcError(const CallPrivateRpcErrorResponse error)
|
||||
: std::runtime_error("CallPrivateRPC@status-go failed")
|
||||
, m_error(std::move(error))
|
||||
{}
|
||||
{ }
|
||||
|
||||
const CallPrivateRpcErrorResponse& errorResponse() const
|
||||
{
|
||||
return m_error;
|
||||
};
|
||||
|
||||
const CallPrivateRpcErrorResponse &errorResponse() const { return m_error; };
|
||||
private:
|
||||
const CallPrivateRpcErrorResponse m_error;
|
||||
};
|
||||
|
@ -160,4 +180,4 @@ private:
|
|||
*/
|
||||
void checkPrivateRpcCallResultAndReportError(const json& response);
|
||||
|
||||
}
|
||||
} // namespace Status::StatusGo
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "SettingsAPI.h"
|
||||
|
||||
#include "Utils.h"
|
||||
#include "Metadata/api_response.h"
|
||||
#include "Utils.h"
|
||||
|
||||
#include <libstatus.h>
|
||||
|
||||
|
@ -13,11 +13,7 @@ using namespace Status::StatusGo;
|
|||
|
||||
Settings::SettingsDto Settings::getSettings()
|
||||
{
|
||||
json inputJson = {
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "settings_getSettings"},
|
||||
{"params", json::array()}
|
||||
};
|
||||
json inputJson = {{"jsonrpc", "2.0"}, {"method", "settings_getSettings"}, {"params", json::array()}};
|
||||
|
||||
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
|
||||
const auto resultJson = json::parse(result);
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
|
||||
namespace Status::StatusGo::Settings
|
||||
{
|
||||
/// \brief Retrieve settings
|
||||
SettingsDto getSettings();
|
||||
}
|
||||
/// \brief Retrieve settings
|
||||
SettingsDto getSettings();
|
||||
} // namespace Status::StatusGo::Settings
|
||||
|
|
|
@ -1,20 +1,23 @@
|
|||
#include "SettingsDto.h"
|
||||
|
||||
#include <Helpers/conversions.h>
|
||||
#include <Helpers/JsonMacros.h>
|
||||
#include <Helpers/conversions.h>
|
||||
|
||||
using namespace Status::StatusGo;
|
||||
|
||||
void Settings::to_json(json& j, const SettingsDto& d) {
|
||||
j = {{"address", d.address},
|
||||
{"display-name", d.displayName},
|
||||
{"preferred-name", d.preferredName},
|
||||
{"key-uid", d.keyUid},
|
||||
{"public-key", d.publicKey},
|
||||
};
|
||||
void Settings::to_json(json& j, const SettingsDto& d)
|
||||
{
|
||||
j = {
|
||||
{"address", d.address},
|
||||
{"display-name", d.displayName},
|
||||
{"preferred-name", d.preferredName},
|
||||
{"key-uid", d.keyUid},
|
||||
{"public-key", d.publicKey},
|
||||
};
|
||||
}
|
||||
|
||||
void Settings::from_json(const json& j, SettingsDto& d) {
|
||||
void Settings::from_json(const json& j, SettingsDto& d)
|
||||
{
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY(address)
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY(displayName, "display-name")
|
||||
STATUS_READ_NLOHMAN_JSON_PROPERTY(preferredName, "preferred-name", false)
|
||||
|
|
|
@ -8,16 +8,18 @@
|
|||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace Status::StatusGo::Settings {
|
||||
namespace Status::StatusGo::Settings
|
||||
{
|
||||
|
||||
struct SettingsDto {
|
||||
QString address;
|
||||
QString displayName;
|
||||
QString preferredName;
|
||||
QString keyUid;
|
||||
QString publicKey;
|
||||
};
|
||||
struct SettingsDto
|
||||
{
|
||||
QString address;
|
||||
QString displayName;
|
||||
QString preferredName;
|
||||
QString keyUid;
|
||||
QString publicKey;
|
||||
};
|
||||
|
||||
void to_json(json& j, const SettingsDto& d);
|
||||
void from_json(const json& j, SettingsDto& d);
|
||||
}
|
||||
void to_json(json& j, const SettingsDto& d);
|
||||
void from_json(const json& j, SettingsDto& d);
|
||||
} // namespace Status::StatusGo::Settings
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
|
||||
using namespace std::string_literals;
|
||||
|
||||
namespace Status::StatusGo {
|
||||
namespace Status::StatusGo
|
||||
{
|
||||
|
||||
std::map<std::string, SignalType> SignalsManager::signalMap;
|
||||
|
||||
|
@ -22,29 +23,25 @@ SignalsManager::SignalsManager()
|
|||
{
|
||||
SetSignalEventCallback((void*)&SignalsManager::signalCallback);
|
||||
|
||||
signalMap = {
|
||||
{"node.ready"s, SignalType::NodeReady},
|
||||
{"node.started"s, SignalType::NodeStarted},
|
||||
{"node.stopped"s, SignalType::NodeStopped},
|
||||
{"node.login"s, SignalType::NodeLogin},
|
||||
{"node.crashed"s, SignalType::NodeCrashed},
|
||||
signalMap = {{"node.ready"s, SignalType::NodeReady},
|
||||
{"node.started"s, SignalType::NodeStarted},
|
||||
{"node.stopped"s, SignalType::NodeStopped},
|
||||
{"node.login"s, SignalType::NodeLogin},
|
||||
{"node.crashed"s, SignalType::NodeCrashed},
|
||||
|
||||
{"discovery.started"s, SignalType::DiscoveryStarted},
|
||||
{"discovery.stopped"s, SignalType::DiscoveryStopped},
|
||||
{"discovery.summary"s, SignalType::DiscoverySummary},
|
||||
{"discovery.started"s, SignalType::DiscoveryStarted},
|
||||
{"discovery.stopped"s, SignalType::DiscoveryStopped},
|
||||
{"discovery.summary"s, SignalType::DiscoverySummary},
|
||||
|
||||
{"mailserver.changed"s, SignalType::MailserverChanged},
|
||||
{"mailserver.available"s, SignalType::MailserverAvailable},
|
||||
{"mailserver.changed"s, SignalType::MailserverChanged},
|
||||
{"mailserver.available"s, SignalType::MailserverAvailable},
|
||||
|
||||
{"history.request.started"s, SignalType::HistoryRequestStarted},
|
||||
{"history.request.batch.processed"s, SignalType::HistoryRequestBatchProcessed},
|
||||
{"history.request.completed"s, SignalType::HistoryRequestCompleted}
|
||||
};
|
||||
{"history.request.started"s, SignalType::HistoryRequestStarted},
|
||||
{"history.request.batch.processed"s, SignalType::HistoryRequestBatchProcessed},
|
||||
{"history.request.completed"s, SignalType::HistoryRequestCompleted}};
|
||||
}
|
||||
|
||||
SignalsManager::~SignalsManager()
|
||||
{
|
||||
}
|
||||
SignalsManager::~SignalsManager() { }
|
||||
|
||||
void SignalsManager::processSignal(const QString& statusSignal)
|
||||
{
|
||||
|
@ -82,46 +79,22 @@ void SignalsManager::decode(const QJsonObject& signalEvent)
|
|||
switch(signalType)
|
||||
{
|
||||
// TODO: create extractor functions like in nim
|
||||
case NodeLogin:
|
||||
emit nodeLogin(signalError);
|
||||
break;
|
||||
case NodeReady:
|
||||
emit nodeReady(signalError);
|
||||
break;
|
||||
case NodeStarted:
|
||||
emit nodeStarted(signalError);
|
||||
break;
|
||||
case NodeStopped:
|
||||
emit nodeStopped(signalError);
|
||||
break;
|
||||
case NodeLogin: emit nodeLogin(signalError); break;
|
||||
case NodeReady: emit nodeReady(signalError); break;
|
||||
case NodeStarted: emit nodeStarted(signalError); break;
|
||||
case NodeStopped: emit nodeStopped(signalError); break;
|
||||
case NodeCrashed:
|
||||
qWarning() << "node.crashed, error: " << signalError;
|
||||
emit nodeCrashed(signalError);
|
||||
break;
|
||||
case DiscoveryStarted:
|
||||
emit discoveryStarted(signalError);
|
||||
break;
|
||||
case DiscoveryStopped:
|
||||
emit discoveryStopped(signalError);
|
||||
break;
|
||||
case DiscoverySummary:
|
||||
emit discoverySummary(signalEvent["event"].toArray().count(), signalError);
|
||||
break;
|
||||
case MailserverChanged:
|
||||
emit mailserverChanged(signalError);
|
||||
break;
|
||||
case MailserverAvailable:
|
||||
emit mailserverAvailable(signalError);
|
||||
break;
|
||||
case HistoryRequestStarted:
|
||||
emit historyRequestStarted(signalError);
|
||||
break;
|
||||
case HistoryRequestBatchProcessed:
|
||||
emit historyRequestBatchProcessed(signalError);
|
||||
break;
|
||||
case HistoryRequestCompleted:
|
||||
emit historyRequestCompleted(signalError);
|
||||
break;
|
||||
case DiscoveryStarted: emit discoveryStarted(signalError); break;
|
||||
case DiscoveryStopped: emit discoveryStopped(signalError); break;
|
||||
case DiscoverySummary: emit discoverySummary(signalEvent["event"].toArray().count(), signalError); break;
|
||||
case MailserverChanged: emit mailserverChanged(signalError); break;
|
||||
case MailserverAvailable: emit mailserverAvailable(signalError); break;
|
||||
case HistoryRequestStarted: emit historyRequestStarted(signalError); break;
|
||||
case HistoryRequestBatchProcessed: emit historyRequestBatchProcessed(signalError); break;
|
||||
case HistoryRequestCompleted: emit historyRequestCompleted(signalError); break;
|
||||
case Unknown: assert(false); break;
|
||||
}
|
||||
}
|
||||
|
@ -130,9 +103,8 @@ void SignalsManager::signalCallback(const char* data)
|
|||
{
|
||||
// TODO: overkill, use some kind of message broker
|
||||
auto dataStrPtr = std::make_shared<QString>(data);
|
||||
QFuture<void> future = QtConcurrent::run([dataStrPtr](){
|
||||
SignalsManager::instance()->processSignal(*dataStrPtr);
|
||||
});
|
||||
QFuture<void> future =
|
||||
QtConcurrent::run([dataStrPtr]() { SignalsManager::instance()->processSignal(*dataStrPtr); });
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::StatusGo
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
#include <QObject>
|
||||
|
||||
namespace Status::StatusGo {
|
||||
namespace Status::StatusGo
|
||||
{
|
||||
|
||||
enum SignalType
|
||||
{
|
||||
|
@ -35,7 +36,6 @@ class SignalsManager final : public QObject
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
static SignalsManager* instance();
|
||||
|
||||
void processSignal(const QString& ev);
|
||||
|
@ -57,6 +57,7 @@ signals:
|
|||
void historyRequestStarted(const QString& error);
|
||||
void historyRequestBatchProcessed(const QString& error);
|
||||
void historyRequestCompleted(const QString& error);
|
||||
|
||||
private:
|
||||
explicit SignalsManager();
|
||||
~SignalsManager();
|
||||
|
@ -67,4 +68,4 @@ private:
|
|||
void decode(const QJsonObject& signalEvent);
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Status::StatusGo
|
||||
|
|
|
@ -30,18 +30,20 @@ struct RpcResponse
|
|||
int id;
|
||||
RpcError error;
|
||||
|
||||
explicit
|
||||
RpcResponse(T result, QString version = RpcError::UnknownVersion, int id = RpcError::UnknownId,
|
||||
RpcError error = RpcError())
|
||||
explicit RpcResponse(T result,
|
||||
QString version = RpcError::UnknownVersion,
|
||||
int id = RpcError::UnknownId,
|
||||
RpcError error = RpcError())
|
||||
: result(std::move(result))
|
||||
, jsonRpcVersion(std::move(version))
|
||||
, id(id)
|
||||
, error(std::move(error))
|
||||
{ }
|
||||
|
||||
bool containsError() const {
|
||||
bool containsError() const
|
||||
{
|
||||
return !error.message.isEmpty() || error.code != RpcError::NoError;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Status::StatusGo
|
||||
|
|
|
@ -15,35 +15,35 @@ QJsonArray toJsonArray(const std::vector<Accounts::DerivationPath>& value)
|
|||
return array;
|
||||
}
|
||||
|
||||
const char* statusGoCallPrivateRPC(const char* inputJSON) {
|
||||
const char* statusGoCallPrivateRPC(const char* inputJSON)
|
||||
{
|
||||
// Evil done here! status-go API doesn't follow the proper const conventions
|
||||
return CallPrivateRPC(const_cast<char*>(inputJSON));
|
||||
}
|
||||
|
||||
HashedPassword hashPassword(const QString &str)
|
||||
HashedPassword hashPassword(const QString& str)
|
||||
{
|
||||
// TODO: is utf8 the standard used by NIM also? Will it unlock DBs encrypted with NIM password hashing?
|
||||
return HashedPassword("0x" + QString::fromUtf8(QCryptographicHash::hash(str.toUtf8(),
|
||||
QCryptographicHash::Keccak_256).toHex().toUpper()));
|
||||
return HashedPassword(
|
||||
"0x" +
|
||||
QString::fromUtf8(QCryptographicHash::hash(str.toUtf8(), QCryptographicHash::Keccak_256).toHex().toUpper()));
|
||||
}
|
||||
|
||||
std::optional<RpcError> getRPCErrorInJson(const QJsonObject& json)
|
||||
{
|
||||
auto errVal = json[Param::Error];
|
||||
if (errVal.isNull() || errVal.isUndefined())
|
||||
return std::nullopt;
|
||||
if(errVal.isString() && errVal.toString().length() == 0)
|
||||
return std::nullopt;
|
||||
if(errVal.isNull() || errVal.isUndefined()) return std::nullopt;
|
||||
if(errVal.isString() && errVal.toString().length() == 0) return std::nullopt;
|
||||
|
||||
RpcError response;
|
||||
auto errObj = json[Param::Id].toObject();
|
||||
if (!errObj[Param::ErrorCode].isNull() && !errObj[Param::ErrorCode].isUndefined())
|
||||
if(!errObj[Param::ErrorCode].isNull() && !errObj[Param::ErrorCode].isUndefined())
|
||||
response.code = errObj[Param::ErrorCode].toInt();
|
||||
if (!errObj[Param::ErrorMessage].isNull() && !errObj[Param::ErrorMessage].isUndefined())
|
||||
if(!errObj[Param::ErrorMessage].isNull() && !errObj[Param::ErrorMessage].isUndefined())
|
||||
response.message = errObj[Param::ErrorMessage].toString();
|
||||
else
|
||||
response.message = errVal.toString();
|
||||
return response;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::StatusGo::Utils
|
||||
|
|
|
@ -1,29 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include "Types.h"
|
||||
#include "Accounts/accounts_types.h"
|
||||
#include "Types.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
|
||||
namespace Status::StatusGo::Utils
|
||||
{
|
||||
|
||||
namespace Param {
|
||||
static constexpr auto Id{"id"};
|
||||
static constexpr auto JsonRpc{"jsonrpc"};
|
||||
static constexpr auto Result{"result"};
|
||||
static constexpr auto Error{"error"};
|
||||
static constexpr auto ErrorMessage{"message"};
|
||||
static constexpr auto ErrorCode{"code"};
|
||||
}
|
||||
namespace Param
|
||||
{
|
||||
static constexpr auto Id{"id"};
|
||||
static constexpr auto JsonRpc{"jsonrpc"};
|
||||
static constexpr auto Result{"result"};
|
||||
static constexpr auto Error{"error"};
|
||||
static constexpr auto ErrorMessage{"message"};
|
||||
static constexpr auto ErrorCode{"code"};
|
||||
} // namespace Param
|
||||
|
||||
template<class T>
|
||||
template <class T>
|
||||
QByteArray jsonToByteArray(const T& json)
|
||||
{
|
||||
static_assert(std::is_same_v<T, QJsonObject> ||
|
||||
std::is_same_v<T, QJsonArray>, "Wrong Json type. Supported: Object, Array");
|
||||
static_assert(std::is_same_v<T, QJsonObject> || std::is_same_v<T, QJsonArray>,
|
||||
"Wrong Json type. Supported: Object, Array");
|
||||
return QJsonDocument(json).toJson(QJsonDocument::Compact);
|
||||
}
|
||||
|
||||
|
@ -32,20 +33,19 @@ QJsonArray toJsonArray(const std::vector<Accounts::DerivationPath>& value);
|
|||
/// Check if json contains a standard status-go error and
|
||||
std::optional<RpcError> getRPCErrorInJson(const QJsonObject& json);
|
||||
|
||||
template<class T>
|
||||
template <class T>
|
||||
bool checkReceivedResponse(const QString& response, T& json)
|
||||
{
|
||||
QJsonParseError error;
|
||||
auto jsonDocument = QJsonDocument::fromJson(response.toUtf8(), &error);
|
||||
if (error.error != QJsonParseError::NoError)
|
||||
return false;
|
||||
if(error.error != QJsonParseError::NoError) return false;
|
||||
|
||||
if constexpr (std::is_same_v<T, QJsonObject>)
|
||||
if constexpr(std::is_same_v<T, QJsonObject>)
|
||||
{
|
||||
json = jsonDocument.object();
|
||||
return true;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, QJsonArray>)
|
||||
else if constexpr(std::is_same_v<T, QJsonArray>)
|
||||
{
|
||||
json = jsonDocument.array();
|
||||
return true;
|
||||
|
@ -55,25 +55,24 @@ bool checkReceivedResponse(const QString& response, T& json)
|
|||
}
|
||||
|
||||
// TODO: Clarify scope. The assumption done here are valid only for status-go::CallPrivateRPC API.
|
||||
template<class T>
|
||||
template <class T>
|
||||
RpcResponse<T> buildPrivateRPCResponse(const T& json)
|
||||
{
|
||||
auto response = RpcResponse<T>(T());
|
||||
|
||||
if constexpr (std::is_same_v<T, QJsonObject>)
|
||||
if constexpr(std::is_same_v<T, QJsonObject>)
|
||||
{
|
||||
if (!json[Param::Id].isNull() && !json[Param::Id].isUndefined())
|
||||
response.id = json[Param::Id].toInt();
|
||||
if(!json[Param::Id].isNull() && !json[Param::Id].isUndefined()) response.id = json[Param::Id].toInt();
|
||||
|
||||
if (!json[Param::JsonRpc].isNull() && !json[Param::JsonRpc].isUndefined())
|
||||
response.jsonRpcVersion = json[Param::JsonRpc].toString();
|
||||
if(!json[Param::JsonRpc].isNull() && !json[Param::JsonRpc].isUndefined())
|
||||
response.jsonRpcVersion = json[Param::JsonRpc].toString();
|
||||
|
||||
response.error = getRPCErrorInJson(json).value_or(RpcError());
|
||||
response.error = getRPCErrorInJson(json).value_or(RpcError());
|
||||
|
||||
if (!json[Param::Result].isNull() && !json[Param::Result].isUndefined())
|
||||
response.result = json[Param::Result].toObject();
|
||||
if(!json[Param::Result].isNull() && !json[Param::Result].isUndefined())
|
||||
response.result = json[Param::Result].toObject();
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, QJsonArray>)
|
||||
else if constexpr(std::is_same_v<T, QJsonArray>)
|
||||
{
|
||||
response.result = json;
|
||||
}
|
||||
|
@ -83,7 +82,7 @@ RpcResponse<T> buildPrivateRPCResponse(const T& json)
|
|||
|
||||
const char* statusGoCallPrivateRPC(const char* inputJSON);
|
||||
|
||||
template<class T>
|
||||
template <class T>
|
||||
RpcResponse<T> callPrivateRpc(const QByteArray& payload)
|
||||
{
|
||||
try
|
||||
|
@ -98,13 +97,13 @@ RpcResponse<T> callPrivateRpc(const QByteArray& payload)
|
|||
|
||||
return Utils::buildPrivateRPCResponse(jsonResult);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
catch(std::exception& e)
|
||||
{
|
||||
auto response = RpcResponse<T>(T());
|
||||
response.error.message = QObject::tr("an error executing rpc call occurred, msg: %1").arg(e.what());
|
||||
return response;
|
||||
}
|
||||
catch (...)
|
||||
catch(...)
|
||||
{
|
||||
auto response = RpcResponse<T>(T());
|
||||
response.error.message = QObject::tr("an error executing rpc call");
|
||||
|
@ -112,6 +111,6 @@ RpcResponse<T> callPrivateRpc(const QByteArray& payload)
|
|||
}
|
||||
}
|
||||
|
||||
HashedPassword hashPassword(const QString &str);
|
||||
HashedPassword hashPassword(const QString& str);
|
||||
|
||||
}
|
||||
} // namespace Status::StatusGo::Utils
|
||||
|
|
|
@ -1,42 +1,42 @@
|
|||
#include "BigInt.h"
|
||||
|
||||
#include <locale>
|
||||
#include <iostream>
|
||||
#include <locale>
|
||||
|
||||
#include <Helpers/helpers.h>
|
||||
|
||||
namespace Status {
|
||||
namespace StatusGo::Wallet {
|
||||
|
||||
std::string toHexData(const BigInt &num, bool uppercase)
|
||||
namespace Status
|
||||
{
|
||||
namespace StatusGo::Wallet
|
||||
{
|
||||
return num.str(0, std::ios_base::showbase | std::ios_base::hex | (uppercase ? std::ios_base::uppercase : std::ios_base::fmtflags(0)));
|
||||
}
|
||||
|
||||
std::string toHexData(const BigInt& num, bool uppercase)
|
||||
{
|
||||
return num.str(0,
|
||||
std::ios_base::showbase | std::ios_base::hex |
|
||||
(uppercase ? std::ios_base::uppercase : std::ios_base::fmtflags(0)));
|
||||
}
|
||||
|
||||
using namespace QtLiterals;
|
||||
|
||||
bool has0xPrefix(const QByteArray &in) {
|
||||
bool has0xPrefix(const QByteArray& in)
|
||||
{
|
||||
return in.size() >= 2 && Helpers::iequals(in.first(2), "0x"_qba);
|
||||
}
|
||||
|
||||
BigInt parseHex(const std::string &value)
|
||||
BigInt parseHex(const std::string& value)
|
||||
{
|
||||
auto data = QByteArray::fromRawData(value.c_str(), value.size());
|
||||
if (!has0xPrefix(data))
|
||||
throw std::runtime_error("BigInt::parseHex missing 0x prefix");
|
||||
if (data.size() == 2)
|
||||
throw std::runtime_error("BigInt::parseHex empty number");
|
||||
if (data.size() > 3 && data[2] == '0')
|
||||
throw std::runtime_error("BigInt::parseHex leading zero");
|
||||
if (data.size() > 66)
|
||||
throw std::runtime_error("BigInt::parseHex more than 256 bits");
|
||||
if(!has0xPrefix(data)) throw std::runtime_error("BigInt::parseHex missing 0x prefix");
|
||||
if(data.size() == 2) throw std::runtime_error("BigInt::parseHex empty number");
|
||||
if(data.size() > 3 && data[2] == '0') throw std::runtime_error("BigInt::parseHex leading zero");
|
||||
if(data.size() > 66) throw std::runtime_error("BigInt::parseHex more than 256 bits");
|
||||
return BigInt{data.data()};
|
||||
}
|
||||
|
||||
} // namespace StatusGo::Wallet
|
||||
|
||||
QString toQString(const StatusGo::Wallet::BigInt &num)
|
||||
QString toQString(const StatusGo::Wallet::BigInt& num)
|
||||
{
|
||||
return QString::fromStdString(num.str(0, std::ios_base::dec));
|
||||
}
|
||||
|
|
|
@ -11,37 +11,43 @@
|
|||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace Status {
|
||||
namespace StatusGo::Wallet {
|
||||
namespace Status
|
||||
{
|
||||
namespace StatusGo::Wallet
|
||||
{
|
||||
|
||||
using BigInt = boost::multiprecision::uint256_t;
|
||||
|
||||
/// Converts into the 0x prefixed hexadecimal display required by status-go (also uppercase)
|
||||
std::string toHexData(const BigInt &num, bool uppercase = false);
|
||||
std::string toHexData(const BigInt& num, bool uppercase = false);
|
||||
|
||||
/// \throws std::runtime_error if value is not a valid status-go hex string
|
||||
/// or value is higher than 2^64 (numbers larger than 256 bits are not accepted)
|
||||
/// \see toHexData
|
||||
BigInt parseHex(const std::string &value);
|
||||
BigInt parseHex(const std::string& value);
|
||||
|
||||
}
|
||||
} // namespace StatusGo::Wallet
|
||||
|
||||
/// Human readable form
|
||||
QString toQString(const StatusGo::Wallet::BigInt &num);
|
||||
QString toQString(const StatusGo::Wallet::BigInt& num);
|
||||
|
||||
} // Status::StatusGo::Wallet
|
||||
} // namespace Status
|
||||
|
||||
namespace nlohmann {
|
||||
namespace nlohmann
|
||||
{
|
||||
|
||||
namespace GoWallet = Status::StatusGo::Wallet;
|
||||
|
||||
template<>
|
||||
struct adl_serializer<GoWallet::BigInt> {
|
||||
static void to_json(json& j, const GoWallet::BigInt& num) {
|
||||
template <>
|
||||
struct adl_serializer<GoWallet::BigInt>
|
||||
{
|
||||
static void to_json(json& j, const GoWallet::BigInt& num)
|
||||
{
|
||||
j = GoWallet::toHexData(num);
|
||||
}
|
||||
|
||||
static void from_json(const json& j, GoWallet::BigInt& num) {
|
||||
static void from_json(const json& j, GoWallet::BigInt& num)
|
||||
{
|
||||
num = GoWallet::BigInt(j.get<std::string>());
|
||||
}
|
||||
};
|
||||
|
|
|
@ -14,7 +14,8 @@ namespace Accounts = Status::StatusGo::Accounts;
|
|||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace Status::StatusGo::Wallet {
|
||||
namespace Status::StatusGo::Wallet
|
||||
{
|
||||
|
||||
/// \brief Define a derived address as returned by the corresponding API
|
||||
/// \note equivalent of status-go's DerivedAddress@api.go
|
||||
|
@ -31,4 +32,4 @@ using DerivedAddresses = std::vector<DerivedAddress>;
|
|||
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(DerivedAddress, address, path, hasActivity, alreadyCreated);
|
||||
|
||||
}
|
||||
} // namespace Status::StatusGo::Wallet
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
using json = nlohmann::json;
|
||||
|
||||
/// \note not sure if this is the best namespace, ok for now
|
||||
namespace Status::StatusGo::Wallet {
|
||||
namespace Status::StatusGo::Wallet
|
||||
{
|
||||
|
||||
/// \note equivalent of status-go's Network@config.go (params package)
|
||||
struct NetworkConfiguration
|
||||
|
@ -34,9 +35,19 @@ struct NetworkConfiguration
|
|||
|
||||
using NetworkConfigurations = std::vector<NetworkConfiguration>;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(NetworkConfiguration, chainId, chainName, rpcUrl, blockExplorerUrl,
|
||||
iconUrl, nativeCurrencyName, nativeCurrencySymbol,
|
||||
nativeCurrencyDecimals, isTest, layer, enabled, chainColor,
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(NetworkConfiguration,
|
||||
chainId,
|
||||
chainName,
|
||||
rpcUrl,
|
||||
blockExplorerUrl,
|
||||
iconUrl,
|
||||
nativeCurrencyName,
|
||||
nativeCurrencySymbol,
|
||||
nativeCurrencyDecimals,
|
||||
isTest,
|
||||
layer,
|
||||
enabled,
|
||||
chainColor,
|
||||
shortName);
|
||||
|
||||
}
|
||||
} // namespace Status::StatusGo::Wallet
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "wallet_types.h"
|
||||
#include "Accounts/accounts_types.h"
|
||||
#include "wallet_types.h"
|
||||
|
||||
#include <Helpers/conversions.h>
|
||||
|
||||
|
@ -11,7 +11,8 @@
|
|||
|
||||
namespace Accounts = Status::StatusGo::Accounts;
|
||||
|
||||
namespace Status::StatusGo::Wallet {
|
||||
namespace Status::StatusGo::Wallet
|
||||
{
|
||||
|
||||
/// \brief Define a saved wallet address as returned by the corresponding API
|
||||
/// \note equivalent of status-go's SavedAddress@api.go
|
||||
|
@ -28,4 +29,4 @@ using SavedAddresses = std::vector<SavedAddress>;
|
|||
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SavedAddress, address, name, favourite, chainId);
|
||||
|
||||
}
|
||||
} // namespace Status::StatusGo::Wallet
|
||||
|
|
|
@ -14,24 +14,24 @@ namespace Accounts = Status::StatusGo::Accounts;
|
|||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace Status::StatusGo::Wallet {
|
||||
namespace Status::StatusGo::Wallet
|
||||
{
|
||||
|
||||
/// \note equivalent of status-go's Token@token.go
|
||||
/// \see \c getDerivedAddressesForPath
|
||||
struct Token
|
||||
{
|
||||
Accounts::EOAddress address;
|
||||
QString name;
|
||||
QString symbol;
|
||||
QColor color;
|
||||
unsigned int decimals;
|
||||
ChainID chainId;
|
||||
QString name;
|
||||
QString symbol;
|
||||
QColor color;
|
||||
unsigned int decimals;
|
||||
ChainID chainId;
|
||||
};
|
||||
|
||||
using TokenPtr = std::shared_ptr<Token>;
|
||||
using Tokens = std::vector<Token>;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Token, address, name,symbol,
|
||||
color, decimals, chainId);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Token, address, name, symbol, color, decimals, chainId);
|
||||
|
||||
}
|
||||
} // namespace Status::StatusGo::Wallet
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "WalletApi.h"
|
||||
|
||||
#include "Utils.h"
|
||||
#include "Metadata/api_response.h"
|
||||
#include "Utils.h"
|
||||
|
||||
#include "Accounts/accounts_types.h"
|
||||
|
||||
|
@ -18,14 +18,14 @@ using json = nlohmann::json;
|
|||
namespace Status::StatusGo::Wallet
|
||||
{
|
||||
|
||||
DerivedAddresses getDerivedAddressesForPath(const HashedPassword &password, const Accounts::EOAddress &derivedFrom, const Accounts::DerivationPath &path, int pageSize, int pageNumber)
|
||||
DerivedAddresses getDerivedAddressesForPath(const HashedPassword& password,
|
||||
const Accounts::EOAddress& derivedFrom,
|
||||
const Accounts::DerivationPath& path,
|
||||
int pageSize,
|
||||
int pageNumber)
|
||||
{
|
||||
std::vector<json> params = {password, derivedFrom, path, pageSize, pageNumber};
|
||||
json inputJson = {
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "wallet_getDerivedAddressesForPath"},
|
||||
{"params", params}
|
||||
};
|
||||
json inputJson = {{"jsonrpc", "2.0"}, {"method", "wallet_getDerivedAddressesForPath"}, {"params", params}};
|
||||
|
||||
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
|
||||
const auto resultJson = json::parse(result);
|
||||
|
@ -36,27 +36,20 @@ DerivedAddresses getDerivedAddressesForPath(const HashedPassword &password, cons
|
|||
|
||||
SavedAddresses getSavedAddresses()
|
||||
{
|
||||
json inputJson = {
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "wallet_getSavedAddresses"}
|
||||
};
|
||||
json inputJson = {{"jsonrpc", "2.0"}, {"method", "wallet_getSavedAddresses"}};
|
||||
|
||||
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
|
||||
const auto resultJson = json::parse(result);
|
||||
checkPrivateRpcCallResultAndReportError(resultJson);
|
||||
|
||||
const auto &data = resultJson.get<CallPrivateRpcResponse>().result;
|
||||
const auto& data = resultJson.get<CallPrivateRpcResponse>().result;
|
||||
return data.is_null() ? json::array() : data;
|
||||
}
|
||||
|
||||
void saveAddress(const SavedAddress &address)
|
||||
void saveAddress(const SavedAddress& address)
|
||||
{
|
||||
std::vector<json> params = { address };
|
||||
json inputJson = {
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "wakuext_upsertSavedAddress"},
|
||||
{"params", params}
|
||||
};
|
||||
std::vector<json> params = {address};
|
||||
json inputJson = {{"jsonrpc", "2.0"}, {"method", "wakuext_upsertSavedAddress"}, {"params", params}};
|
||||
|
||||
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
|
||||
auto resultJson = json::parse(result);
|
||||
|
@ -66,64 +59,53 @@ void saveAddress(const SavedAddress &address)
|
|||
NetworkConfigurations getEthereumChains(bool onlyEnabled)
|
||||
{
|
||||
std::vector<json> params = {onlyEnabled};
|
||||
json inputJson = {
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "wallet_getEthereumChains"},
|
||||
{"params", params}
|
||||
};
|
||||
json inputJson = {{"jsonrpc", "2.0"}, {"method", "wallet_getEthereumChains"}, {"params", params}};
|
||||
|
||||
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
|
||||
const auto resultJson = json::parse(result);
|
||||
checkPrivateRpcCallResultAndReportError(resultJson);
|
||||
|
||||
const auto &data = resultJson.get<CallPrivateRpcResponse>().result;
|
||||
const auto& data = resultJson.get<CallPrivateRpcResponse>().result;
|
||||
return data.is_null() ? json::array() : data;
|
||||
}
|
||||
|
||||
Tokens getTokens(const ChainID &chainId)
|
||||
Tokens getTokens(const ChainID& chainId)
|
||||
{
|
||||
std::vector<json> params = {chainId};
|
||||
json inputJson = {
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "wallet_getTokens"},
|
||||
{"params", params}
|
||||
};
|
||||
json inputJson = {{"jsonrpc", "2.0"}, {"method", "wallet_getTokens"}, {"params", params}};
|
||||
|
||||
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
|
||||
const auto resultJson = json::parse(result);
|
||||
checkPrivateRpcCallResultAndReportError(resultJson);
|
||||
|
||||
const auto &data = resultJson.get<CallPrivateRpcResponse>().result;
|
||||
const auto& data = resultJson.get<CallPrivateRpcResponse>().result;
|
||||
return data.is_null() ? json::array() : data;
|
||||
}
|
||||
|
||||
TokenBalances getTokensBalancesForChainIDs(const std::vector<ChainID> &chainIds,
|
||||
TokenBalances getTokensBalancesForChainIDs(const std::vector<ChainID>& chainIds,
|
||||
const std::vector<Accounts::EOAddress> accounts,
|
||||
const std::vector<Accounts::EOAddress> tokens)
|
||||
{
|
||||
std::vector<json> params = {chainIds, accounts, tokens};
|
||||
json inputJson = {
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "wallet_getTokensBalancesForChainIDs"},
|
||||
{"params", params}
|
||||
};
|
||||
json inputJson = {{"jsonrpc", "2.0"}, {"method", "wallet_getTokensBalancesForChainIDs"}, {"params", params}};
|
||||
|
||||
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
|
||||
const auto resultJson = json::parse(result);
|
||||
checkPrivateRpcCallResultAndReportError(resultJson);
|
||||
|
||||
TokenBalances resultData;
|
||||
const auto &data = resultJson.get<CallPrivateRpcResponse>().result;
|
||||
const auto& data = resultJson.get<CallPrivateRpcResponse>().result;
|
||||
// Workaround to exception "type must be array, but is object" for custom key-types
|
||||
// TODO: find out why
|
||||
std::map<std::string, std::map<std::string, BigInt>> dataMap = data.is_null() ? nlohmann::json() : data;
|
||||
for(const auto &keyIt : dataMap) {
|
||||
for(const auto& keyIt : dataMap)
|
||||
{
|
||||
std::map<Accounts::EOAddress, BigInt> val;
|
||||
for(const auto &valIt : keyIt.second)
|
||||
for(const auto& valIt : keyIt.second)
|
||||
val.emplace(QString::fromStdString(valIt.first), valIt.second);
|
||||
resultData.emplace(QString::fromStdString(keyIt.first), std::move(val));
|
||||
}
|
||||
return resultData;
|
||||
}
|
||||
|
||||
} // namespaces
|
||||
} // namespace Status::StatusGo::Wallet
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
|
||||
#include "DerivedAddress.h"
|
||||
#include "NetworkConfiguration.h"
|
||||
#include "Token.h"
|
||||
#include "SavedAddress.h"
|
||||
#include "Token.h"
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
|
@ -20,10 +20,11 @@ namespace Status::StatusGo::Wallet
|
|||
/// \brief Retrieve a list of derived account addresses
|
||||
/// \see \c generateAccountWithDerivedPath
|
||||
/// \throws \c CallPrivateRpcError
|
||||
DerivedAddresses getDerivedAddressesForPath(const HashedPassword &password,
|
||||
const Accounts::EOAddress &derivedFrom,
|
||||
const Accounts::DerivationPath &path,
|
||||
int pageSize, int pageNumber);
|
||||
DerivedAddresses getDerivedAddressesForPath(const HashedPassword& password,
|
||||
const Accounts::EOAddress& derivedFrom,
|
||||
const Accounts::DerivationPath& path,
|
||||
int pageSize,
|
||||
int pageNumber);
|
||||
|
||||
/// \brief Retrieve a list of saved wallet addresses
|
||||
/// \see \c getSavedAddresses
|
||||
|
@ -33,7 +34,7 @@ SavedAddresses getSavedAddresses();
|
|||
/// \brief Add a new or update existing saved wallet address
|
||||
/// \see wakuext_upsertSavedAddress RPC method
|
||||
/// \throws \c CallPrivateRpcError
|
||||
void saveAddress(const SavedAddress &address);
|
||||
void saveAddress(const SavedAddress& address);
|
||||
|
||||
/// \note status-go's GetEthereumChains@api.go which calls
|
||||
/// NetworkManager@client.go -> network.Manager.get()
|
||||
|
@ -46,15 +47,14 @@ NetworkConfigurations getEthereumChains(bool onlyEnabled);
|
|||
/// \throws \c CallPrivateRpcError for general RPC call failure
|
||||
NetworkConfigurations getEthereumChains(bool onlyEnabled);
|
||||
|
||||
|
||||
/// \note status-go's GetTokens@api.go -> TokenManager.getTokens@token.go
|
||||
/// \throws \c CallPrivateRpcError with
|
||||
Tokens getTokens(const ChainID &chainId);
|
||||
Tokens getTokens(const ChainID& chainId);
|
||||
|
||||
using TokenBalances = std::map<Accounts::EOAddress, std::map<Accounts::EOAddress, BigInt>>;
|
||||
/// \note status-go's @api.go -> <xx>@<xx>.go
|
||||
/// \throws \c CallPrivateRpcError
|
||||
TokenBalances getTokensBalancesForChainIDs(const std::vector<ChainID> &chainIds,
|
||||
TokenBalances getTokensBalancesForChainIDs(const std::vector<ChainID>& chainIds,
|
||||
const std::vector<Accounts::EOAddress> accounts,
|
||||
const std::vector<Accounts::EOAddress> tokens);
|
||||
} // namespaces
|
||||
} // namespace Status::StatusGo::Wallet
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
|
||||
#include <QString>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
/// Defines phantom types for strong typing
|
||||
namespace Status::StatusGo::Wallet {
|
||||
namespace Status::StatusGo::Wallet
|
||||
{
|
||||
|
||||
using ChainID = Helpers::NamedType<unsigned long long int, struct ChainIDTag>;
|
||||
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
|
||||
using json = nlohmann::json;
|
||||
namespace StatusGo = Status::StatusGo;
|
||||
namespace Status::Testing {
|
||||
namespace Status::Testing
|
||||
{
|
||||
|
||||
TEST(StatusGoQt, TestJsonParsing)
|
||||
{
|
||||
|
@ -19,13 +20,15 @@ TEST(StatusGoQt, TestJsonParsing)
|
|||
ASSERT_EQ(callRawRPCJson.error.message, expectedJsonError.message);
|
||||
|
||||
auto callRawRPCBadJsonKeyStr = R"({"unknown":"2.0","id":42,"error":{"code":-32601,"message":"Method not found"}})";
|
||||
ASSERT_THROW(json::parse(callRawRPCBadJsonKeyStr).get<StatusGo::CallPrivateRpcErrorResponse>(), nlohmann::detail::out_of_range);
|
||||
ASSERT_THROW(json::parse(callRawRPCBadJsonKeyStr).get<StatusGo::CallPrivateRpcErrorResponse>(),
|
||||
nlohmann::detail::out_of_range);
|
||||
auto callRawRPCBadJsonValStr = R"({"jsonrpc":"2.0","id":42,"error":23})";
|
||||
ASSERT_THROW(json::parse(callRawRPCBadJsonValStr).get<StatusGo::CallPrivateRpcErrorResponse>(), nlohmann::detail::type_error);
|
||||
ASSERT_THROW(json::parse(callRawRPCBadJsonValStr).get<StatusGo::CallPrivateRpcErrorResponse>(),
|
||||
nlohmann::detail::type_error);
|
||||
|
||||
auto statusGoWithResultJsonStr = R"({"result":"0x123"})";
|
||||
auto statusGoWithResultJson = json::parse(statusGoWithResultJsonStr).get<StatusGo::ApiResponse>();
|
||||
ASSERT_EQ(statusGoWithResultJson.result, "0x123");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace Status::Testing
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace Status::Testing {
|
||||
namespace Status::Testing
|
||||
{
|
||||
|
||||
fs::path createTestFolder(const std::string& testName)
|
||||
{
|
||||
|
@ -12,14 +13,13 @@ fs::path createTestFolder(const std::string& testName)
|
|||
auto tm = *std::localtime(&t);
|
||||
std::ostringstream timeOss;
|
||||
timeOss << std::put_time(&tm, "%d-%m-%Y_%H-%M-%S");
|
||||
return fs::path(testing::TempDir())/"StatusTests"/(testName + "-" + timeOss.str());
|
||||
return fs::path(testing::TempDir()) / "StatusTests" / (testName + "-" + timeOss.str());
|
||||
}
|
||||
|
||||
AutoCleanTempTestDir::AutoCleanTempTestDir(const std::string &testName, bool createDir)
|
||||
AutoCleanTempTestDir::AutoCleanTempTestDir(const std::string& testName, bool createDir)
|
||||
: m_testFolder(createTestFolder(testName))
|
||||
{
|
||||
if(createDir)
|
||||
fs::create_directories(m_testFolder);
|
||||
if(createDir) fs::create_directories(m_testFolder);
|
||||
}
|
||||
|
||||
AutoCleanTempTestDir::~AutoCleanTempTestDir()
|
||||
|
@ -33,4 +33,4 @@ const std::filesystem::path& AutoCleanTempTestDir::tempFolder()
|
|||
return m_testFolder;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::Testing
|
||||
|
|
|
@ -4,9 +4,11 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
namespace Status::Testing {
|
||||
namespace Status::Testing
|
||||
{
|
||||
|
||||
class AutoCleanTempTestDir {
|
||||
class AutoCleanTempTestDir
|
||||
{
|
||||
public:
|
||||
/// Creates a temporary folder to be used in tests. The folder content's will
|
||||
/// be removed when out of scope
|
||||
|
@ -19,4 +21,4 @@ private:
|
|||
const std::filesystem::path m_testFolder;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Status::Testing
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace Status::Testing {
|
||||
namespace Status::Testing
|
||||
{
|
||||
|
||||
std::weak_ptr<QString> MonitorQtOutput::m_qtMessageOutputForSharing;
|
||||
std::mutex MonitorQtOutput::m_mutex;
|
||||
QtMessageHandler MonitorQtOutput::m_previousHandler = nullptr;
|
||||
|
||||
|
||||
MonitorQtOutput::MonitorQtOutput()
|
||||
{
|
||||
// Ensure only one instance registers a handler
|
||||
|
@ -17,13 +17,14 @@ MonitorQtOutput::MonitorQtOutput()
|
|||
std::unique_lock<std::mutex> localLock(m_mutex);
|
||||
auto globalMsgOut = m_qtMessageOutputForSharing.lock();
|
||||
auto prev = qInstallMessageHandler(qtMessageOutput);
|
||||
if(prev != qtMessageOutput)
|
||||
m_previousHandler = prev;
|
||||
if(!globalMsgOut) {
|
||||
if(prev != qtMessageOutput) m_previousHandler = prev;
|
||||
if(!globalMsgOut)
|
||||
{
|
||||
m_thisMessageOutput = std::make_shared<QString>();
|
||||
m_qtMessageOutputForSharing = m_thisMessageOutput;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
m_thisMessageOutput = globalMsgOut;
|
||||
m_start = m_thisMessageOutput->length();
|
||||
}
|
||||
|
@ -32,15 +33,15 @@ MonitorQtOutput::MonitorQtOutput()
|
|||
MonitorQtOutput::~MonitorQtOutput()
|
||||
{
|
||||
std::unique_lock<std::mutex> localLock(m_mutex);
|
||||
if(m_thisMessageOutput.use_count() == 1) {
|
||||
if(m_thisMessageOutput.use_count() == 1)
|
||||
{
|
||||
// Last instance, deregister the handler
|
||||
qInstallMessageHandler(0);
|
||||
m_thisMessageOutput.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MonitorQtOutput::qtMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
||||
void MonitorQtOutput::qtMessageOutput(QtMsgType type, const QMessageLogContext& context, const QString& msg)
|
||||
{
|
||||
std::unique_lock<std::mutex> localLock(m_mutex);
|
||||
auto globalMsgOut = m_qtMessageOutputForSharing.lock();
|
||||
|
@ -50,23 +51,20 @@ MonitorQtOutput::qtMessageOutput(QtMsgType type, const QMessageLogContext &conte
|
|||
m_previousHandler(type, context, msg);
|
||||
}
|
||||
|
||||
QString
|
||||
MonitorQtOutput::qtOuput()
|
||||
QString MonitorQtOutput::qtOuput()
|
||||
{
|
||||
std::unique_lock<std::mutex> localLock(m_mutex);
|
||||
assert(m_thisMessageOutput->length() >= m_start);
|
||||
return m_thisMessageOutput->right(m_thisMessageOutput->length() - m_start);
|
||||
}
|
||||
|
||||
void
|
||||
MonitorQtOutput::restartCapturing()
|
||||
void MonitorQtOutput::restartCapturing()
|
||||
{
|
||||
std::unique_lock<std::mutex> localLock(m_mutex);
|
||||
// Ensure the messageHandler is installed. Foun to be reset at test initializaiton
|
||||
auto prev = qInstallMessageHandler(qtMessageOutput);
|
||||
if(prev != qtMessageOutput)
|
||||
m_previousHandler = prev;
|
||||
if(prev != qtMessageOutput) m_previousHandler = prev;
|
||||
m_start = m_thisMessageOutput->length();
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::Testing
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace Status::Testing {
|
||||
namespace Status::Testing
|
||||
{
|
||||
|
||||
///
|
||||
/// \brief Monitor output for tests and declaratively control message handler availability
|
||||
|
@ -36,7 +37,7 @@ public:
|
|||
signals:
|
||||
|
||||
private:
|
||||
static void qtMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg);
|
||||
static void qtMessageOutput(QtMsgType type, const QMessageLogContext& context, const QString& msg);
|
||||
static QtMessageHandler m_previousHandler;
|
||||
|
||||
// Use it to keep track of qInstallMessageHandler call
|
||||
|
@ -46,4 +47,4 @@ private:
|
|||
int m_start = 0;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Status::Testing
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
|
||||
#include <QtQmlIntegration>
|
||||
|
||||
namespace Status::Wallet {
|
||||
namespace Status::Wallet
|
||||
{
|
||||
|
||||
/// Controlls asset for an account using hardcoded network and token lists
|
||||
///
|
||||
|
@ -15,7 +16,7 @@ namespace Status::Wallet {
|
|||
/// \todo impliement \c AccountsBalanceService to fetch and cache realtime balance (or better implement this in status-go)
|
||||
/// \todo implement native token fetching
|
||||
/// \todo double responsibility, split functionality in asset management and balance
|
||||
class AccountAssetsController: public QObject
|
||||
class AccountAssetsController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
|
||||
namespace WalletGo = Status::StatusGo::Wallet;
|
||||
|
||||
namespace Status::Wallet {
|
||||
namespace Status::Wallet
|
||||
{
|
||||
|
||||
class DerivedWalletAddress : public QObject
|
||||
{
|
||||
|
@ -18,11 +19,14 @@ class DerivedWalletAddress : public QObject
|
|||
Q_PROPERTY(bool alreadyCreated READ alreadyCreated CONSTANT)
|
||||
|
||||
public:
|
||||
explicit DerivedWalletAddress(WalletGo::DerivedAddress address, QObject *parent = nullptr);
|
||||
explicit DerivedWalletAddress(WalletGo::DerivedAddress address, QObject* parent = nullptr);
|
||||
|
||||
QString address() const;
|
||||
|
||||
const WalletGo::DerivedAddress &data() const { return m_derivedAddress; };
|
||||
const WalletGo::DerivedAddress& data() const
|
||||
{
|
||||
return m_derivedAddress;
|
||||
};
|
||||
|
||||
bool alreadyCreated() const;
|
||||
|
||||
|
@ -32,4 +36,4 @@ private:
|
|||
|
||||
using DerivedWalletAddressPtr = std::shared_ptr<DerivedWalletAddress>;
|
||||
|
||||
}
|
||||
} // namespace Status::Wallet
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include "Status/Wallet/WalletAccount.h"
|
||||
#include "Status/Wallet/DerivedWalletAddress.h"
|
||||
#include "Status/Wallet/WalletAccount.h"
|
||||
|
||||
#include <Helpers/QObjectVectorModel.h>
|
||||
|
||||
#include <QtQmlIntegration>
|
||||
|
||||
namespace Status::Wallet {
|
||||
namespace Status::Wallet
|
||||
{
|
||||
|
||||
/// \note the following values are kept in sync \c selectedDerivedAddress, \c derivedAddressIndex and \c derivationPath
|
||||
/// and \c customDerivationPath; \see connascence.io/value
|
||||
class NewWalletAccountController: public QObject
|
||||
class NewWalletAccountController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
@ -20,7 +21,8 @@ class NewWalletAccountController: public QObject
|
|||
Q_PROPERTY(QAbstractListModel* mainAccountsModel READ mainAccountsModel CONSTANT)
|
||||
|
||||
Q_PROPERTY(QAbstractItemModel* currentDerivedAddressModel READ currentDerivedAddressModel CONSTANT)
|
||||
Q_PROPERTY(DerivedWalletAddress* selectedDerivedAddress READ selectedDerivedAddress WRITE setSelectedDerivedAddress NOTIFY selectedDerivedAddressChanged)
|
||||
Q_PROPERTY(DerivedWalletAddress* selectedDerivedAddress READ selectedDerivedAddress WRITE setSelectedDerivedAddress
|
||||
NOTIFY selectedDerivedAddressChanged)
|
||||
Q_PROPERTY(int derivedAddressIndex MEMBER m_derivedAddressIndex NOTIFY selectedDerivedAddressChanged)
|
||||
|
||||
Q_PROPERTY(QString derivationPath READ derivationPath WRITE setDerivationPath NOTIFY derivationPathChanged)
|
||||
|
@ -32,29 +34,29 @@ public:
|
|||
/// \note On account creation \c accounts are updated with the newly created wallet account
|
||||
NewWalletAccountController(std::shared_ptr<AccountsModel> accounts);
|
||||
|
||||
QAbstractListModel *mainAccountsModel();
|
||||
QAbstractItemModel *currentDerivedAddressModel();
|
||||
QAbstractListModel* mainAccountsModel();
|
||||
QAbstractItemModel* currentDerivedAddressModel();
|
||||
|
||||
QString derivationPath() const;
|
||||
void setDerivationPath(const QString &newDerivationPath);
|
||||
void setDerivationPath(const QString& newDerivationPath);
|
||||
|
||||
/// \see \c accountCreatedStatus for async result
|
||||
Q_INVOKABLE void createAccountAsync(const QString &password, const QString &name,
|
||||
const QColor &color, const QString &path,
|
||||
const Status::Wallet::WalletAccount *derivedFrom);
|
||||
Q_INVOKABLE void createAccountAsync(const QString& password,
|
||||
const QString& name,
|
||||
const QColor& color,
|
||||
const QString& path,
|
||||
const Status::Wallet::WalletAccount* derivedFrom);
|
||||
|
||||
/// \see \c accountCreatedStatus for async result
|
||||
Q_INVOKABLE void addWatchOnlyAccountAsync(const QString &address, const QString &name,
|
||||
const QColor &color);
|
||||
|
||||
Q_INVOKABLE void addWatchOnlyAccountAsync(const QString& address, const QString& name, const QColor& color);
|
||||
|
||||
/// \returns \c false if fails (due to incomplete user input)
|
||||
Q_INVOKABLE bool retrieveAndUpdateDerivedAddresses(const QString &password,
|
||||
const Status::Wallet::WalletAccount *derivedFrom);
|
||||
Q_INVOKABLE bool retrieveAndUpdateDerivedAddresses(const QString& password,
|
||||
const Status::Wallet::WalletAccount* derivedFrom);
|
||||
Q_INVOKABLE void clearDerivedAddresses();
|
||||
|
||||
DerivedWalletAddress *selectedDerivedAddress() const;
|
||||
void setSelectedDerivedAddress(DerivedWalletAddress *newSelectedDerivedAddress);
|
||||
DerivedWalletAddress* selectedDerivedAddress() const;
|
||||
void setSelectedDerivedAddress(DerivedWalletAddress* newSelectedDerivedAddress);
|
||||
|
||||
signals:
|
||||
void accountCreatedStatus(bool createdSuccessfully);
|
||||
|
@ -68,11 +70,11 @@ signals:
|
|||
private:
|
||||
void updateSelectedDerivedAddress(int index, std::shared_ptr<DerivedWalletAddress> newEntry);
|
||||
|
||||
std::tuple<DerivedWalletAddressPtr, int> searchDerivationPath(const GoAccounts::DerivationPath &derivationPath);
|
||||
std::tuple<DerivedWalletAddressPtr, int> searchDerivationPath(const GoAccounts::DerivationPath& derivationPath);
|
||||
|
||||
WalletAccountPtr findMissingAccount();
|
||||
|
||||
AccountsModel::ObjectContainer filterMainAccounts(const AccountsModel &accounts);
|
||||
AccountsModel::ObjectContainer filterMainAccounts(const AccountsModel& accounts);
|
||||
/// Logs a debug message if it fails
|
||||
void addNewlyCreatedAccount(WalletAccountPtr newAccount);
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
|
||||
#include <QtQmlIntegration>
|
||||
|
||||
namespace Status::Wallet {
|
||||
namespace Status::Wallet
|
||||
{
|
||||
|
||||
class SavedAddress : public QObject
|
||||
{
|
||||
|
@ -16,8 +17,7 @@ class SavedAddress : public QObject
|
|||
Q_PROPERTY(QString name READ name CONSTANT)
|
||||
|
||||
public:
|
||||
SavedAddress(const QString &address = QString(), const QString &name = QString(),
|
||||
QObject *parent = nullptr);
|
||||
SavedAddress(const QString& address = QString(), const QString& name = QString(), QObject* parent = nullptr);
|
||||
|
||||
const QString& address() const;
|
||||
const QString& name() const;
|
||||
|
@ -28,4 +28,4 @@ private:
|
|||
};
|
||||
|
||||
using SavedAddressPtr = std::shared_ptr<SavedAddress>;
|
||||
}
|
||||
} // namespace Status::Wallet
|
||||
|
|
|
@ -15,7 +15,7 @@ class SavedAddressesController : public QObject
|
|||
QML_ELEMENT
|
||||
QML_UNCREATABLE("C++ only")
|
||||
|
||||
Q_PROPERTY(QAbstractListModel *savedAddresses READ savedAddresses CONSTANT)
|
||||
Q_PROPERTY(QAbstractListModel* savedAddresses READ savedAddresses CONSTANT)
|
||||
|
||||
public:
|
||||
enum Error
|
||||
|
@ -26,11 +26,11 @@ public:
|
|||
};
|
||||
Q_ENUM(Error)
|
||||
|
||||
explicit SavedAddressesController(QObject *parent = nullptr);
|
||||
explicit SavedAddressesController(QObject* parent = nullptr);
|
||||
|
||||
QAbstractListModel *savedAddresses() const;
|
||||
QAbstractListModel* savedAddresses() const;
|
||||
|
||||
Q_INVOKABLE void saveAddress(const QString &address, const QString &name);
|
||||
Q_INVOKABLE void saveAddress(const QString& address, const QString& name);
|
||||
Q_INVOKABLE void refresh();
|
||||
|
||||
signals:
|
||||
|
|
|
@ -6,9 +6,10 @@
|
|||
|
||||
namespace GoAccounts = Status::StatusGo::Accounts;
|
||||
|
||||
namespace Status::Wallet {
|
||||
namespace Status::Wallet
|
||||
{
|
||||
|
||||
class WalletAccount: public QObject
|
||||
class WalletAccount : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
@ -19,15 +20,18 @@ class WalletAccount: public QObject
|
|||
Q_PROPERTY(QColor color READ color CONSTANT)
|
||||
|
||||
public:
|
||||
explicit WalletAccount(const GoAccounts::ChatOrWalletAccount rawAccount, QObject *parent = nullptr);
|
||||
explicit WalletAccount(const GoAccounts::ChatOrWalletAccount rawAccount, QObject* parent = nullptr);
|
||||
|
||||
const QString &name() const;
|
||||
const QString& name() const;
|
||||
|
||||
const QString &strAddress() const;
|
||||
const QString& strAddress() const;
|
||||
|
||||
QColor color() const;
|
||||
|
||||
const GoAccounts::ChatOrWalletAccount &data() const { return m_data; };
|
||||
const GoAccounts::ChatOrWalletAccount& data() const
|
||||
{
|
||||
return m_data;
|
||||
};
|
||||
|
||||
private:
|
||||
const GoAccounts::ChatOrWalletAccount m_data;
|
||||
|
@ -36,4 +40,4 @@ private:
|
|||
using WalletAccountPtr = std::shared_ptr<WalletAccount>;
|
||||
using WalletAccounts = std::vector<WalletAccount>;
|
||||
|
||||
}
|
||||
} // namespace Status::Wallet
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <StatusGo/Wallet/Token.h>
|
||||
#include <StatusGo/Wallet/BigInt.h>
|
||||
#include <StatusGo/Wallet/Token.h>
|
||||
|
||||
#include <QtQmlIntegration>
|
||||
|
||||
namespace WalletGo = Status::StatusGo::Wallet;
|
||||
|
||||
namespace Status::Wallet {
|
||||
namespace Status::Wallet
|
||||
{
|
||||
|
||||
class WalletAsset : public QObject
|
||||
{
|
||||
|
@ -22,7 +23,7 @@ class WalletAsset : public QObject
|
|||
Q_PROPERTY(float value READ value CONSTANT)
|
||||
|
||||
public:
|
||||
explicit WalletAsset(const WalletGo::TokenPtr token, StatusGo::Wallet::BigInt balance, QObject *parent = nullptr);
|
||||
explicit WalletAsset(const WalletGo::TokenPtr token, StatusGo::Wallet::BigInt balance, QObject* parent = nullptr);
|
||||
|
||||
const QString name() const;
|
||||
|
||||
|
@ -42,4 +43,4 @@ private:
|
|||
int m_count;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Status::Wallet
|
||||
|
|
|
@ -11,14 +11,15 @@
|
|||
class QQmlEngine;
|
||||
class QJSEngine;
|
||||
|
||||
namespace Status::Wallet {
|
||||
namespace Status::Wallet
|
||||
{
|
||||
|
||||
class NewWalletAccountController;
|
||||
class AccountAssetsController;
|
||||
class SavedAddressesController;
|
||||
|
||||
/// \todo move account creation to its own controller
|
||||
class WalletController: public QObject
|
||||
class WalletController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
@ -31,26 +32,27 @@ public:
|
|||
WalletController();
|
||||
|
||||
/// Called by QML engine to register the instance. QML takes ownership of the instance
|
||||
[[nodiscard]] static WalletController *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine);
|
||||
[[nodiscard]] static WalletController* create(QQmlEngine* qmlEngine, QJSEngine* jsEngine);
|
||||
|
||||
/// To be used in the new wallet account workflow
|
||||
/// \note caller (QML) takes ownership of the returned object
|
||||
/// \todo consider if complex approach of keeping ownership here and enforcing a unique instance
|
||||
/// or not reusing the account list and make it singleton are better options
|
||||
Q_INVOKABLE [[nodiscard]] Status::Wallet::NewWalletAccountController *createNewWalletAccountController() const;
|
||||
Q_INVOKABLE [[nodiscard]] Status::Wallet::NewWalletAccountController* createNewWalletAccountController() const;
|
||||
/// Separated controler for working with wallet saved addresses
|
||||
/// \note caller (QML) takes ownership of the returned object
|
||||
/// \todo consider if complex approach of keeping ownership here and enforcing a unique instance
|
||||
/// or not reusing the saved addresses list and make it singleton are better options
|
||||
Q_INVOKABLE [[nodiscard]] Status::Wallet::SavedAddressesController *createSavedAddressesController() const;
|
||||
Q_INVOKABLE [[nodiscard]] Status::Wallet::SavedAddressesController* createSavedAddressesController() const;
|
||||
|
||||
QAbstractListModel *accountsModel() const;
|
||||
QAbstractListModel* accountsModel() const;
|
||||
|
||||
WalletAccount *currentAccount() const;
|
||||
WalletAccount* currentAccount() const;
|
||||
Q_INVOKABLE void setCurrentAccountIndex(int index);
|
||||
|
||||
/// \note caller (QML) takes ownership of the returned instance
|
||||
Q_INVOKABLE Status::Wallet::AccountAssetsController* createAccountAssetsController(Status::Wallet::WalletAccount* account);
|
||||
Q_INVOKABLE Status::Wallet::AccountAssetsController*
|
||||
createAccountAssetsController(Status::Wallet::WalletAccount* account);
|
||||
|
||||
signals:
|
||||
void currentAccountChanged();
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include "Status/Wallet/AccountAssetsController.h"
|
||||
|
||||
#include <StatusGo/Wallet/WalletApi.h>
|
||||
#include <StatusGo/Wallet/BigInt.h>
|
||||
#include <StatusGo/Metadata/api_response.h>
|
||||
#include <StatusGo/Wallet/BigInt.h>
|
||||
#include <StatusGo/Wallet/WalletApi.h>
|
||||
|
||||
#include <Helpers/helpers.h>
|
||||
|
||||
|
@ -10,7 +10,8 @@
|
|||
|
||||
namespace WalletGo = Status::StatusGo::Wallet;
|
||||
|
||||
namespace Status::Wallet {
|
||||
namespace Status::Wallet
|
||||
{
|
||||
|
||||
AccountAssetsController::AccountAssetsController(WalletAccount* address, QObject* parent)
|
||||
: QObject(parent)
|
||||
|
@ -18,7 +19,7 @@ AccountAssetsController::AccountAssetsController(WalletAccount* address, QObject
|
|||
, m_enabledTokens({u"SNT"_qs, u"ETH"_qs, u"STT"_qs, u"DAI"_qs})
|
||||
, m_assets(Helpers::makeSharedQObject<AssetModel>("asset"))
|
||||
{
|
||||
QtConcurrent::run([this, address]{ updateBalances(); })
|
||||
QtConcurrent::run([this, address] { updateBalances(); })
|
||||
.then([this] {
|
||||
m_assetsReady = true;
|
||||
emit assetsReadyChanged();
|
||||
|
@ -30,56 +31,68 @@ AccountAssetsController::AccountAssetsController(WalletAccount* address, QObject
|
|||
})
|
||||
.onFailed([this] {
|
||||
emit assetsReadyChanged();
|
||||
qWarning() << "Unexpected failure while executing updateBalances for account" << m_address->data().address.get();
|
||||
qWarning() << "Unexpected failure while executing updateBalances for account"
|
||||
<< m_address->data().address.get();
|
||||
});
|
||||
}
|
||||
|
||||
void AccountAssetsController::updateBalances()
|
||||
{
|
||||
const StatusGo::Accounts::EOAddress& address = m_address->data().address;
|
||||
if(m_assets->size() > 0)
|
||||
m_assets->clear();
|
||||
if(m_assets->size() > 0) m_assets->clear();
|
||||
// TODO: this should be moved to status-go and exposed as "get balances for account and tokens with currency"
|
||||
std::map<Accounts::EOAddress, StatusGo::Wallet::Token> tokens;
|
||||
std::vector<WalletGo::ChainID> chainIds;
|
||||
auto allNets = WalletGo::getEthereumChains(false);
|
||||
for(const auto &net : allNets) {
|
||||
if(net.enabled && !net.isTest) {
|
||||
try {
|
||||
for(const auto& net : allNets)
|
||||
{
|
||||
if(net.enabled && !net.isTest)
|
||||
{
|
||||
try
|
||||
{
|
||||
const auto allTokens = WalletGo::getTokens(net.chainId);
|
||||
for(const auto& tokenToMove : allTokens) {
|
||||
if(isTokenEnabled(tokenToMove)) {
|
||||
for(const auto& tokenToMove : allTokens)
|
||||
{
|
||||
if(isTokenEnabled(tokenToMove))
|
||||
{
|
||||
auto address = tokenToMove.address;
|
||||
tokens.emplace(std::move(address), std::move(tokenToMove));
|
||||
}
|
||||
}
|
||||
chainIds.push_back(net.chainId);
|
||||
}
|
||||
catch (const StatusGo::CallPrivateRpcError& e) {
|
||||
catch(const StatusGo::CallPrivateRpcError& e)
|
||||
{
|
||||
// Most probably "no tokens for this network"
|
||||
if(e.errorResponse().error.message.compare("no tokens for this network") != 0)
|
||||
qWarning() << "Failed retrieving tokens for network" << net.chainId.get() << "; error" << e.errorResponse().error.message.c_str();
|
||||
qWarning() << "Failed retrieving tokens for network" << net.chainId.get() << "; error"
|
||||
<< e.errorResponse().error.message.c_str();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto accountBalances = WalletGo::getTokensBalancesForChainIDs(chainIds, { address }, std::move(Helpers::getKeys(tokens)));
|
||||
if(accountBalances.size() == 1) {
|
||||
for(const auto& accountAndBalance : accountBalances.begin()->second) {
|
||||
auto asset = Helpers::makeSharedQObject<WalletAsset>(std::make_shared<WalletGo::Token>(tokens.at(accountAndBalance.first)), accountAndBalance.second);
|
||||
auto accountBalances =
|
||||
WalletGo::getTokensBalancesForChainIDs(chainIds, {address}, std::move(Helpers::getKeys(tokens)));
|
||||
if(accountBalances.size() == 1)
|
||||
{
|
||||
for(const auto& accountAndBalance : accountBalances.begin()->second)
|
||||
{
|
||||
auto asset = Helpers::makeSharedQObject<WalletAsset>(
|
||||
std::make_shared<WalletGo::Token>(tokens.at(accountAndBalance.first)), accountAndBalance.second);
|
||||
m_assets->push_back(asset);
|
||||
}
|
||||
}
|
||||
else
|
||||
qWarning() << "Failed fetching balances for account" << address.get() << "; balances count" << accountBalances.size();
|
||||
qWarning() << "Failed fetching balances for account" << address.get() << "; balances count"
|
||||
<< accountBalances.size();
|
||||
}
|
||||
|
||||
bool AccountAssetsController::isTokenEnabled(const StatusGo::Wallet::Token& token) const
|
||||
{
|
||||
return find_if(m_enabledTokens.begin(), m_enabledTokens.end(), [&token](const auto& symbol) {
|
||||
return token.symbol == symbol;
|
||||
}) != m_enabledTokens.end();
|
||||
return token.symbol == symbol;
|
||||
}) != m_enabledTokens.end();
|
||||
}
|
||||
|
||||
QAbstractItemModel* AccountAssetsController::assetsModel() const
|
||||
|
@ -97,4 +110,4 @@ bool AccountAssetsController::assetsReady() const
|
|||
return m_assetsReady;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::Wallet
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
#include "DerivedWalletAddress.h"
|
||||
|
||||
namespace Status::Wallet {
|
||||
namespace Status::Wallet
|
||||
{
|
||||
|
||||
DerivedWalletAddress::DerivedWalletAddress(WalletGo::DerivedAddress address, QObject *parent)
|
||||
DerivedWalletAddress::DerivedWalletAddress(WalletGo::DerivedAddress address, QObject* parent)
|
||||
: QObject{parent}
|
||||
, m_derivedAddress{std::move(address)}
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
QString DerivedWalletAddress::address() const
|
||||
{
|
||||
|
@ -18,4 +18,4 @@ bool DerivedWalletAddress::alreadyCreated() const
|
|||
return m_derivedAddress.alreadyCreated;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::Wallet
|
||||
|
|
|
@ -2,17 +2,17 @@
|
|||
|
||||
#include <StatusGo/Wallet/WalletApi.h>
|
||||
|
||||
#include <StatusGo/Accounts/AccountsAPI.h>
|
||||
#include <StatusGo/Accounts/Accounts.h>
|
||||
#include <StatusGo/Accounts/AccountsAPI.h>
|
||||
#include <StatusGo/Accounts/accounts_types.h>
|
||||
#include <StatusGo/Metadata/api_response.h>
|
||||
#include <StatusGo/Utils.h>
|
||||
#include <StatusGo/Types.h>
|
||||
#include <StatusGo/Utils.h>
|
||||
|
||||
#include <Onboarding/Common/Constants.h>
|
||||
|
||||
#include <QQmlEngine>
|
||||
#include <QJSEngine>
|
||||
#include <QQmlEngine>
|
||||
|
||||
#include <ranges>
|
||||
|
||||
|
@ -21,22 +21,23 @@ namespace WalletGo = Status::StatusGo::Wallet;
|
|||
namespace UtilsSG = Status::StatusGo::Utils;
|
||||
namespace StatusGo = Status::StatusGo;
|
||||
|
||||
namespace Status::Wallet {
|
||||
namespace Status::Wallet
|
||||
{
|
||||
|
||||
NewWalletAccountController::NewWalletAccountController(std::shared_ptr<Helpers::QObjectVectorModel<WalletAccount>> accounts)
|
||||
NewWalletAccountController::NewWalletAccountController(
|
||||
std::shared_ptr<Helpers::QObjectVectorModel<WalletAccount>> accounts)
|
||||
: m_accounts(accounts)
|
||||
, m_mainAccounts(std::move(filterMainAccounts(*accounts)), "account")
|
||||
, m_derivedAddress("derivedAddress")
|
||||
, m_derivationPath(Status::Constants::General::PathWalletRoot)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
QAbstractListModel* NewWalletAccountController::mainAccountsModel()
|
||||
{
|
||||
return &m_mainAccounts;
|
||||
}
|
||||
|
||||
QAbstractItemModel *NewWalletAccountController::currentDerivedAddressModel()
|
||||
QAbstractItemModel* NewWalletAccountController::currentDerivedAddressModel()
|
||||
{
|
||||
return &m_derivedAddress;
|
||||
}
|
||||
|
@ -46,77 +47,92 @@ QString NewWalletAccountController::derivationPath() const
|
|||
return m_derivationPath.get();
|
||||
}
|
||||
|
||||
void NewWalletAccountController::setDerivationPath(const QString &newDerivationPath)
|
||||
void NewWalletAccountController::setDerivationPath(const QString& newDerivationPath)
|
||||
{
|
||||
if (m_derivationPath.get() == newDerivationPath)
|
||||
return;
|
||||
if(m_derivationPath.get() == newDerivationPath) return;
|
||||
m_derivationPath = GoAccounts::DerivationPath(newDerivationPath);
|
||||
emit derivationPathChanged();
|
||||
|
||||
auto oldCustom = m_customDerivationPath;
|
||||
const auto &[derivedPath, index]= searchDerivationPath(m_derivationPath);
|
||||
const auto& [derivedPath, index] = searchDerivationPath(m_derivationPath);
|
||||
m_customDerivationPath = derivedPath == nullptr;
|
||||
if(!m_customDerivationPath && !derivedPath.get()->alreadyCreated())
|
||||
updateSelectedDerivedAddress(index, derivedPath);
|
||||
|
||||
if(m_customDerivationPath != oldCustom)
|
||||
emit customDerivationPathChanged();
|
||||
if(m_customDerivationPath != oldCustom) emit customDerivationPathChanged();
|
||||
}
|
||||
|
||||
void NewWalletAccountController::createAccountAsync(const QString &password, const QString &name,
|
||||
const QColor &color, const QString &path,
|
||||
const WalletAccount *derivedFrom)
|
||||
void NewWalletAccountController::createAccountAsync(const QString& password,
|
||||
const QString& name,
|
||||
const QColor& color,
|
||||
const QString& path,
|
||||
const WalletAccount* derivedFrom)
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
GoAccounts::generateAccountWithDerivedPath(StatusGo::HashedPassword(UtilsSG::hashPassword(password)),
|
||||
name, color, "", GoAccounts::DerivationPath(path),
|
||||
name,
|
||||
color,
|
||||
"",
|
||||
GoAccounts::DerivationPath(path),
|
||||
derivedFrom->data().derivedFrom.value());
|
||||
|
||||
addNewlyCreatedAccount(findMissingAccount());
|
||||
}
|
||||
catch(const StatusGo::CallPrivateRpcError& e) {
|
||||
catch(const StatusGo::CallPrivateRpcError& e)
|
||||
{
|
||||
qWarning() << "StatusGoQt.generateAccountWithDerivedPath error: " << e.errorResponse().error.message.c_str();
|
||||
|
||||
emit accountCreatedStatus(false);
|
||||
}
|
||||
}
|
||||
|
||||
void NewWalletAccountController::addWatchOnlyAccountAsync(const QString &address, const QString &name, const QColor &color)
|
||||
void NewWalletAccountController::addWatchOnlyAccountAsync(const QString& address,
|
||||
const QString& name,
|
||||
const QColor& color)
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
GoAccounts::addAccountWatch(Accounts::EOAddress(address), name, color, u""_qs);
|
||||
|
||||
addNewlyCreatedAccount(findMissingAccount());
|
||||
}
|
||||
catch(const StatusGo::CallPrivateRpcError& e) {
|
||||
catch(const StatusGo::CallPrivateRpcError& e)
|
||||
{
|
||||
qWarning() << "StatusGoQt.generateAccountWithDerivedPath error: " << e.errorResponse().error.message.c_str();
|
||||
|
||||
emit accountCreatedStatus(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool NewWalletAccountController::retrieveAndUpdateDerivedAddresses(const QString &password,
|
||||
const WalletAccount *derivedFrom)
|
||||
bool NewWalletAccountController::retrieveAndUpdateDerivedAddresses(const QString& password,
|
||||
const WalletAccount* derivedFrom)
|
||||
{
|
||||
assert(derivedFrom->data().derivedFrom.has_value());
|
||||
try {
|
||||
try
|
||||
{
|
||||
int currentPage = 1;
|
||||
int foundIndex = -1;
|
||||
int currentIndex = 0;
|
||||
auto maxPageCount = static_cast<int>(std::ceil(static_cast<double>(m_maxDerivedAddresses)/static_cast<double>(m_derivedAddressesPageSize)));
|
||||
auto maxPageCount = static_cast<int>(
|
||||
std::ceil(static_cast<double>(m_maxDerivedAddresses) / static_cast<double>(m_derivedAddressesPageSize)));
|
||||
std::shared_ptr<DerivedWalletAddress> foundEntry;
|
||||
while(currentPage <= maxPageCount && foundIndex < 0) {
|
||||
while(currentPage <= maxPageCount && foundIndex < 0)
|
||||
{
|
||||
auto all = WalletGo::getDerivedAddressesForPath(StatusGo::HashedPassword(UtilsSG::hashPassword(password)),
|
||||
derivedFrom->data().derivedFrom.value(),
|
||||
Status::Constants::General::PathWalletRoot,
|
||||
m_derivedAddressesPageSize, currentPage);
|
||||
m_derivedAddressesPageSize,
|
||||
currentPage);
|
||||
if((currentIndex + all.size()) > m_derivedAddress.size())
|
||||
m_derivedAddress.resize(currentIndex + all.size());
|
||||
|
||||
for(auto newDerived : all) {
|
||||
for(auto newDerived : all)
|
||||
{
|
||||
auto newEntry = Helpers::makeSharedQObject<DerivedWalletAddress>(std::move(newDerived));
|
||||
m_derivedAddress.set(currentIndex, newEntry);
|
||||
if(foundIndex < 0 && !newEntry->data().alreadyCreated) {
|
||||
if(foundIndex < 0 && !newEntry->data().alreadyCreated)
|
||||
{
|
||||
foundIndex = currentIndex;
|
||||
foundEntry = newEntry;
|
||||
}
|
||||
|
@ -124,11 +140,12 @@ bool NewWalletAccountController::retrieveAndUpdateDerivedAddresses(const QString
|
|||
}
|
||||
currentPage++;
|
||||
}
|
||||
if(foundIndex > 0)
|
||||
updateSelectedDerivedAddress(foundIndex, foundEntry);
|
||||
if(foundIndex > 0) updateSelectedDerivedAddress(foundIndex, foundEntry);
|
||||
|
||||
return true;
|
||||
} catch(const StatusGo::CallPrivateRpcError &e) {
|
||||
}
|
||||
catch(const StatusGo::CallPrivateRpcError& e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -142,19 +159,20 @@ WalletAccountPtr NewWalletAccountController::findMissingAccount()
|
|||
{
|
||||
auto accounts = GoAccounts::getAccounts();
|
||||
// TODO: consider using a QObjectSetModel and a proxy sort model on top instead
|
||||
auto it = std::find_if(accounts.begin(), accounts.end(), [this](const auto &a) {
|
||||
return std::none_of(m_accounts->objects().begin(), m_accounts->objects().end(),
|
||||
[&a](const auto &eA) { return a.address == eA->data().address; });
|
||||
auto it = std::find_if(accounts.begin(), accounts.end(), [this](const auto& a) {
|
||||
return std::none_of(m_accounts->objects().begin(), m_accounts->objects().end(), [&a](const auto& eA) {
|
||||
return a.address == eA->data().address;
|
||||
});
|
||||
});
|
||||
return it != accounts.end() ? Helpers::makeSharedQObject<WalletAccount>(*it) : nullptr;
|
||||
}
|
||||
|
||||
NewWalletAccountController::AccountsModel::ObjectContainer
|
||||
NewWalletAccountController::filterMainAccounts(const AccountsModel &accounts)
|
||||
NewWalletAccountController::filterMainAccounts(const AccountsModel& accounts)
|
||||
{
|
||||
AccountsModel::ObjectContainer out;
|
||||
const auto &c = accounts.objects();
|
||||
std::copy_if(c.begin(), c.end(), std::back_inserter(out), [](const auto &a){ return a->data().isWallet; });
|
||||
const auto& c = accounts.objects();
|
||||
std::copy_if(c.begin(), c.end(), std::back_inserter(out), [](const auto& a) { return a->data().isWallet; });
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -168,36 +186,41 @@ void NewWalletAccountController::addNewlyCreatedAccount(WalletAccountPtr newAcco
|
|||
emit accountCreatedStatus(newAccount != nullptr);
|
||||
}
|
||||
|
||||
DerivedWalletAddress *NewWalletAccountController::selectedDerivedAddress() const
|
||||
DerivedWalletAddress* NewWalletAccountController::selectedDerivedAddress() const
|
||||
{
|
||||
return m_selectedDerivedAddress.get();
|
||||
}
|
||||
|
||||
void NewWalletAccountController::setSelectedDerivedAddress(DerivedWalletAddress *newSelectedDerivedAddress)
|
||||
void NewWalletAccountController::setSelectedDerivedAddress(DerivedWalletAddress* newSelectedDerivedAddress)
|
||||
{
|
||||
if (m_selectedDerivedAddress.get() == newSelectedDerivedAddress)
|
||||
return;
|
||||
auto &objs = m_derivedAddress.objects();
|
||||
auto foundIt = std::find_if(objs.begin(), objs.end(), [newSelectedDerivedAddress](const auto &a) { return a.get() == newSelectedDerivedAddress; });
|
||||
if(m_selectedDerivedAddress.get() == newSelectedDerivedAddress) return;
|
||||
auto& objs = m_derivedAddress.objects();
|
||||
auto foundIt = std::find_if(objs.begin(), objs.end(), [newSelectedDerivedAddress](const auto& a) {
|
||||
return a.get() == newSelectedDerivedAddress;
|
||||
});
|
||||
updateSelectedDerivedAddress(std::distance(objs.begin(), foundIt), *foundIt);
|
||||
}
|
||||
|
||||
void NewWalletAccountController::updateSelectedDerivedAddress(int index, std::shared_ptr<DerivedWalletAddress> newEntry) {
|
||||
void NewWalletAccountController::updateSelectedDerivedAddress(int index, std::shared_ptr<DerivedWalletAddress> newEntry)
|
||||
{
|
||||
m_derivedAddressIndex = index;
|
||||
m_selectedDerivedAddress = newEntry;
|
||||
emit selectedDerivedAddressChanged();
|
||||
if(m_derivationPath != newEntry->data().path) {
|
||||
if(m_derivationPath != newEntry->data().path)
|
||||
{
|
||||
m_derivationPath = newEntry->data().path;
|
||||
emit derivationPathChanged();
|
||||
}
|
||||
}
|
||||
|
||||
std::tuple<DerivedWalletAddressPtr, int> NewWalletAccountController::searchDerivationPath(const GoAccounts::DerivationPath &derivationPath) {
|
||||
const auto &c = m_derivedAddress.objects();
|
||||
auto foundIt = find_if(c.begin(), c.end(), [&derivationPath](const auto &a) { return a->data().path == derivationPath; });
|
||||
if(foundIt != c.end())
|
||||
return {*foundIt, std::distance(c.begin(), foundIt)};
|
||||
std::tuple<DerivedWalletAddressPtr, int>
|
||||
NewWalletAccountController::searchDerivationPath(const GoAccounts::DerivationPath& derivationPath)
|
||||
{
|
||||
const auto& c = m_derivedAddress.objects();
|
||||
auto foundIt =
|
||||
find_if(c.begin(), c.end(), [&derivationPath](const auto& a) { return a->data().path == derivationPath; });
|
||||
if(foundIt != c.end()) return {*foundIt, std::distance(c.begin(), foundIt)};
|
||||
return {nullptr, -1};
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::Wallet
|
||||
|
|
|
@ -3,12 +3,11 @@
|
|||
namespace Status::Wallet
|
||||
{
|
||||
|
||||
SavedAddress::SavedAddress(const QString &address, const QString &name, QObject *parent)
|
||||
SavedAddress::SavedAddress(const QString& address, const QString& name, QObject* parent)
|
||||
: QObject(parent)
|
||||
, m_address(address)
|
||||
, m_name(name)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
const QString& SavedAddress::address() const
|
||||
{
|
||||
|
@ -20,4 +19,4 @@ const QString& SavedAddress::name() const
|
|||
return m_name;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Status::Wallet
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue