chore(cpp): apply clang-format

This commit is contained in:
Patryk Osmaczko 2022-10-19 15:41:53 +02:00 committed by osmaczko
parent 1dcc3a1f2f
commit c53264b124
104 changed files with 1736 additions and 1511 deletions

View File

@ -2,14 +2,13 @@
#include <QtQml/QQmlEngine> #include <QtQml/QQmlEngine>
namespace Status::Application { namespace Status::Application
ApplicationController::ApplicationController(QObject *parent)
: QObject{parent}
, m_dataProvider(std::make_unique<DataProvider>())
{ {
} ApplicationController::ApplicationController(QObject* parent)
: QObject{parent}
, m_dataProvider(std::make_unique<DataProvider>())
{ }
void ApplicationController::initOnLogin() void ApplicationController::initOnLogin()
{ {
@ -17,23 +16,22 @@ void ApplicationController::initOnLogin()
m_dbSettings = std::make_shared<DbSettingsObj>(dbSettings); m_dbSettings = std::make_shared<DbSettingsObj>(dbSettings);
} }
QObject *ApplicationController::dbSettings() const QObject* ApplicationController::dbSettings() const
{ {
return m_dbSettings.get(); return m_dbSettings.get();
} }
QObject *ApplicationController::statusAccount() const QObject* ApplicationController::statusAccount() const
{ {
QQmlEngine::setObjectOwnership(m_statusAccount, QQmlEngine::CppOwnership); QQmlEngine::setObjectOwnership(m_statusAccount, QQmlEngine::CppOwnership);
return m_statusAccount; return m_statusAccount;
} }
void ApplicationController::setStatusAccount(QObject *newStatusAccount) void ApplicationController::setStatusAccount(QObject* newStatusAccount)
{ {
if (m_statusAccount == newStatusAccount) if(m_statusAccount == newStatusAccount) return;
return;
m_statusAccount = newStatusAccount; m_statusAccount = newStatusAccount;
emit statusAccountChanged(); emit statusAccountChanged();
} }
} } // namespace Status::Application

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "DbSettingsObj.h"
#include "DataProvider.h" #include "DataProvider.h"
#include "DbSettingsObj.h"
#include <QObject> #include <QObject>
#include <QtQml/qqmlregistration.h> #include <QtQml/qqmlregistration.h>
@ -9,7 +9,8 @@
// TODO: investigate. This line breaks qobject_cast in OnboardingController::login // TODO: investigate. This line breaks qobject_cast in OnboardingController::login
//#include <Onboarding/UserAccount.h> //#include <Onboarding/UserAccount.h>
namespace Status::Application { namespace Status::Application
{
/** /**
* @brief Responsible for providing general information and utility components * @brief Responsible for providing general information and utility components
@ -23,12 +24,12 @@ class ApplicationController : public QObject
Q_PROPERTY(QObject* dbSettings READ dbSettings CONSTANT) Q_PROPERTY(QObject* dbSettings READ dbSettings CONSTANT)
public: public:
explicit ApplicationController(QObject *parent = nullptr); explicit ApplicationController(QObject* parent = nullptr);
Q_INVOKABLE void initOnLogin(); Q_INVOKABLE void initOnLogin();
QObject *statusAccount() const; QObject* statusAccount() const;
void setStatusAccount(QObject *newStatusAccount); void setStatusAccount(QObject* newStatusAccount);
QObject* dbSettings() const; QObject* dbSettings() const;
@ -41,4 +42,4 @@ private:
std::shared_ptr<DbSettingsObj> m_dbSettings; std::shared_ptr<DbSettingsObj> m_dbSettings;
}; };
} } // namespace Status::Application

View File

@ -6,18 +6,20 @@ namespace StatusGo = Status::StatusGo;
DataProvider::DataProvider() DataProvider::DataProvider()
: QObject(nullptr) : QObject(nullptr)
{ { }
}
StatusGo::Settings::SettingsDto DataProvider::getSettings() const StatusGo::Settings::SettingsDto DataProvider::getSettings() const
{ {
try { try
{
return StatusGo::Settings::getSettings(); return StatusGo::Settings::getSettings();
} }
catch (std::exception& e) { catch(std::exception& e)
{
qWarning() << "DataProvider::getSettings, error: " << e.what(); qWarning() << "DataProvider::getSettings, error: " << e.what();
} }
catch (...) { catch(...)
{
qWarning() << "DataProvider::getSettings, unknown error"; qWarning() << "DataProvider::getSettings, unknown error";
} }
return StatusGo::Settings::SettingsDto{}; return StatusGo::Settings::SettingsDto{};

View File

@ -1,17 +1,18 @@
#pragma once #pragma once
#include <StatusGo/SettingsAPI>
#include <QtCore/QtCore> #include <QtCore/QtCore>
#include <StatusGo/SettingsAPI>
namespace Status::Application { namespace Status::Application
{
class DataProvider: public QObject class DataProvider : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
DataProvider(); DataProvider();
StatusGo::Settings::SettingsDto getSettings() const; StatusGo::Settings::SettingsDto getSettings() const;
}; };
} } // namespace Status::Application

View File

@ -5,8 +5,7 @@ using namespace Status::Application;
DbSettingsObj::DbSettingsObj(StatusGo::Settings::SettingsDto rawData) DbSettingsObj::DbSettingsObj(StatusGo::Settings::SettingsDto rawData)
: QObject(nullptr) : QObject(nullptr)
, m_data(std::move(rawData)) , m_data(std::move(rawData))
{ { }
}
QString DbSettingsObj::address() const QString DbSettingsObj::address() const
{ {
@ -15,8 +14,7 @@ QString DbSettingsObj::address() const
void DbSettingsObj::setAddress(const QString& value) void DbSettingsObj::setAddress(const QString& value)
{ {
if (m_data.address == value) if(m_data.address == value) return;
return;
m_data.address = value; m_data.address = value;
emit addressChanged(); emit addressChanged();
} }
@ -28,8 +26,7 @@ QString DbSettingsObj::displayName() const
void DbSettingsObj::setDisplayName(const QString& value) void DbSettingsObj::setDisplayName(const QString& value)
{ {
if (m_data.displayName == value) if(m_data.displayName == value) return;
return;
m_data.displayName = value; m_data.displayName = value;
emit displayNameChanged(); emit displayNameChanged();
} }
@ -41,8 +38,7 @@ QString DbSettingsObj::preferredName() const
void DbSettingsObj::setPreferredName(const QString& value) void DbSettingsObj::setPreferredName(const QString& value)
{ {
if (m_data.preferredName == value) if(m_data.preferredName == value) return;
return;
m_data.preferredName = value; m_data.preferredName = value;
emit preferredNameChanged(); emit preferredNameChanged();
} }
@ -54,8 +50,7 @@ QString DbSettingsObj::keyUid() const
void DbSettingsObj::setKeyUid(const QString& value) void DbSettingsObj::setKeyUid(const QString& value)
{ {
if (m_data.keyUid == value) if(m_data.keyUid == value) return;
return;
m_data.keyUid = value; m_data.keyUid = value;
emit keyUidChanged(); emit keyUidChanged();
} }
@ -67,8 +62,7 @@ QString DbSettingsObj::publicKey() const
void DbSettingsObj::setPublicKey(const QString& value) void DbSettingsObj::setPublicKey(const QString& value)
{ {
if (m_data.publicKey == value) if(m_data.publicKey == value) return;
return;
m_data.publicKey = value; m_data.publicKey = value;
emit publicKeyChanged(); emit publicKeyChanged();
} }

View File

@ -4,46 +4,45 @@
#include <QtCore/QtCore> #include <QtCore/QtCore>
namespace Status::Application { namespace Status::Application
{
class DbSettingsObj: public QObject class DbSettingsObj : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString address READ address NOTIFY addressChanged) Q_PROPERTY(QString address READ address NOTIFY addressChanged)
Q_PROPERTY(QString displayName READ displayName NOTIFY displayNameChanged) Q_PROPERTY(QString displayName READ displayName NOTIFY displayNameChanged)
Q_PROPERTY(QString preferredName READ preferredName NOTIFY preferredNameChanged) Q_PROPERTY(QString preferredName READ preferredName NOTIFY preferredNameChanged)
Q_PROPERTY(QString keyUid READ keyUid NOTIFY keyUidChanged) Q_PROPERTY(QString keyUid READ keyUid NOTIFY keyUidChanged)
Q_PROPERTY(QString publicKey READ publicKey NOTIFY publicKeyChanged) Q_PROPERTY(QString publicKey READ publicKey NOTIFY publicKeyChanged)
public:
explicit DbSettingsObj(StatusGo::Settings::SettingsDto rawData);
public: [[nodiscard]] QString address() const;
explicit DbSettingsObj(StatusGo::Settings::SettingsDto rawData); void setAddress(const QString& address);
[[nodiscard]] QString address() const; [[nodiscard]] QString displayName() const;
void setAddress(const QString& address); void setDisplayName(const QString& value);
[[nodiscard]] QString displayName() const; [[nodiscard]] QString preferredName() const;
void setDisplayName(const QString& value); void setPreferredName(const QString& value);
[[nodiscard]] QString preferredName() const; [[nodiscard]] QString keyUid() const;
void setPreferredName(const QString& value); void setKeyUid(const QString& value);
[[nodiscard]] QString keyUid() const; [[nodiscard]] QString publicKey() const;
void setKeyUid(const QString& value); void setPublicKey(const QString& value);
[[nodiscard]] QString publicKey() const; signals:
void setPublicKey(const QString& value); void addressChanged();
void displayNameChanged();
void preferredNameChanged();
void keyUidChanged();
void publicKeyChanged();
private:
signals: StatusGo::Settings::SettingsDto m_data;
void addressChanged(); };
void displayNameChanged(); } // namespace Status::Application
void preferredNameChanged();
void keyUidChanged();
void publicKeyChanged();
private:
StatusGo::Settings::SettingsDto m_data;
};
}

View File

@ -7,14 +7,14 @@
#include <Helpers/helpers.h> #include <Helpers/helpers.h>
#include <Helpers/logs.h> #include <Helpers/logs.h>
#include <QDir>
#include <QDebug> #include <QDebug>
#include <QDir>
using namespace Status; using namespace Status;
void setApplicationInformation(QGuiApplication& app); void setApplicationInformation(QGuiApplication& app);
int main(int argc, char *argv[]) int main(int argc, char* argv[])
{ {
//qInstallMessageHandler(Helpers::logFormatter); //qInstallMessageHandler(Helpers::logFormatter);
@ -24,9 +24,11 @@ int main(int argc, char *argv[])
QTranslator translator; QTranslator translator;
const QStringList uiLanguages = QLocale::system().uiLanguages(); 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(); const QString baseName = BUILD_PROJECT_NAME + QLocale(locale).name();
if (translator.load(":/i18n/" + baseName)) { if(translator.load(":/i18n/" + baseName))
{
app.installTranslator(&translator); app.installTranslator(&translator);
break; break;
} }
@ -35,27 +37,31 @@ int main(int argc, char *argv[])
QQmlApplicationEngine engine; QQmlApplicationEngine engine;
const QUrl url(u"qrc:/Status/Application/qml/main.qml"_qs); const QUrl url(u"qrc:/Status/Application/qml/main.qml"_qs);
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, QObject::connect(
&app, [url](QObject *obj, const QUrl &objUrl) { &engine,
if (!obj && url == objUrl) &QQmlApplicationEngine::objectCreated,
QCoreApplication::exit(-1); &app,
}, Qt::QueuedConnection); [url](QObject* obj, const QUrl& objUrl) {
if(!obj && url == objUrl) QCoreApplication::exit(-1);
},
Qt::QueuedConnection);
engine.load(url); engine.load(url);
return app.exec(); return app.exec();
} }
void setApplicationInformation(QGuiApplication& app) { void setApplicationInformation(QGuiApplication& app)
{
#if !defined BUILD_PROJECT_ORGANIZATION_NAME #if !defined BUILD_PROJECT_ORGANIZATION_NAME
static_assert(false, "Compile-time define missing: BUILD_PROJECT_ORGANIZATION_NAME") static_assert(false, "Compile-time define missing: BUILD_PROJECT_ORGANIZATION_NAME")
#endif #endif
app.setOrganizationName(BUILD_PROJECT_ORGANIZATION_NAME); app.setOrganizationName(BUILD_PROJECT_ORGANIZATION_NAME);
#if !defined BUILD_PROJECT_ORGANIZATION_DOMAIN #if !defined BUILD_PROJECT_ORGANIZATION_DOMAIN
static_assert(false, "Compile-time define missing: BUILD_PROJECT_ORGANIZATION_DOMAIN") static_assert(false, "Compile-time define missing: BUILD_PROJECT_ORGANIZATION_DOMAIN")
#endif #endif
app.setOrganizationDomain(BUILD_PROJECT_ORGANIZATION_DOMAIN); app.setOrganizationDomain(BUILD_PROJECT_ORGANIZATION_DOMAIN);
#if !defined BUILD_PROJECT_APPLICATION_NAME #if !defined BUILD_PROJECT_APPLICATION_NAME
static_assert(false, "Compile-time define missing: BUILD_PROJECT_APPLICATION_NAME") static_assert(false, "Compile-time define missing: BUILD_PROJECT_APPLICATION_NAME")
#endif #endif
app.setApplicationName(BUILD_PROJECT_APPLICATION_NAME); app.setApplicationName(BUILD_PROJECT_APPLICATION_NAME);
} }

View File

@ -8,14 +8,16 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace Status::ApplicationCore { namespace Status::ApplicationCore
{
namespace { namespace
constexpr auto statusFolder = "Status"; {
constexpr auto dataSubfolder = "data"; constexpr auto statusFolder = "Status";
} constexpr auto dataSubfolder = "data";
} // namespace
UserConfiguration::UserConfiguration(QObject *parent) UserConfiguration::UserConfiguration(QObject* parent)
: QObject{parent} : QObject{parent}
{ {
generateReleaseConfiguration(); generateReleaseConfiguration();
@ -26,16 +28,15 @@ const QString UserConfiguration::qmlUserDataFolder() const
return toQString(m_userDataFolder.string()); return toQString(m_userDataFolder.string());
} }
const fs::path &UserConfiguration::userDataFolder() const const fs::path& UserConfiguration::userDataFolder() const
{ {
return m_userDataFolder; return m_userDataFolder;
} }
void UserConfiguration::setUserDataFolder(const QString &newUserDataFolder) void UserConfiguration::setUserDataFolder(const QString& newUserDataFolder)
{ {
auto newVal = Status::toPath(newUserDataFolder); auto newVal = Status::toPath(newUserDataFolder);
if (m_userDataFolder.compare(newVal) == 0) if(m_userDataFolder.compare(newVal) == 0) return;
return;
m_userDataFolder = newVal; m_userDataFolder = newVal;
emit userDataFolderChanged(); emit userDataFolderChanged();
} }
@ -43,7 +44,8 @@ void UserConfiguration::setUserDataFolder(const QString &newUserDataFolder)
void UserConfiguration::generateReleaseConfiguration() void UserConfiguration::generateReleaseConfiguration()
{ {
if(!parseFromCommandLineAndReturnTrueIfSet()) if(!parseFromCommandLineAndReturnTrueIfSet())
m_userDataFolder = toPath(QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation))/statusFolder/dataSubfolder; m_userDataFolder =
toPath(QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation)) / statusFolder / dataSubfolder;
emit userDataFolderChanged(); emit userDataFolderChanged();
} }
@ -55,7 +57,8 @@ bool UserConfiguration::parseFromCommandLineAndReturnTrueIfSet()
parser.addPositionalArgument("dataDir", "Data folder"); parser.addPositionalArgument("dataDir", "Data folder");
parser.process(*QCoreApplication::instance()); parser.process(*QCoreApplication::instance());
auto args = parser.positionalArguments(); auto args = parser.positionalArguments();
if (args.size() > 0) { if(args.size() > 0)
{
m_userDataFolder = toPath(args[0]); m_userDataFolder = toPath(args[0]);
emit userDataFolderChanged(); emit userDataFolderChanged();
return true; return true;
@ -63,4 +66,4 @@ bool UserConfiguration::parseFromCommandLineAndReturnTrueIfSet()
return false; return false;
} }
} } // namespace Status::ApplicationCore

View File

@ -5,12 +5,13 @@
#include <filesystem> #include <filesystem>
namespace Status::ApplicationCore { namespace Status::ApplicationCore
{
namespace fs = std::filesystem; namespace fs = std::filesystem;
/// Contains necessary data for each created account hence this will be the same path for all accounts /// 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 Q_OBJECT
QML_ELEMENT QML_ELEMENT
@ -19,11 +20,11 @@ class UserConfiguration: public QObject
Q_PROPERTY(QString userDataFolder READ qmlUserDataFolder WRITE setUserDataFolder NOTIFY userDataFolderChanged) Q_PROPERTY(QString userDataFolder READ qmlUserDataFolder WRITE setUserDataFolder NOTIFY userDataFolderChanged)
public: public:
explicit UserConfiguration(QObject *parent = nullptr); explicit UserConfiguration(QObject* parent = nullptr);
const QString qmlUserDataFolder() const; const QString qmlUserDataFolder() const;
const fs::path &userDataFolder() const; const fs::path& userDataFolder() const;
void setUserDataFolder(const QString &newUserDataFolder); void setUserDataFolder(const QString& newUserDataFolder);
signals: signals:
void userDataFolderChanged(); void userDataFolderChanged();
@ -35,4 +36,4 @@ private:
fs::path m_userDataFolder; fs::path m_userDataFolder;
}; };
} } // namespace Status::ApplicationCore

View File

@ -1,17 +1,18 @@
#pragma once #pragma once
#include <StatusGo/ChatAPI>
#include <QtCore/QtCore> #include <QtCore/QtCore>
#include <StatusGo/ChatAPI>
namespace Status::ChatSection { namespace Status::ChatSection
{
class ChatDataProvider: public QObject class ChatDataProvider : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
ChatDataProvider(); ChatDataProvider();
StatusGo::Chats::ChannelGroupDto getSectionData(const QString& sectionId) const; StatusGo::Chats::ChannelGroupDto getSectionData(const QString& sectionId) const;
}; };
} } // namespace Status::ChatSection

View File

@ -4,49 +4,50 @@
#include <QtCore/QtCore> #include <QtCore/QtCore>
namespace Status::ChatSection { namespace Status::ChatSection
{
class ChatItem: public QObject class ChatItem : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString id READ id CONSTANT) Q_PROPERTY(QString id READ id CONSTANT)
Q_PROPERTY(QString name READ name NOTIFY nameChanged) Q_PROPERTY(QString name READ name NOTIFY nameChanged)
Q_PROPERTY(QString description READ description NOTIFY descriptionChanged) Q_PROPERTY(QString description READ description NOTIFY descriptionChanged)
Q_PROPERTY(QColor color READ color NOTIFY colorChanged) Q_PROPERTY(QColor color READ color NOTIFY colorChanged)
Q_PROPERTY(bool muted READ muted NOTIFY mutedChanged) Q_PROPERTY(bool muted READ muted NOTIFY mutedChanged)
Q_PROPERTY(bool active READ active NOTIFY activeChanged) Q_PROPERTY(bool active READ active NOTIFY activeChanged)
public: public:
explicit ChatItem(StatusGo::Chats::ChatDto rawData); explicit ChatItem(StatusGo::Chats::ChatDto rawData);
[[nodiscard]] QString id() const; [[nodiscard]] QString id() const;
[[nodiscard]] QString name() const; [[nodiscard]] QString name() const;
void setName(const QString& value); void setName(const QString& value);
[[nodiscard]] QString description() const; [[nodiscard]] QString description() const;
void setDescription(const QString& value); void setDescription(const QString& value);
[[nodiscard]] QColor color() const; [[nodiscard]] QColor color() const;
void setColor(const QColor& value); void setColor(const QColor& value);
[[nodiscard]] bool muted() const; [[nodiscard]] bool muted() const;
void setMuted(bool value); void setMuted(bool value);
[[nodiscard]] bool active() const; [[nodiscard]] bool active() const;
void setActive(bool value); void setActive(bool value);
signals: signals:
void nameChanged(); void nameChanged();
void descriptionChanged(); void descriptionChanged();
void colorChanged(); void colorChanged();
void mutedChanged(); void mutedChanged();
void activeChanged(); void activeChanged();
private: private:
StatusGo::Chats::ChatDto m_data; StatusGo::Chats::ChatDto m_data;
}; };
using ChatItemPtr = std::shared_ptr<ChatItem>; using ChatItemPtr = std::shared_ptr<ChatItem>;
} } // namespace Status::ChatSection

View File

@ -1,37 +1,38 @@
#pragma once #pragma once
#include "ChatItem.h"
#include "ChatDataProvider.h" #include "ChatDataProvider.h"
#include "ChatItem.h"
#include <Helpers/QObjectVectorModel.h> #include <Helpers/QObjectVectorModel.h>
namespace Status::ChatSection { namespace Status::ChatSection
{
class ChatSectionController: public QObject class ChatSectionController : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
Q_PROPERTY(QAbstractListModel* chatsModel READ chatsModel NOTIFY chatsModelChanged) Q_PROPERTY(QAbstractListModel* chatsModel READ chatsModel NOTIFY chatsModelChanged)
Q_PROPERTY(ChatItem* currentChat READ currentChat NOTIFY currentChatChanged) Q_PROPERTY(ChatItem* currentChat READ currentChat NOTIFY currentChatChanged)
public: public:
ChatSectionController(); ChatSectionController();
QAbstractListModel* chatsModel() const; QAbstractListModel* chatsModel() const;
ChatItem* currentChat() const; ChatItem* currentChat() const;
Q_INVOKABLE void init(const QString& sectionId); Q_INVOKABLE void init(const QString& sectionId);
Q_INVOKABLE void setCurrentChatIndex(int index); Q_INVOKABLE void setCurrentChatIndex(int index);
signals: signals:
void chatsModelChanged(); void chatsModelChanged();
void currentChatChanged(); void currentChatChanged();
private: private:
using ChatsModel = Helpers::QObjectVectorModel<ChatItem>; using ChatsModel = Helpers::QObjectVectorModel<ChatItem>;
std::shared_ptr<ChatsModel> m_chats; std::shared_ptr<ChatsModel> m_chats;
std::unique_ptr<ChatDataProvider> m_dataProvider; std::unique_ptr<ChatDataProvider> m_dataProvider;
ChatItemPtr m_currentChat; ChatItemPtr m_currentChat;
}; };
} } // namespace Status::ChatSection

View File

@ -6,22 +6,24 @@ namespace StatusGo = Status::StatusGo;
ChatDataProvider::ChatDataProvider() ChatDataProvider::ChatDataProvider()
: QObject(nullptr) : QObject(nullptr)
{ { }
}
StatusGo::Chats::ChannelGroupDto ChatDataProvider::getSectionData(const QString& sectionId) const StatusGo::Chats::ChannelGroupDto ChatDataProvider::getSectionData(const QString& sectionId) const
{ {
try { try
{
auto result = StatusGo::Chats::getChats(); auto result = StatusGo::Chats::getChats();
for(auto chGroup : result.allChannelGroups) { for(auto chGroup : result.allChannelGroups)
if (chGroup.id == sectionId) {
return chGroup; if(chGroup.id == sectionId) return chGroup;
} }
} }
catch (std::exception& e) { catch(std::exception& e)
{
qWarning() << "ChatDataProvider::getSectionData, error: " << e.what(); qWarning() << "ChatDataProvider::getSectionData, error: " << e.what();
} }
catch (...) { catch(...)
{
qWarning() << "ChatDataProvider::getSectionData, unknown error"; qWarning() << "ChatDataProvider::getSectionData, unknown error";
} }
return StatusGo::Chats::ChannelGroupDto{}; return StatusGo::Chats::ChannelGroupDto{};

View File

@ -5,8 +5,7 @@ using namespace Status::ChatSection;
ChatItem::ChatItem(StatusGo::Chats::ChatDto rawData) ChatItem::ChatItem(StatusGo::Chats::ChatDto rawData)
: QObject(nullptr) : QObject(nullptr)
, m_data(std::move(rawData)) , m_data(std::move(rawData))
{ { }
}
QString ChatItem::id() const QString ChatItem::id() const
{ {
@ -20,8 +19,7 @@ QString ChatItem::name() const
void ChatItem::setName(const QString& value) void ChatItem::setName(const QString& value)
{ {
if (m_data.name == value) if(m_data.name == value) return;
return;
m_data.name = value; m_data.name = value;
emit nameChanged(); emit nameChanged();
} }
@ -33,8 +31,7 @@ QString ChatItem::description() const
void ChatItem::setDescription(const QString& value) void ChatItem::setDescription(const QString& value)
{ {
if (m_data.description == value) if(m_data.description == value) return;
return;
m_data.description = value; m_data.description = value;
emit descriptionChanged(); emit descriptionChanged();
} }
@ -46,8 +43,7 @@ QColor ChatItem::color() const
void ChatItem::setColor(const QColor& value) void ChatItem::setColor(const QColor& value)
{ {
if (m_data.color == value) if(m_data.color == value) return;
return;
m_data.color = value; m_data.color = value;
emit colorChanged(); emit colorChanged();
} }
@ -59,8 +55,7 @@ bool ChatItem::muted() const
void ChatItem::setMuted(bool value) void ChatItem::setMuted(bool value)
{ {
if (m_data.muted == value) if(m_data.muted == value) return;
return;
m_data.muted = value; m_data.muted = value;
emit mutedChanged(); emit mutedChanged();
} }
@ -72,8 +67,7 @@ bool ChatItem::active() const
void ChatItem::setActive(bool value) void ChatItem::setActive(bool value)
{ {
if (m_data.active == value) if(m_data.active == value) return;
return;
m_data.active = value; m_data.active = value;
emit activeChanged(); emit activeChanged();
} }

View File

@ -5,15 +5,15 @@ using namespace Status::ChatSection;
ChatSectionController::ChatSectionController() ChatSectionController::ChatSectionController()
: QObject(nullptr) : QObject(nullptr)
, m_dataProvider(std::make_unique<ChatDataProvider>()) , m_dataProvider(std::make_unique<ChatDataProvider>())
{ { }
}
void ChatSectionController::init(const QString& sectionId) void ChatSectionController::init(const QString& sectionId)
{ {
auto chatSectionData = m_dataProvider->getSectionData(sectionId); auto chatSectionData = m_dataProvider->getSectionData(sectionId);
assert(chatSectionData.chats.size() > 0); assert(chatSectionData.chats.size() > 0);
std::vector<ChatItemPtr> model; std::vector<ChatItemPtr> model;
for (auto c : chatSectionData.chats) { for(auto c : chatSectionData.chats)
{
model.push_back(std::make_shared<ChatItem>(std::move(c))); model.push_back(std::make_shared<ChatItem>(std::move(c)));
} }
m_chats = std::make_shared<ChatsModel>(std::move(model), "chat"); m_chats = std::make_shared<ChatsModel>(std::move(model), "chat");
@ -34,8 +34,7 @@ ChatItem* ChatSectionController::currentChat() const
void ChatSectionController::setCurrentChatIndex(int index) void ChatSectionController::setCurrentChatIndex(int index)
{ {
auto chat = index >= 0 && index < m_chats->size() ? m_chats->get(index) : ChatItemPtr(); auto chat = index >= 0 && index < m_chats->size() ? m_chats->get(index) : ChatItemPtr();
if (m_currentChat == chat) if(m_currentChat == chat) return;
return;
m_currentChat = chat; m_currentChat = chat;
emit currentChatChanged(); emit currentChatChanged();

View File

@ -2,17 +2,16 @@
#include "Macros.h" #include "Macros.h"
#define STATUS_READ_NLOHMAN_JSON_PROPERTY_3_ARGS(FIELD, NAME, REQUIRED) \ #define STATUS_READ_NLOHMAN_JSON_PROPERTY_3_ARGS(FIELD, NAME, REQUIRED) \
if(REQUIRED) \ if(REQUIRED) \
j.at(NAME).get_to(d.FIELD); \ j.at(NAME).get_to(d.FIELD); \
else if(j.contains(NAME)) \ else if(j.contains(NAME)) \
j.at(NAME).get_to(d.FIELD); \ j.at(NAME).get_to(d.FIELD);
#define STATUS_READ_NLOHMAN_JSON_PROPERTY_2_ARGS(FIELD, NAME) \ #define STATUS_READ_NLOHMAN_JSON_PROPERTY_2_ARGS(FIELD, NAME) \
STATUS_READ_NLOHMAN_JSON_PROPERTY_3_ARGS(FIELD, NAME, true) STATUS_READ_NLOHMAN_JSON_PROPERTY_3_ARGS(FIELD, NAME, true)
#define STATUS_READ_NLOHMAN_JSON_PROPERTY_1_ARGS(FIELD) \ #define STATUS_READ_NLOHMAN_JSON_PROPERTY_1_ARGS(FIELD) STATUS_READ_NLOHMAN_JSON_PROPERTY_2_ARGS(FIELD, #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 // 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`. // 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")
// STATUS_READ_NLOHMAN_JSON_PROPERTY(field, "realFieldName", false) // STATUS_READ_NLOHMAN_JSON_PROPERTY(field, "realFieldName", false)
// //
#define STATUS_READ_NLOHMAN_JSON_PROPERTY(...) \ #define STATUS_READ_NLOHMAN_JSON_PROPERTY(...) \
STATUS_EXPAND( \ STATUS_EXPAND(STATUS_MACRO_SELECTOR_3_ARGS(__VA_ARGS__, \
STATUS_MACRO_SELECTOR_3_ARGS( \ STATUS_READ_NLOHMAN_JSON_PROPERTY_3_ARGS, \
__VA_ARGS__, \ STATUS_READ_NLOHMAN_JSON_PROPERTY_2_ARGS, \
STATUS_READ_NLOHMAN_JSON_PROPERTY_3_ARGS, \ STATUS_READ_NLOHMAN_JSON_PROPERTY_1_ARGS)(__VA_ARGS__))
STATUS_READ_NLOHMAN_JSON_PROPERTY_2_ARGS, \
STATUS_READ_NLOHMAN_JSON_PROPERTY_1_ARGS \
)(__VA_ARGS__) \
)

View File

@ -4,9 +4,7 @@
#define STATUS_EXPAND(x) x #define STATUS_EXPAND(x) x
// 2 arguments macro selector. // 2 arguments macro selector.
#define STATUS_MACRO_SELECTOR_2_ARGS(_1, _2, selected, ...) \ #define STATUS_MACRO_SELECTOR_2_ARGS(_1, _2, selected, ...) selected
selected
// 3 arguments macro selector. // 3 arguments macro selector.
#define STATUS_MACRO_SELECTOR_3_ARGS(_1, _2, _3, selected, ...) \ #define STATUS_MACRO_SELECTOR_3_ARGS(_1, _2, _3, selected, ...) selected
selected

View File

@ -7,9 +7,10 @@
using json = nlohmann::json; 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; 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 /// Featureless version of https://github.com/joboccara/NamedType that works with nlohmann::json
@ -19,27 +20,52 @@ class NamedType
public: public:
using UnderlyingType = T; using UnderlyingType = T;
explicit constexpr NamedType(T const& value) : m_value(value) {} explicit constexpr NamedType(T const& value)
template<typename T_ = T, typename = IsNotReference<T_>> : m_value(value)
explicit constexpr NamedType(T&& value) : m_value(std::move(value)) {} { }
template <typename T_ = T, typename = IsNotReference<T_>>
explicit constexpr NamedType(T&& value)
: m_value(std::move(value))
{ }
explicit constexpr NamedType() = default; explicit constexpr NamedType() = default;
constexpr T& get() { constexpr T& get()
{
return m_value; return m_value;
} }
constexpr std::remove_reference_t<T> const& get() const { constexpr std::remove_reference_t<T> const& get() const
{
return m_value; 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
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; }; 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
bool operator!=(const NamedType<T, Parameter> &other) const { return m_value != other.m_value; }; {
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; return m_value = rhs.m_value;
}; };
@ -48,16 +74,18 @@ private:
}; };
template <typename T, typename P> 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(); j = p.get();
} }
template <typename T, typename P> 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>()}; p = NamedType<T, P>{j.get<T>()};
} }
} } // namespace Status::Helpers
namespace std namespace std
{ {

View File

@ -2,96 +2,110 @@
#include <QAbstractListModel> #include <QAbstractListModel>
#include <QQmlEngine> #include <QQmlEngine>
namespace Status::Helpers { namespace Status::Helpers
{
/// Generic typed QObject provider model /// Generic typed QObject provider model
/// ///
/// Supports: source model update /// Supports: source model update
/// \todo rename it to SharedQObjectVectorModel /// \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 /// \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 class QObjectVectorModel final : public QAbstractListModel
{ {
static_assert(std::is_base_of<QObject, T>::value, "Template parameter (T) not a QObject"); static_assert(std::is_base_of<QObject, T>::value, "Template parameter (T) not a QObject");
public: public:
using ObjectContainer = std::vector<std::shared_ptr<T>>; using ObjectContainer = std::vector<std::shared_ptr<T>>;
explicit QObjectVectorModel(ObjectContainer initialObjects, const char* objectRoleName, QObject* parent = nullptr) explicit QObjectVectorModel(ObjectContainer initialObjects, const char* objectRoleName, QObject* parent = nullptr)
: QAbstractListModel(parent) : QAbstractListModel(parent)
, m_objects(std::move(initialObjects)) , m_objects(std::move(initialObjects))
, m_roleName(objectRoleName) , m_roleName(objectRoleName)
{ { }
}
explicit QObjectVectorModel(const char* objectRoleName, QObject* parent = nullptr) explicit QObjectVectorModel(const char* objectRoleName, QObject* parent = nullptr)
: QObjectVectorModel(ObjectContainer{}, objectRoleName, parent) : QObjectVectorModel(ObjectContainer{}, objectRoleName, parent)
{} { }
~QObjectVectorModel() {}; ~QObjectVectorModel(){};
QHash<int, QByteArray> roleNames() const override { QHash<int, QByteArray> roleNames() const override
{
return {{ObjectRole, m_roleName}}; 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) Q_UNUSED(parent)
return m_objects.size(); return m_objects.size();
} }
virtual QVariant data(const QModelIndex& index, int role) const override { virtual QVariant data(const QModelIndex& index, int role) const override
if(!QAbstractItemModel::checkIndex(index) || role != ObjectRole) {
return QVariant(); if(!QAbstractItemModel::checkIndex(index) || role != ObjectRole) return QVariant();
return QVariant::fromValue<QObject*>(m_objects[index.row()].get()); 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(); 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); return m_objects.at(pos);
}; };
size_t size() const { size_t size() const
{
return m_objects.size(); return m_objects.size();
}; };
void reset(const ObjectContainer& objects) { void reset(const ObjectContainer& objects)
{
beginResetModel(); beginResetModel();
m_objects = objects; m_objects = objects;
endResetModel(); endResetModel();
}; };
void clear() { void clear()
{
reset({}); 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()); beginInsertRows(QModelIndex(), m_objects.size(), m_objects.size());
m_objects.push_back(newValue); m_objects.push_back(newValue);
endInsertRows(); endInsertRows();
}; };
void resize(size_t count) { void resize(size_t count)
if(count > m_objects.size()) { {
if(count > m_objects.size())
{
beginInsertRows(QModelIndex(), m_objects.size(), count - 1); beginInsertRows(QModelIndex(), m_objects.size(), count - 1);
m_objects.resize(count); m_objects.resize(count);
endInsertRows(); endInsertRows();
} }
else if(count < m_objects.size()) { else if(count < m_objects.size())
{
beginRemoveRows(QModelIndex(), count, m_objects.size() - 1); beginRemoveRows(QModelIndex(), count, m_objects.size() - 1);
m_objects.resize(count); m_objects.resize(count);
endRemoveRows(); 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; m_objects.at(row) = newVal;
emit dataChanged(index(row), index(row), {}); emit dataChanged(index(row), index(row), {});
}; };
const ObjectContainer &objects() const { return m_objects; }; const ObjectContainer& objects() const
{
return m_objects;
};
private: private:
ObjectContainer m_objects; ObjectContainer m_objects;
@ -101,4 +115,4 @@ private:
constexpr static auto ObjectRole = Qt::UserRole + 1; constexpr static auto ObjectRole = Qt::UserRole + 1;
}; };
} } // namespace Status::Helpers

View File

@ -5,7 +5,7 @@
namespace Status::Helpers namespace Status::Helpers
{ {
template<typename T> template <typename T>
class Singleton class Singleton
{ {
public: public:
@ -18,10 +18,10 @@ public:
} }
Singleton<T>(const Singleton<T>&) = delete; Singleton<T>(const Singleton<T>&) = delete;
Singleton<T>& operator = (const Singleton<T>&) = delete; Singleton<T>& operator=(const Singleton<T>&) = delete;
private:
private:
Singleton<T>() = default; Singleton<T>() = default;
}; };
} } // namespace Status::Helpers

View File

@ -2,14 +2,17 @@
namespace fs = std::filesystem; 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()); return QString::fromStdString(path.string());
} }
fs::path toPath(const QString &pathStr) { fs::path toPath(const QString& pathStr)
{
return fs::path(pathStr.toStdString()); return fs::path(pathStr.toStdString());
} }
} } // namespace Status

View File

@ -2,9 +2,9 @@
#include "helpers.h" #include "helpers.h"
#include <QString>
#include <QByteArray> #include <QByteArray>
#include <QColor> #include <QColor>
#include <QString>
#include <QUrl> #include <QUrl>
#include <filesystem> #include <filesystem>
@ -13,7 +13,8 @@
using json = nlohmann::json; using json = nlohmann::json;
namespace Status { namespace Status
{
QString toQString(const std::filesystem::path& path); QString toQString(const std::filesystem::path& path);
@ -21,28 +22,35 @@ std::filesystem::path toPath(const QString& pathStr);
} // namespace Status } // namespace Status
namespace nlohmann { namespace nlohmann
{
template<> template <>
struct adl_serializer<QString> { struct adl_serializer<QString>
static void to_json(json& j, const QString& str) { {
static void to_json(json& j, const QString& str)
{
j = str.toStdString(); 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>()); str = QString::fromStdString(j.get<std::string>());
} }
}; };
using namespace std::string_literals; using namespace std::string_literals;
template<> template <>
struct adl_serializer<QByteArray> { struct adl_serializer<QByteArray>
static void to_json(json& j, const QByteArray& data) { {
static void to_json(json& j, const QByteArray& data)
{
j = data.toStdString(); 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>(); auto str = j.get<std::string>();
if(str.size() >= 2 && Status::Helpers::iequals(str, "0x"s, 2)) 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)); data = QByteArray::fromHex(QByteArray::fromRawData(str.c_str() + 2 * sizeof(str[0]), str.size() - 2));
@ -51,35 +59,44 @@ struct adl_serializer<QByteArray> {
} }
}; };
template<> template <>
struct adl_serializer<QColor> { struct adl_serializer<QColor>
static void to_json(json& j, const QColor& color) { {
static void to_json(json& j, const QColor& color)
{
j = color.name(); 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>())); color = QColor(QString::fromStdString(j.get<std::string>()));
} }
}; };
template<> template <>
struct adl_serializer<QUrl> { struct adl_serializer<QUrl>
static void to_json(json& j, const QUrl& url) { {
static void to_json(json& j, const QUrl& url)
{
j = url.toString(); 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>())); url = QUrl(QString::fromStdString(j.get<std::string>()));
} }
}; };
template<typename T> template <typename T>
struct adl_serializer<std::optional<T>> { struct adl_serializer<std::optional<T>>
static void to_json(json& j, const std::optional<T>& opt) { {
static void to_json(json& j, const std::optional<T>& opt)
{
j = opt.value(); 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>()); opt.emplace(j.get<T>());
} }
}; };

View File

@ -4,53 +4,56 @@
#include <QObject> #include <QObject>
#include <string>
#include <map> #include <map>
#include <memory.h> #include <memory.h>
#include <string>
namespace Status::Helpers { namespace Status::Helpers
{
constexpr bool isDebugBuild() constexpr bool isDebugBuild()
{ {
#if defined BUILD_DEBUG #if defined BUILD_DEBUG
return true; return true;
#else #else
return false; return false;
#endif #endif
} }
/// Case insensitive comparision with optional limitation to first \c len characters /// Case insensitive comparision with optional limitation to first \c len characters
/// \note \c T entry type must support \c tolower /// \note \c T entry type must support \c tolower
/// \todo test me /// \todo test me
template<typename T> template <typename T>
bool iequals(const T& a, const T& b, size_t len = -1) bool iequals(const T& a, const T& b, size_t len = -1)
{ {
return len < a.size() && len < b.size() && return len < a.size() && len < b.size() &&
std::equal(a.begin(), len >= 0 ? a.end() : a.begin() + len, std::equal(a.begin(),
b.begin(), len >= 0 ? b.end() : b.begin() + len, len >= 0 ? a.end() : a.begin() + len,
[](auto a, auto b) { b.begin(),
return tolower(a) == tolower(b); 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> getKeys(const std::map<KeyType, ValT>& map)
{ {
std::vector<KeyType> keys; std::vector<KeyType> keys;
keys.reserve(map.size()); keys.reserve(map.size());
for (const auto& [key, _] : map) for(const auto& [key, _] : map)
keys.push_back(key); keys.push_back(key);
return keys; return keys;
} }
static void doDeleteLater(QObject *obj) { static void doDeleteLater(QObject* obj)
{
obj->deleteLater(); obj->deleteLater();
} }
// TODO: use https://en.cppreference.com/w/cpp/memory/shared_ptr/allocate_shared // TODO: use https://en.cppreference.com/w/cpp/memory/shared_ptr/allocate_shared
template<typename T, typename ...Args> template <typename T, typename... Args>
std::shared_ptr<T> makeSharedQObject(Args&& ...args) { std::shared_ptr<T> makeSharedQObject(Args&&... args)
{
return std::shared_ptr<T>(new T(std::forward<Args>(args)...), doDeleteLater); return std::shared_ptr<T>(new T(std::forward<Args>(args)...), doDeleteLater);
} }
} } // namespace Status::Helpers

View File

@ -8,14 +8,15 @@
#include "BuildConfiguration.h" #include "BuildConfiguration.h"
namespace Status::Helpers { namespace Status::Helpers
{
void logFormatter(QtMsgType type, const QMessageLogContext& context, const QString& msg) void logFormatter(QtMsgType type, const QMessageLogContext& context, const QString& msg)
{ {
// TODO: Refactor it into development-tools app // TODO: Refactor it into development-tools app
//if(isDebugBuild()) { //if(isDebugBuild()) {
std::cout << msg.toLocal8Bit().data() << std::endl; std::cout << msg.toLocal8Bit().data() << std::endl;
return; return;
//} //}
QByteArray localMsg = msg.toLocal8Bit(); 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; 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, 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

View File

@ -4,9 +4,10 @@
#include <QDebug> #include <QDebug>
#include <QString> #include <QString>
namespace Status::Helpers { namespace Status::Helpers
{
/// Formats with colloring output if not a development build /// Formats with colloring output if not a development build
void logFormatter(QtMsgType type, const QMessageLogContext& context, const QString& msg); void logFormatter(QtMsgType type, const QMessageLogContext& context, const QString& msg);
} } // namespace Status::Helpers

View File

@ -3,16 +3,14 @@
#include <StatusGo/Accounts/Accounts.h> #include <StatusGo/Accounts/Accounts.h>
#include <StatusGo/Accounts/AccountsAPI.h> #include <StatusGo/Accounts/AccountsAPI.h>
#include <StatusGo/General.h> #include <StatusGo/General.h>
#include <StatusGo/Utils.h>
#include <StatusGo/Messenger/Service.h> #include <StatusGo/Messenger/Service.h>
#include <StatusGo/Utils.h>
#include <Helpers/conversions.h> #include <Helpers/conversions.h>
#include <optional> #include <optional>
std::optional<QString> getDataFromFile(const fs::path& path)
std::optional<QString>
getDataFromFile(const fs::path &path)
{ {
QFile jsonFile{Status::toQString(path)}; QFile jsonFile{Status::toQString(path)};
if(!jsonFile.open(QIODevice::ReadOnly)) if(!jsonFile.open(QIODevice::ReadOnly))
@ -34,8 +32,7 @@ namespace Status::Onboarding
AccountsService::AccountsService() AccountsService::AccountsService()
: m_isFirstTimeAccountLogin(false) : m_isFirstTimeAccountLogin(false)
{ { }
}
bool AccountsService::init(const fs::path& statusgoDataDir) bool AccountsService::init(const fs::path& statusgoDataDir)
{ {
@ -47,7 +44,7 @@ bool AccountsService::init(const fs::path& statusgoDataDir)
return false; return false;
} }
for(const auto &genAddressObj : response.result) for(const auto& genAddressObj : response.result)
{ {
auto gAcc = GeneratedMultiAccount::toGeneratedMultiAccount(genAddressObj.toObject()); auto gAcc = GeneratedMultiAccount::toGeneratedMultiAccount(genAddressObj.toObject());
gAcc.alias = generateAlias(gAcc.derivedAccounts.whisper.publicKey); gAcc.alias = generateAlias(gAcc.derivedAccounts.whisper.publicKey);
@ -67,7 +64,7 @@ std::vector<MultiAccount> AccountsService::openAndListAccounts()
const auto multiAccounts = response.result; const auto multiAccounts = response.result;
std::vector<MultiAccount> result; std::vector<MultiAccount> result;
for(const auto &value : multiAccounts) for(const auto& value : multiAccounts)
{ {
result.push_back(MultiAccount::toMultiAccount(value.toObject())); result.push_back(MultiAccount::toMultiAccount(value.toObject()));
} }
@ -79,13 +76,14 @@ const std::vector<GeneratedMultiAccount>& AccountsService::generatedAccounts() c
return m_generatedAccounts; 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 QString installationId(QUuid::createUuid().toString(QUuid::WithoutBraces));
const QJsonObject accountData(getAccountDataForAccountId(accountId, displayName)); const QJsonObject accountData(getAccountDataForAccountId(accountId, displayName));
if(!setKeyStoreDir(accountData.value("key-uid").toString())) if(!setKeyStoreDir(accountData.value("key-uid").toString())) return false;
return false;
QJsonArray subAccountData(getSubaccountDataForAccountId(accountId, displayName)); QJsonArray subAccountData(getSubaccountDataForAccountId(accountId, displayName));
QJsonObject settings(getAccountSettings(accountId, installationId, displayName)); QJsonObject settings(getAccountSettings(accountId, installationId, displayName));
@ -94,8 +92,7 @@ bool AccountsService::setupAccountAndLogin(const QString &accountId, const QStri
auto hashedPassword(Utils::hashPassword(password)); auto hashedPassword(Utils::hashPassword(password));
// This initialize the DB if first time running. Required for storing accounts // This initialize the DB if first time running. Required for storing accounts
if(StatusGo::Accounts::openAccounts(m_statusgoDataDir.c_str()).containsError()) if(StatusGo::Accounts::openAccounts(m_statusgoDataDir.c_str()).containsError()) return false;
return false;
AccountsService::storeAccount(accountId, hashedPassword); AccountsService::storeAccount(accountId, hashedPassword);
AccountsService::storeDerivedAccounts(accountId, hashedPassword, Constants::General::AccountDefaultPaths); AccountsService::storeDerivedAccounts(accountId, hashedPassword, Constants::General::AccountDefaultPaths);
@ -120,7 +117,7 @@ bool AccountsService::isFirstTimeAccountLogin() const
return m_isFirstTimeAccountLogin; return m_isFirstTimeAccountLogin;
} }
bool AccountsService::setKeyStoreDir(const QString &key) bool AccountsService::setKeyStoreDir(const QString& key)
{ {
m_keyStoreDir = m_statusgoDataDir / m_keyStoreDirName / key.toStdString(); m_keyStoreDir = m_statusgoDataDir / m_keyStoreDirName / key.toStdString();
const auto response = StatusGo::General::initKeystore(m_keyStoreDir.c_str()); 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) QString AccountsService::login(MultiAccount account, const QString& password)
{ {
// This is a requirement. Make it more explicit into the status go module // This is a requirement. Make it more explicit into the status go module
if(!setKeyStoreDir(account.keyUid)) if(!setKeyStoreDir(account.keyUid)) return QString("Failed to initialize keystore before logging in");
return QString("Failed to initialize keystore before logging in");
// This initialize the DB if first time running. Required before logging in // This initialize the DB if first time running. Required before logging in
if(StatusGo::Accounts::openAccounts(m_statusgoDataDir.c_str()).containsError()) 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 thumbnailImage;
const QString largeImage; const QString largeImage;
const auto response = StatusGo::Accounts::login(account.name, account.keyUid, hashedPassword, const auto response =
thumbnailImage, largeImage); StatusGo::Accounts::login(account.name, account.keyUid, hashedPassword, thumbnailImage, largeImage);
if(response.containsError()) if(response.containsError())
{ {
qWarning() << response.error.message; qWarning() << response.error.message;
@ -174,13 +170,14 @@ QString AccountsService::generateAlias(const QString& publicKey)
return response.result; return response.result;
} }
void AccountsService::deleteMultiAccount(const MultiAccount &account) void AccountsService::deleteMultiAccount(const MultiAccount& account)
{ {
StatusGo::Accounts::deleteMultiaccount(account.keyUid, m_keyStoreDir); StatusGo::Accounts::deleteMultiaccount(account.keyUid, m_keyStoreDir);
} }
DerivedAccounts AccountsService::storeDerivedAccounts(const QString& accountId, const StatusGo::HashedPassword& password, DerivedAccounts AccountsService::storeDerivedAccounts(const QString& accountId,
const std::vector<Accounts::DerivationPath> &paths) const StatusGo::HashedPassword& password,
const std::vector<Accounts::DerivationPath>& paths)
{ {
const auto response = StatusGo::Accounts::storeDerivedAccounts(accountId, password, paths); const auto response = StatusGo::Accounts::storeDerivedAccounts(accountId, password, paths);
if(response.containsError()) if(response.containsError())
@ -202,11 +199,14 @@ StoredMultiAccount AccountsService::storeAccount(const QString& accountId, const
return toStoredMultiAccount(response.result); return toStoredMultiAccount(response.result);
} }
MultiAccount AccountsService::saveAccountAndLogin(const StatusGo::HashedPassword& password, const QJsonObject& account, MultiAccount AccountsService::saveAccountAndLogin(const StatusGo::HashedPassword& password,
const QJsonArray& subaccounts, const QJsonObject& settings, const QJsonObject& account,
const QJsonObject& config) 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"); qWarning() << "Failed saving acccount" << account.value("name");
return MultiAccount(); return MultiAccount();
} }
@ -215,17 +215,18 @@ MultiAccount AccountsService::saveAccountAndLogin(const StatusGo::HashedPassword
return MultiAccount::toMultiAccount(account); 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}, return QJsonObject{{"name", displayName.isEmpty() ? account.alias : displayName},
{"address", account.address}, {"address", account.address},
{"key-uid", account.keyUid}, {"key-uid", account.keyUid},
{"keycard-pairing", QJsonValue()}}; {"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) if(acc.id == accountId)
{ {
@ -245,33 +246,28 @@ QJsonObject AccountsService::getAccountDataForAccountId(const QString &accountId
return QJsonObject(); return QJsonObject();
} }
QJsonArray AccountsService::prepareSubaccountJsonObject(const GeneratedMultiAccount& account, const QString &displayName) const QJsonArray AccountsService::prepareSubaccountJsonObject(const GeneratedMultiAccount& account,
const QString& displayName) const
{ {
return { return {QJsonObject{{"public-key", account.derivedAccounts.defaultWallet.publicKey},
QJsonObject{ {"address", account.derivedAccounts.defaultWallet.address},
{"public-key", account.derivedAccounts.defaultWallet.publicKey}, {"color", "#4360df"},
{"address", account.derivedAccounts.defaultWallet.address}, {"wallet", true},
{"color", "#4360df"}, {"path", Constants::General::PathDefaultWallet.get()},
{"wallet", true}, {"name", "Status account"},
{"path", Constants::General::PathDefaultWallet.get()}, {"derived-from", account.address}},
{"name", "Status account"}, QJsonObject{{"public-key", account.derivedAccounts.whisper.publicKey},
{"derived-from", account.address} {"address", account.derivedAccounts.whisper.address},
}, {"name", displayName.isEmpty() ? account.alias : displayName},
QJsonObject{ {"path", Constants::General::PathWhisper.get()},
{"public-key", account.derivedAccounts.whisper.publicKey}, {"chat", true},
{"address", account.derivedAccounts.whisper.address}, {"derived-from", ""}}};
{"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 :)" // "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) if(acc.id == accountId)
{ {
@ -297,42 +293,42 @@ QString AccountsService::generateSigningPhrase(int count) const
for(int i = 0; i < count; i++) for(int i = 0; i < count; i++)
{ {
words.append(Constants::SigningPhrases[QRandomGenerator::global()->bounded( words.append(Constants::SigningPhrases[QRandomGenerator::global()->bounded(
static_cast<int>(Constants::SigningPhrases.size()))]); static_cast<int>(Constants::SigningPhrases.size()))]);
} }
return words.join(" "); return words.join(" ");
} }
QJsonObject AccountsService::prepareAccountSettingsJsonObject(const GeneratedMultiAccount& account, QJsonObject AccountsService::prepareAccountSettingsJsonObject(const GeneratedMultiAccount& account,
const QString& installationId, const QString& installationId,
const QString& displayName) const const QString& displayName) const
{ {
return QJsonObject{ return QJsonObject{{"key-uid", account.keyUid},
{"key-uid", account.keyUid}, {"mnemonic", account.mnemonic},
{"mnemonic", account.mnemonic}, {"public-key", account.derivedAccounts.whisper.publicKey},
{"public-key", account.derivedAccounts.whisper.publicKey}, {"name", account.alias},
{"name", account.alias}, {"display-name", displayName},
{"display-name", displayName}, {"address", account.address},
{"address", account.address}, {"eip1581-address", account.derivedAccounts.eip1581.address},
{"eip1581-address", account.derivedAccounts.eip1581.address}, {"dapps-address", account.derivedAccounts.defaultWallet.address},
{"dapps-address", account.derivedAccounts.defaultWallet.address}, {"wallet-root-address", account.derivedAccounts.walletRoot.address},
{"wallet-root-address", account.derivedAccounts.walletRoot.address}, {"preview-privacy?", true},
{"preview-privacy?", true}, {"signing-phrase", generateSigningPhrase(3)},
{"signing-phrase", generateSigningPhrase(3)}, {"log-level", "INFO"},
{"log-level", "INFO"}, {"latest-derived-path", 0},
{"latest-derived-path", 0}, {"currency", "usd"},
{"currency", "usd"}, {"networks/networks", QJsonArray()},
{"networks/networks", QJsonArray()}, {"networks/current-network", ""},
{"networks/current-network", ""}, {"wallet/visible-tokens", QJsonObject()},
{"wallet/visible-tokens", QJsonObject()}, {"waku-enabled", true},
{"waku-enabled", true}, {"appearance", 0},
{"appearance", 0}, {"installation-id", installationId}};
{"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) if(acc.id == accountId)
{ {
@ -363,7 +359,8 @@ QJsonArray getNodes(const QJsonObject& fleet, const QString& nodeType)
QJsonObject AccountsService::getDefaultNodeConfig(const QString& installationId) const QJsonObject AccountsService::getDefaultNodeConfig(const QString& installationId) const
{ {
try { try
{
auto templateNodeConfigJsonStr = getDataFromFile(":/Status/StaticConfig/node-config.json").value(); auto templateNodeConfigJsonStr = getDataFromFile(":/Status/StaticConfig/node-config.json").value();
auto fleetJson = getDataFromFile(":/Status/StaticConfig/fleets.json").value(); auto fleetJson = getDataFromFile(":/Status/StaticConfig/fleets.json").value();
auto infuraKey = getDataFromFile(":/Status/StaticConfig/infura_key").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_DATADIR = m_statusgoDataDir / "archivedata";
auto DEFAULT_TORRENT_CONFIG_TORRENTDIR = m_statusgoDataDir / "torrents"; auto DEFAULT_TORRENT_CONFIG_TORRENTDIR = m_statusgoDataDir / "torrents";
auto nodeConfigJsonStr = templateNodeConfigJsonStr auto nodeConfigJsonStr =
.replace("%INSTALLATIONID%", installationId) templateNodeConfigJsonStr.replace("%INSTALLATIONID%", installationId)
.replace("%INFURA_TOKEN_RESOLVED%", infuraKey) .replace("%INFURA_TOKEN_RESOLVED%", infuraKey)
.replace("%DEFAULT_TORRENT_CONFIG_PORT%", QString::number(DEFAULT_TORRENT_CONFIG_PORT)) .replace("%DEFAULT_TORRENT_CONFIG_PORT%", QString::number(DEFAULT_TORRENT_CONFIG_PORT))
.replace("%DEFAULT_TORRENT_CONFIG_DATADIR%", DEFAULT_TORRENT_CONFIG_DATADIR.c_str()) .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)); nodeConfigJson["KeyStoreDir"] = toQString(fs::relative(m_keyStoreDir, m_statusgoDataDir));
return nodeConfigJson; return nodeConfigJson;
} catch (std::bad_optional_access) { }
catch(std::bad_optional_access)
{
return QJsonObject(); return QJsonObject();
} }
} }
} } // namespace Status::Onboarding

View File

@ -44,7 +44,7 @@ public:
[[nodiscard]] bool isFirstTimeAccountLogin() const override; [[nodiscard]] bool isFirstTimeAccountLogin() const override;
/// \see ServiceInterface /// \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 /// \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 /// 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; QString generateAlias(const QString& publicKey) override;
void deleteMultiAccount(const MultiAccount &account) override; void deleteMultiAccount(const MultiAccount& account) override;
private: private:
QJsonObject prepareAccountJsonObject(const GeneratedMultiAccount& account, const QString& displayName) const; 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); const std::vector<Accounts::DerivationPath>& paths);
StoredMultiAccount storeAccount(const QString& accountId, const StatusGo::HashedPassword& password); StoredMultiAccount storeAccount(const QString& accountId, const StatusGo::HashedPassword& password);
MultiAccount saveAccountAndLogin(const StatusGo::HashedPassword& password, const QJsonObject& account, MultiAccount saveAccountAndLogin(const StatusGo::HashedPassword& password,
const QJsonArray& subaccounts, const QJsonObject& settings, const QJsonObject& account,
const QJsonObject& config); const QJsonArray& subaccounts,
const QJsonObject& settings,
const QJsonObject& config);
QJsonObject getAccountDataForAccountId(const QString& accountId, const QString& displayName) const; QJsonObject getAccountDataForAccountId(const QString& accountId, const QString& displayName) const;
@ -79,7 +82,8 @@ private:
const QString& installationId, const QString& installationId,
const QString& displayName) const; 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; QJsonObject getDefaultNodeConfig(const QString& installationId) const;
@ -97,4 +101,4 @@ private:
static constexpr auto m_keyStoreDirName = "keystore"; static constexpr auto m_keyStoreDirName = "keystore";
}; };
} } // namespace Status::Onboarding

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "MultiAccount.h"
#include "GeneratedMultiAccount.h" #include "GeneratedMultiAccount.h"
#include "MultiAccount.h"
#include <filesystem> #include <filesystem>
@ -13,7 +13,6 @@ namespace Status::Onboarding
class AccountsServiceInterface class AccountsServiceInterface
{ {
public: public:
virtual ~AccountsServiceInterface() = default; virtual ~AccountsServiceInterface() = default;
/// Generates and cache addresses accessible by \c generatedAccounts /// Generates and cache addresses accessible by \c generatedAccounts
@ -26,7 +25,8 @@ public:
[[nodiscard]] virtual const std::vector<GeneratedMultiAccount>& generatedAccounts() const = 0; [[nodiscard]] virtual const std::vector<GeneratedMultiAccount>& generatedAccounts() const = 0;
/// Configure an generated account. \a accountID must be sourced from \c generatedAccounts /// 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 /// Account that is currently logged-in
[[nodiscard]] virtual const MultiAccount& getLoggedInAccount() const = 0; [[nodiscard]] virtual const MultiAccount& getLoggedInAccount() const = 0;
@ -37,7 +37,7 @@ public:
[[nodiscard]] virtual bool isFirstTimeAccountLogin() const = 0; [[nodiscard]] virtual bool isFirstTimeAccountLogin() const = 0;
/// Set and initializes the keystore directory. \see StatusGo::General::initKeystore /// 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; virtual QString login(MultiAccount account, const QString& password) = 0;
@ -45,9 +45,9 @@ public:
virtual QString generateAlias(const QString& publicKey) = 0; 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>; using AccountsServiceInterfacePtr = std::shared_ptr<AccountsServiceInterface>;
} } // namespace Status::Onboarding

View File

@ -1,8 +1,8 @@
#pragma once #pragma once
#include "Common/Constants.h" #include "Common/Constants.h"
#include "Common/SigningPhrases.h"
#include "Common/Json.h" #include "Common/Json.h"
#include "Common/SigningPhrases.h"
#include <QtCore> #include <QtCore>
@ -27,7 +27,7 @@ struct DerivedAccountDetails
result.publicKey = Json::getMandatoryProp(jsonObj, "publicKey")->toString(); result.publicKey = Json::getMandatoryProp(jsonObj, "publicKey")->toString();
result.address = Json::getMandatoryProp(jsonObj, "address")->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()); qWarning() << QString("Mapping DerivedAccountDetails failed: %1").arg(e.what());
} }
@ -47,7 +47,7 @@ struct DerivedAccounts
{ {
auto result = DerivedAccounts(); auto result = DerivedAccounts();
for(const auto &derivationPath : jsonObj.keys()) for(const auto& derivationPath : jsonObj.keys())
{ {
auto derivedObj = jsonObj.value(derivationPath).toObject(); auto derivedObj = jsonObj.value(derivationPath).toObject();
if(derivationPath == Constants::General::PathWhisper.get()) if(derivationPath == Constants::General::PathWhisper.get())
@ -76,17 +76,19 @@ struct StoredMultiAccount
{ {
QString publicKey; QString publicKey;
QString address; QString address;
}; };
static StoredMultiAccount toStoredMultiAccount(const QJsonObject& jsonObj) static StoredMultiAccount toStoredMultiAccount(const QJsonObject& jsonObj)
{ {
auto result = StoredMultiAccount(); auto result = StoredMultiAccount();
try { try
{
result.address = Json::getMandatoryProp(jsonObj, "address")->toString(); result.address = Json::getMandatoryProp(jsonObj, "address")->toString();
result.publicKey = Json::getMandatoryProp(jsonObj, "publicKey")->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()); qWarning() << QString("Mapping StoredMultiAccount failed: %1").arg(e.what());
} }
@ -128,7 +130,7 @@ struct GeneratedMultiAccount
result.derivedAccounts = DerivedAccounts::toDerivedAccounts(derivedObj); result.derivedAccounts = DerivedAccounts::toDerivedAccounts(derivedObj);
} }
} }
catch (std::exception e) catch(std::exception e)
{ {
qWarning() << QString("Mapping GeneratedMultiAccount failed: %1").arg(e.what()); qWarning() << QString("Mapping GeneratedMultiAccount failed: %1").arg(e.what());
} }
@ -137,4 +139,4 @@ struct GeneratedMultiAccount
} }
}; };
} } // namespace Status::Onboarding

View File

@ -1,8 +1,8 @@
#pragma once #pragma once
#include "Common/Constants.h" #include "Common/Constants.h"
#include "Common/SigningPhrases.h"
#include "Common/Json.h" #include "Common/Json.h"
#include "Common/SigningPhrases.h"
#include <StatusGo/Accounts/accounts_types.h> #include <StatusGo/Accounts/accounts_types.h>
@ -39,11 +39,11 @@ struct MultiAccount
{ {
result.name = Json::getMandatoryProp(jsonObj, "name")->toString(); result.name = Json::getMandatoryProp(jsonObj, "name")->toString();
auto timestampIt = Json::getProp(jsonObj, "timestamp"); auto timestampIt = Json::getProp(jsonObj, "timestamp");
if(timestampIt != jsonObj.constEnd()) { if(timestampIt != jsonObj.constEnd())
{
bool ok = false; bool ok = false;
auto t = timestampIt->toString().toLong(&ok); auto t = timestampIt->toString().toLong(&ok);
if(ok) if(ok) result.timestamp = t;
result.timestamp = t;
} }
result.keycardPairing = Json::getMandatoryProp(jsonObj, "keycard-pairing")->toString(); result.keycardPairing = Json::getMandatoryProp(jsonObj, "keycard-pairing")->toString();
result.keyUid = Json::getMandatoryProp(jsonObj, "key-uid")->toString(); result.keyUid = Json::getMandatoryProp(jsonObj, "key-uid")->toString();
@ -51,7 +51,7 @@ struct MultiAccount
/// TODO: investigate unhandled `photo-path` value /// TODO: investigate unhandled `photo-path` value
} }
catch (std::exception e) catch(std::exception e)
{ {
qWarning() << QString("Mapping MultiAccount failed: %1").arg(e.what()); qWarning() << QString("Mapping MultiAccount failed: %1").arg(e.what());
} }
@ -60,4 +60,4 @@ struct MultiAccount
} }
}; };
} } // namespace Status::Onboarding

View File

@ -2,8 +2,8 @@
#include <StatusGo/Accounts/accounts_types.h> #include <StatusGo/Accounts/accounts_types.h>
#include <QtCore>
#include <QStringLiteral> #include <QStringLiteral>
#include <QtCore>
namespace GoAccounts = Status::StatusGo::Accounts; namespace GoAccounts = Status::StatusGo::Accounts;
@ -12,41 +12,42 @@ namespace Status::Constants
namespace Fleet namespace Fleet
{ {
inline const auto Prod = u"eth.prod"_qs; inline const auto Prod = u"eth.prod"_qs;
inline const auto Staging = u"eth.staging"_qs; inline const auto Staging = u"eth.staging"_qs;
inline const auto Test = u"eth.test"_qs; inline const auto Test = u"eth.test"_qs;
inline const auto WakuV2Prod = u"wakuv2.prod"_qs; inline const auto WakuV2Prod = u"wakuv2.prod"_qs;
inline const auto WakuV2Test = u"wakuv2.test"_qs; inline const auto WakuV2Test = u"wakuv2.test"_qs;
inline const auto GoWakuTest = u"go-waku.test"_qs; inline const auto GoWakuTest = u"go-waku.test"_qs;
} } // namespace Fleet
namespace FleetNodes namespace FleetNodes
{ {
inline const auto Bootnodes = u"boot"_qs; inline const auto Bootnodes = u"boot"_qs;
inline const auto Mailservers = u"mail"_qs; inline const auto Mailservers = u"mail"_qs;
inline const auto Rendezvous = u"rendezvous"_qs; inline const auto Rendezvous = u"rendezvous"_qs;
inline const auto Whisper = u"whisper"_qs; inline const auto Whisper = u"whisper"_qs;
inline const auto Waku = u"waku"_qs; inline const auto Waku = u"waku"_qs;
inline const auto LibP2P = u"libp2p"_qs; inline const auto LibP2P = u"libp2p"_qs;
inline const auto Websocket = u"websocket"_qs; inline const auto Websocket = u"websocket"_qs;
} } // namespace FleetNodes
namespace General namespace General
{ {
inline const auto DefaultNetworkName = u"mainnet_rpc"_qs; inline const auto DefaultNetworkName = u"mainnet_rpc"_qs;
//const DEFAULT_NETWORKS_IDS* = @["mainnet_rpc", "testnet_rpc", "rinkeby_rpc", "goerli_rpc", "xdai_rpc", "poa_rpc" ] //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}; 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 // 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}; inline const GoAccounts::DerivationPath PathEIP1581{u"m/43'/60'/1581'"_qs};
// BIP44-0 Wallet key, the default wallet key // BIP44-0 Wallet key, the default wallet key
inline const GoAccounts::DerivationPath PathDefaultWallet{PathWalletRoot.get() + u"/0"_qs}; inline const GoAccounts::DerivationPath PathDefaultWallet{PathWalletRoot.get() + u"/0"_qs};
// EIP1581 Chat Key 0, the default whisper key // EIP1581 Chat Key 0, the default whisper key
inline const GoAccounts::DerivationPath PathWhisper{PathEIP1581.get() + u"/0'/0"_qs}; 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

View File

@ -20,7 +20,7 @@ public:
{ {
const auto it = getProp(object, field); 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()); throw std::logic_error(QString("No field `%1`").arg(field).toStdString());
} }
@ -29,4 +29,4 @@ public:
} }
}; };
} } // namespace Status

View File

@ -5,7 +5,7 @@
namespace Status::Constants 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", "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", "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", "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", "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", "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", "wood", "wool", "word", "work", "worm", "wrap", "wren", "yard", "yarn", "yawl", "year", "yoga", "yoke", "yurt",
"zinc", "zone" "zinc", "zone"};
};
} }

View File

@ -15,70 +15,70 @@ NewAccountController::NewAccountController(AccountsServiceInterfacePtr accountsS
: m_accountsService(accountsService) : m_accountsService(accountsService)
{ {
connect(this, &NewAccountController::passwordChanged, this, &NewAccountController::checkAndUpdateDataValidity); 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); connect(this, &NewAccountController::nameChanged, this, &NewAccountController::checkAndUpdateDataValidity);
} }
void NewAccountController::createAccount() void NewAccountController::createAccount()
{ {
// TODO: fix this after moving SingalManager to StatusGo wrapper lib // 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]() { auto setupAccountFn = [this]() {
if(m_nameIsValid && m_passwordIsValid && m_confirmationPasswordIsValid) { if(m_nameIsValid && m_passwordIsValid && m_confirmationPasswordIsValid)
{
auto genAccounts = m_accountsService->generatedAccounts(); auto genAccounts = m_accountsService->generatedAccounts();
if(genAccounts.size() > 0) { if(genAccounts.size() > 0)
if(m_accountsService->setupAccountAndLogin(genAccounts[0].id, m_password, m_name)) {
return; if(m_accountsService->setupAccountAndLogin(genAccounts[0].id, m_password, m_name)) return;
} }
} }
}; };
// TODO: refactor StatusGo wrapper to work with futures instead of SignalManager // TODO: refactor StatusGo wrapper to work with futures instead of SignalManager
m_createAccountFuture = QtConcurrent::run(setupAccountFn) m_createAccountFuture = QtConcurrent::run(setupAccountFn)
.then([]{ /*Nothing, we expect status-go events*/ }) .then([] { /*Nothing, we expect status-go events*/ })
.onFailed([this] { .onFailed([this] { emit accountCreationError(); })
emit accountCreationError(); .onCanceled([this] { emit accountCreationError(); });
})
.onCanceled([this] {
emit accountCreationError();
});
} }
const QString &NewAccountController::password() const const QString& NewAccountController::password() const
{ {
return m_password; return m_password;
} }
void NewAccountController::setPassword(const QString &newPassword) void NewAccountController::setPassword(const QString& newPassword)
{ {
if (m_password == newPassword) if(m_password == newPassword) return;
return;
m_password = newPassword; m_password = newPassword;
emit passwordChanged(); emit passwordChanged();
} }
const QString &NewAccountController::confirmationPassword() const const QString& NewAccountController::confirmationPassword() const
{ {
return m_confirmationPassword; return m_confirmationPassword;
} }
void NewAccountController::setConfirmationPassword(const QString &newConfirmationPassword) void NewAccountController::setConfirmationPassword(const QString& newConfirmationPassword)
{ {
if (m_confirmationPassword == newConfirmationPassword) if(m_confirmationPassword == newConfirmationPassword) return;
return;
m_confirmationPassword = newConfirmationPassword; m_confirmationPassword = newConfirmationPassword;
emit confirmationPasswordChanged(); emit confirmationPasswordChanged();
} }
const QString &NewAccountController::name() const const QString& NewAccountController::name() const
{ {
return m_name; return m_name;
} }
void NewAccountController::setName(const QString &newName) void NewAccountController::setName(const QString& newName)
{ {
if (m_name == newName) if(m_name == newName) return;
return;
m_name = newName; m_name = newName;
emit nameChanged(); emit nameChanged();
} }
@ -109,19 +109,22 @@ void NewAccountController::onNodeLogin(const QString& error)
void NewAccountController::checkAndUpdateDataValidity() void NewAccountController::checkAndUpdateDataValidity()
{ {
auto passwordValid = m_password.length() >= 6; auto passwordValid = m_password.length() >= 6;
if(passwordValid != m_passwordIsValid) { if(passwordValid != m_passwordIsValid)
{
m_passwordIsValid = passwordValid; m_passwordIsValid = passwordValid;
emit passwordIsValidChanged(); emit passwordIsValidChanged();
} }
auto confirmationPasswordValid = m_password == m_confirmationPassword; auto confirmationPasswordValid = m_password == m_confirmationPassword;
if(confirmationPasswordValid != m_confirmationPasswordIsValid) { if(confirmationPasswordValid != m_confirmationPasswordIsValid)
{
m_confirmationPasswordIsValid = confirmationPasswordValid; m_confirmationPasswordIsValid = confirmationPasswordValid;
emit confirmationPasswordIsValidChanged(); emit confirmationPasswordIsValidChanged();
} }
auto nameValid = m_name.length() >= 10; auto nameValid = m_name.length() >= 10;
if(nameValid != m_nameIsValid) { if(nameValid != m_nameIsValid)
{
m_nameIsValid = nameValid; m_nameIsValid = nameValid;
emit nameIsValidChanged(); emit nameIsValidChanged();
} }

View File

@ -20,7 +20,7 @@ class ServiceInterface;
* *
* \todo shared functionality should be moved to Common library (e.g. Name/Picture Validation) * \todo shared functionality should be moved to Common library (e.g. Name/Picture Validation)
*/ */
class NewAccountController: public QObject class NewAccountController : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -28,10 +28,12 @@ class NewAccountController: public QObject
QML_UNCREATABLE("Created and owned externally") QML_UNCREATABLE("Created and owned externally")
Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged) 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(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(bool passwordIsValid READ passwordIsValid NOTIFY passwordIsValidChanged) 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) Q_PROPERTY(bool nameIsValid READ nameIsValid NOTIFY nameIsValidChanged)
public: public:
@ -39,14 +41,14 @@ public:
Q_INVOKABLE void createAccount(); Q_INVOKABLE void createAccount();
const QString &password() const; const QString& password() const;
void setPassword(const QString &newPassword); void setPassword(const QString& newPassword);
const QString &confirmationPassword() const; const QString& confirmationPassword() const;
void setConfirmationPassword(const QString &newConfirmationPassword); void setConfirmationPassword(const QString& newConfirmationPassword);
const QString &name() const; const QString& name() const;
void setName(const QString &newName); void setName(const QString& newName);
bool passwordIsValid() const; bool passwordIsValid() const;
bool confirmationPasswordIsValid() const; bool confirmationPasswordIsValid() const;

View File

@ -8,7 +8,8 @@
#include <Helpers/helpers.h> #include <Helpers/helpers.h>
namespace Status::Onboarding { namespace Status::Onboarding
{
namespace StatusGo = Status::StatusGo; namespace StatusGo = Status::StatusGo;
@ -16,15 +17,20 @@ OnboardingController::OnboardingController(AccountsServiceInterfacePtr accountsS
: QObject(nullptr) : QObject(nullptr)
, m_accountsService(std::move(accountsService)) , m_accountsService(std::move(accountsService))
{ {
{ // Init accounts { // Init accounts
std::vector<std::shared_ptr<UserAccount>> accounts; std::vector<std::shared_ptr<UserAccount>> accounts;
for(auto &account : getOpenedAccounts()) { for(auto& account : getOpenedAccounts())
accounts.push_back(Helpers::makeSharedQObject<UserAccount>(std::make_unique<MultiAccount>(std::move(account)))); {
accounts.push_back(
Helpers::makeSharedQObject<UserAccount>(std::make_unique<MultiAccount>(std::move(account))));
} }
m_accounts = Helpers::makeSharedQObject<UserAccountsModel>(std::move(accounts)); 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() OnboardingController::~OnboardingController()
@ -50,16 +56,15 @@ void OnboardingController::login(QObject* user, const QString& password)
auto account = qobject_cast<UserAccount*>(user); auto account = qobject_cast<UserAccount*>(user);
assert(account != nullptr); assert(account != nullptr);
auto error = m_accountsService->login(account->accountData(), password); auto error = m_accountsService->login(account->accountData(), password);
if(!error.isEmpty()) if(!error.isEmpty()) emit accountLoginError(error);
emit accountLoginError(error);
} }
UserAccountsModel *OnboardingController::accounts() const UserAccountsModel* OnboardingController::accounts() const
{ {
return m_accounts.get(); return m_accounts.get();
} }
NewAccountController *OnboardingController::initNewAccountController() NewAccountController* OnboardingController::initNewAccountController()
{ {
m_newAccountController = std::make_unique<NewAccountController>(m_accountsService); m_newAccountController = std::make_unique<NewAccountController>(m_accountsService);
emit newAccountControllerChanged(); emit newAccountControllerChanged();
@ -72,7 +77,7 @@ void OnboardingController::terminateNewAccountController()
emit newAccountControllerChanged(); emit newAccountControllerChanged();
} }
NewAccountController *OnboardingController::newAccountController() const NewAccountController* OnboardingController::newAccountController() const
{ {
return m_newAccountController.get(); return m_newAccountController.get();
} }
@ -82,4 +87,4 @@ AccountsServiceInterfacePtr OnboardingController::accountsService() const
return m_accountsService; return m_accountsService;
} }
} } // namespace Status::Onboarding

View File

@ -22,8 +22,7 @@ class NewAccountController;
* \todo don't use DTOs in controllers, use QObjects directly * \todo don't use DTOs in controllers, use QObjects directly
* \todo make dependency on SignalManager explicit. Now it is hidden. * \todo make dependency on SignalManager explicit. Now it is hidden.
*/ */
class OnboardingController final : public QObject class OnboardingController final : public QObject, public std::enable_shared_from_this<OnboardingController>
, public std::enable_shared_from_this<OnboardingController>
{ {
Q_OBJECT 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 /// 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); 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(); Q_INVOKABLE void terminateNewAccountController();
NewAccountController *newAccountController() const; NewAccountController* newAccountController() const;
std::shared_ptr<AccountsServiceInterface> accountsService() const; std::shared_ptr<AccountsServiceInterface> accountsService() const;
signals: signals:
@ -72,4 +71,4 @@ private:
std::unique_ptr<NewAccountController> m_newAccountController; std::unique_ptr<NewAccountController> m_newAccountController;
}; };
} } // namespace Status::Onboarding

View File

@ -10,20 +10,20 @@ namespace AppCore = Status::ApplicationCore;
namespace fs = std::filesystem; 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} : OnboardingModule{parent}
{ {
m_userDataPath = userDataPath; m_userDataPath = userDataPath;
initWithUserDataPath(m_userDataPath); initWithUserDataPath(m_userDataPath);
} }
OnboardingModule::OnboardingModule(QObject *parent) OnboardingModule::OnboardingModule(QObject* parent)
: QObject{parent} : QObject{parent}
, m_accountsService(std::make_shared<AccountsService>()) , m_accountsService(std::make_shared<AccountsService>())
{ { }
}
OnboardingController* OnboardingModule::controller() const OnboardingController* OnboardingModule::controller() const
{ {
@ -32,20 +32,21 @@ OnboardingController* OnboardingModule::controller() const
void OnboardingModule::componentComplete() void OnboardingModule::componentComplete()
{ {
try { try
{
initWithUserDataPath(m_userDataPath); initWithUserDataPath(m_userDataPath);
} catch(const std::exception &e) { }
catch(const std::exception& e)
{
qCritical() << "OnboardingModule: failed to initialize"; 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); auto result = m_accountsService->init(path);
if(!result) if(!result) throw std::runtime_error(std::string("Failed to initialize OnboadingService") + path.string());
throw std::runtime_error(std::string("Failed to initialize OnboadingService") + path.string()); m_controller = Helpers::makeSharedQObject<OnboardingController>(m_accountsService);
m_controller = Helpers::makeSharedQObject<OnboardingController>(
m_accountsService);
emit controllerChanged(); emit controllerChanged();
} }
@ -54,13 +55,12 @@ const QString OnboardingModule::userDataPath() const
return QString::fromStdString(m_userDataPath.string()); return QString::fromStdString(m_userDataPath.string());
} }
void OnboardingModule::setUserDataPath(const QString &newUserDataPath) void OnboardingModule::setUserDataPath(const QString& newUserDataPath)
{ {
auto newVal = newUserDataPath.toStdString(); auto newVal = newUserDataPath.toStdString();
if (m_userDataPath.compare(newVal) == 0) if(m_userDataPath.compare(newVal) == 0) return;
return;
m_userDataPath = newVal; m_userDataPath = newVal;
emit userDataPathChanged(); emit userDataPathChanged();
} }
} } // namespace Status::Onboarding

View File

@ -9,7 +9,8 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace Status::Onboarding { namespace Status::Onboarding
{
class AccountsService; class AccountsService;
@ -31,16 +32,16 @@ class OnboardingModule : public QObject, public QQmlParserStatus
Q_PROPERTY(QString userDataPath READ userDataPath WRITE setUserDataPath NOTIFY userDataPathChanged REQUIRED) Q_PROPERTY(QString userDataPath READ userDataPath WRITE setUserDataPath NOTIFY userDataPathChanged REQUIRED)
public: public:
explicit OnboardingModule(const fs::path& userDataPath, QObject *parent = nullptr); explicit OnboardingModule(const fs::path& userDataPath, QObject* parent = nullptr);
explicit OnboardingModule(QObject *parent = nullptr); explicit OnboardingModule(QObject* parent = nullptr);
OnboardingController* controller() const; OnboardingController* controller() const;
const QString userDataPath() const; const QString userDataPath() const;
void setUserDataPath(const QString &newUserDataPath); void setUserDataPath(const QString& newUserDataPath);
/// QML inteface /// QML inteface
void classBegin() override {}; void classBegin() override{};
void componentComplete() override; void componentComplete() override;
signals: signals:
@ -48,9 +49,8 @@ signals:
void userDataPathChanged(); void userDataPathChanged();
private: private:
/// Throws exceptions /// Throws exceptions
void initWithUserDataPath(const fs::path &path); void initWithUserDataPath(const fs::path& path);
// TODO: plain object after refactoring shared_ptr requirement for now // TODO: plain object after refactoring shared_ptr requirement for now
std::shared_ptr<AccountsService> m_accountsService; std::shared_ptr<AccountsService> m_accountsService;
@ -59,4 +59,4 @@ private:
fs::path m_userDataPath; fs::path m_userDataPath;
}; };
} } // namespace Status::Onboarding

View File

@ -8,15 +8,14 @@ namespace Status::Onboarding
UserAccount::UserAccount(std::unique_ptr<MultiAccount> data) UserAccount::UserAccount(std::unique_ptr<MultiAccount> data)
: QObject() : QObject()
, m_data(std::move(data)) , m_data(std::move(data))
{ { }
}
const QString &UserAccount::name() const const QString& UserAccount::name() const
{ {
return m_data->name; return m_data->name;
} }
const MultiAccount &UserAccount::accountData() const const MultiAccount& UserAccount::accountData() const
{ {
return *m_data; return *m_data;
} }
@ -27,9 +26,7 @@ void UserAccount::updateAccountData(const MultiAccount& newData)
*m_data = newData; *m_data = newData;
if(newData.name != m_data->name) if(newData.name != m_data->name) notifyUpdates.push_back([this]() { emit nameChanged(); });
notifyUpdates.push_back([this]() { emit nameChanged(); });
} }
} } // namespace Status::Onboarding

View File

@ -13,7 +13,7 @@ class MultiAccount;
* @see OnboardingController * @see OnboardingController
* @see UserAccountsModel * @see UserAccountsModel
*/ */
class UserAccount: public QObject class UserAccount : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
@ -23,7 +23,7 @@ class UserAccount: public QObject
public: public:
explicit UserAccount(std::unique_ptr<MultiAccount> data); explicit UserAccount(std::unique_ptr<MultiAccount> data);
const QString &name() const; const QString& name() const;
const MultiAccount& accountData() const; const MultiAccount& accountData() const;
void updateAccountData(const MultiAccount& newData); void updateAccountData(const MultiAccount& newData);
@ -35,4 +35,4 @@ private:
std::unique_ptr<MultiAccount> m_data; std::unique_ptr<MultiAccount> m_data;
}; };
} } // namespace Status::Onboarding

View File

@ -2,25 +2,19 @@
#include <QObject> #include <QObject>
namespace Status::Onboarding { namespace Status::Onboarding
{
UserAccountsModel::UserAccountsModel(const std::vector<std::shared_ptr<UserAccount>> accounts, QObject* parent) UserAccountsModel::UserAccountsModel(const std::vector<std::shared_ptr<UserAccount>> accounts, QObject* parent)
: QAbstractListModel(parent) : QAbstractListModel(parent)
, m_accounts(std::move(accounts)) , m_accounts(std::move(accounts))
{ { }
}
UserAccountsModel::~UserAccountsModel() UserAccountsModel::~UserAccountsModel() { }
{
}
QHash<int, QByteArray> UserAccountsModel::roleNames() const QHash<int, QByteArray> UserAccountsModel::roleNames() const
{ {
static QHash<int, QByteArray> roles{ static QHash<int, QByteArray> roles{{Name, "name"}, {Account, "account"}};
{Name, "name"},
{Account, "account"}
};
return roles; return roles;
} }
@ -32,14 +26,14 @@ int UserAccountsModel::rowCount(const QModelIndex& parent) const
QVariant UserAccountsModel::data(const QModelIndex& index, int role) const QVariant UserAccountsModel::data(const QModelIndex& index, int role) const
{ {
if(!QAbstractItemModel::checkIndex(index)) if(!QAbstractItemModel::checkIndex(index)) return QVariant();
return QVariant();
switch(static_cast<ModelRole>(role)) { 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()); case Name: return QVariant::fromValue(m_accounts[index.row()].get()->name());
default: return QVariant(); case Account: return QVariant::fromValue<QObject*>(m_accounts[index.row()].get());
default: return QVariant();
} }
} }
} } // namespace Status::Onboarding

View File

@ -4,7 +4,8 @@
#include <QAbstractListModel> #include <QAbstractListModel>
namespace Status::Onboarding { namespace Status::Onboarding
{
/// \todo Replace it with \c QObjectVectorModel /// \todo Replace it with \c QObjectVectorModel
class UserAccountsModel : public QAbstractListModel class UserAccountsModel : public QAbstractListModel
@ -14,12 +15,13 @@ class UserAccountsModel : public QAbstractListModel
QML_ELEMENT QML_ELEMENT
QML_UNCREATABLE("Created by OnboardingController") QML_UNCREATABLE("Created by OnboardingController")
enum ModelRole { enum ModelRole
{
Name = Qt::UserRole + 1, Name = Qt::UserRole + 1,
Account Account
}; };
public:
public:
explicit UserAccountsModel(const std::vector<std::shared_ptr<UserAccount>> accounts, QObject* parent = nullptr); explicit UserAccountsModel(const std::vector<std::shared_ptr<UserAccount>> accounts, QObject* parent = nullptr);
~UserAccountsModel(); ~UserAccountsModel();
QHash<int, QByteArray> roleNames() const override; QHash<int, QByteArray> roleNames() const override;
@ -30,4 +32,4 @@ private:
const std::vector<std::shared_ptr<UserAccount>> m_accounts; const std::vector<std::shared_ptr<UserAccount>> m_accounts;
}; };
} } // namespace Status::Onboarding

View File

@ -2,7 +2,8 @@
#include <string> #include <string>
namespace Status::Testing::Constants { namespace Status::Testing::Constants
{
inline constexpr auto userDataDirName = "StatusTest"; inline constexpr auto userDataDirName = "StatusTest";
inline constexpr auto statusGoDataDirName = "data"; inline constexpr auto statusGoDataDirName = "data";
@ -12,4 +13,4 @@ inline constexpr auto qtDataDirName = "qt";
inline constexpr auto keystoreDataDirName = "keystore"; inline constexpr auto keystoreDataDirName = "keystore";
inline constexpr auto globalSettingsFileName = "global"; inline constexpr auto globalSettingsFileName = "global";
} } // namespace Status::Testing::Constants

View File

@ -20,11 +20,12 @@ namespace Accounts = Status::StatusGo::Accounts;
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace Status::Testing { namespace Status::Testing
{
ScopedTestAccount::ScopedTestAccount(const std::string &tempTestSubfolderName, ScopedTestAccount::ScopedTestAccount(const std::string& tempTestSubfolderName,
const QString &accountName, const QString& accountName,
const QString &accountPassword) const QString& accountPassword)
: m_fusedTestFolder{std::make_unique<AutoCleanTempTestDir>(tempTestSubfolderName)} : m_fusedTestFolder{std::make_unique<AutoCleanTempTestDir>(tempTestSubfolderName)}
, m_accountName(accountName) , m_accountName(accountName)
, m_accountPassword(accountPassword) , m_accountPassword(accountPassword)
@ -41,7 +42,9 @@ ScopedTestAccount::ScopedTestAccount(const std::string &tempTestSubfolderName,
auto accountsService = std::make_shared<Onboarding::AccountsService>(); auto accountsService = std::make_shared<Onboarding::AccountsService>();
auto result = accountsService->init(m_testFolderPath); auto result = accountsService->init(m_testFolderPath);
if(!result) if(!result)
{
throw std::runtime_error("ScopedTestAccount - Failed to create temporary test account"); throw std::runtime_error("ScopedTestAccount - Failed to create temporary test account");
}
// TODO refactor and merge account creation events with login into Onboarding controller // 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 // Beware, smartpointer is a requirement
m_onboarding = Helpers::makeSharedQObject<Onboarding::OnboardingController>(accountsService); m_onboarding = Helpers::makeSharedQObject<Onboarding::OnboardingController>(accountsService);
if(m_onboarding->getOpenedAccounts().size() != 0) if(m_onboarding->getOpenedAccounts().size() != 0)
{
throw std::runtime_error("ScopedTestAccount - already have opened account"); throw std::runtime_error("ScopedTestAccount - already have opened account");
}
int accountLoggedInCount = 0; int accountLoggedInCount = 0;
QObject::connect(m_onboarding.get(), &Onboarding::OnboardingController::accountLoggedIn, [&accountLoggedInCount]() { QObject::connect(m_onboarding.get(), &Onboarding::OnboardingController::accountLoggedIn, [&accountLoggedInCount]() {
accountLoggedInCount++; accountLoggedInCount++;
}); });
bool accountLoggedInError = false; bool accountLoggedInError = false;
QObject::connect(m_onboarding.get(), &Onboarding::OnboardingController::accountLoginError, [&accountLoggedInError]() { QObject::connect(m_onboarding.get(),
accountLoggedInError = true; &Onboarding::OnboardingController::accountLoginError,
}); [&accountLoggedInError]() { accountLoggedInError = true; });
// Create Accounts // Create Accounts
auto genAccounts = accountsService->generatedAccounts(); auto genAccounts = accountsService->generatedAccounts();
if(genAccounts.size() == 0) if(genAccounts.size() == 0)
{
throw std::runtime_error("ScopedTestAccount - missing generated accounts"); throw std::runtime_error("ScopedTestAccount - missing generated accounts");
}
if(accountsService->isFirstTimeAccountLogin()) if(accountsService->isFirstTimeAccountLogin())
{
throw std::runtime_error("ScopedTestAccount - Service::isFirstTimeAccountLogin returned true"); throw std::runtime_error("ScopedTestAccount - Service::isFirstTimeAccountLogin returned true");
}
if(!accountsService->setupAccountAndLogin(genAccounts[0].id, m_accountPassword, m_accountName)) if(!accountsService->setupAccountAndLogin(genAccounts[0].id, m_accountPassword, m_accountName))
{
throw std::runtime_error("ScopedTestAccount - Service::setupAccountAndLogin failed"); throw std::runtime_error("ScopedTestAccount - Service::setupAccountAndLogin failed");
}
if(!accountsService->isFirstTimeAccountLogin()) if(!accountsService->isFirstTimeAccountLogin())
{
throw std::runtime_error("ScopedTestAccount - Service::isFirstTimeAccountLogin returned false"); throw std::runtime_error("ScopedTestAccount - Service::isFirstTimeAccountLogin returned false");
}
if(!accountsService->getLoggedInAccount().isValid()) if(!accountsService->getLoggedInAccount().isValid())
{
throw std::runtime_error("ScopedTestAccount - newly created account is not valid"); throw std::runtime_error("ScopedTestAccount - newly created account is not valid");
}
if(accountsService->getLoggedInAccount().name != accountName) if(accountsService->getLoggedInAccount().name != accountName)
{
throw std::runtime_error("ScopedTestAccount - newly created account has a wrong name"); 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) if(accountLoggedInCount != 1)
{
throw std::runtime_error("ScopedTestAccount - missing confirmation of account creation"); throw std::runtime_error("ScopedTestAccount - missing confirmation of account creation");
}
if(accountLoggedInError) if(accountLoggedInError)
{
throw std::runtime_error("ScopedTestAccount - account loggedin error"); throw std::runtime_error("ScopedTestAccount - account loggedin error");
}
} }
ScopedTestAccount::~ScopedTestAccount() ScopedTestAccount::~ScopedTestAccount()
@ -94,12 +115,14 @@ ScopedTestAccount::~ScopedTestAccount()
m_onboarding->accountsService()->deleteMultiAccount(rootAccount); 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; using namespace std::chrono_literals;
std::chrono::milliseconds maxWaitTime{maxWaitTimeMillis}; std::chrono::milliseconds maxWaitTime{maxWaitTimeMillis};
auto iterationSleepTime = 2ms; auto iterationSleepTime = 2ms;
auto remainingIterations = maxWaitTime/iterationSleepTime; auto remainingIterations = maxWaitTime / iterationSleepTime;
while (remainingIterations-- > 0 && shouldWaitUntilTimeout()) { while(remainingIterations-- > 0 && shouldWaitUntilTimeout())
{
std::this_thread::sleep_for(iterationSleepTime); std::this_thread::sleep_for(iterationSleepTime);
QCoreApplication::sendPostedEvents(); QCoreApplication::sendPostedEvents();
@ -109,44 +132,46 @@ void ScopedTestAccount::processMessages(size_t maxWaitTimeMillis, std::function<
void ScopedTestAccount::logOut() void ScopedTestAccount::logOut()
{ {
if(Status::StatusGo::Accounts::logout().containsError()) if(Status::StatusGo::Accounts::logout().containsError())
{
throw std::runtime_error("ScopedTestAccount - failed logging out"); throw std::runtime_error("ScopedTestAccount - failed logging out");
}
} }
Accounts::ChatOrWalletAccount ScopedTestAccount::firstChatAccount() Accounts::ChatOrWalletAccount ScopedTestAccount::firstChatAccount()
{ {
auto accounts = Accounts::getAccounts(); auto accounts = Accounts::getAccounts();
auto chatIt = std::find_if(accounts.begin(), accounts.end(), [](const auto& a) { auto chatIt = std::find_if(accounts.begin(), accounts.end(), [](const auto& a) { return a.isChat; });
return a.isChat;
});
if(chatIt == accounts.end()) if(chatIt == accounts.end())
{
throw std::runtime_error("ScopedTestAccount::chatAccount: account not found"); throw std::runtime_error("ScopedTestAccount::chatAccount: account not found");
}
return *chatIt; return *chatIt;
} }
Accounts::ChatOrWalletAccount ScopedTestAccount::firstWalletAccount() Accounts::ChatOrWalletAccount ScopedTestAccount::firstWalletAccount()
{ {
auto accounts = Accounts::getAccounts(); auto accounts = Accounts::getAccounts();
auto walletIt = std::find_if(accounts.begin(), accounts.end(), [](const auto& a) { auto walletIt = std::find_if(accounts.begin(), accounts.end(), [](const auto& a) { return a.isWallet; });
return a.isWallet;
});
if(walletIt == accounts.end()) if(walletIt == accounts.end())
{
throw std::runtime_error("ScopedTestAccount::firstWalletAccount: account not found"); throw std::runtime_error("ScopedTestAccount::firstWalletAccount: account not found");
}
return *walletIt; return *walletIt;
} }
const Onboarding::MultiAccount &ScopedTestAccount::loggedInAccount() const const Onboarding::MultiAccount& ScopedTestAccount::loggedInAccount() const
{ {
return m_onboarding->accountsService()->getLoggedInAccount(); return m_onboarding->accountsService()->getLoggedInAccount();
} }
Onboarding::OnboardingController *ScopedTestAccount::onboardingController() const Onboarding::OnboardingController* ScopedTestAccount::onboardingController() const
{ {
return m_onboarding.get(); return m_onboarding.get();
} }
const std::filesystem::path &ScopedTestAccount::fusedTestFolder() const const std::filesystem::path& ScopedTestAccount::fusedTestFolder() const
{ {
return m_testFolderPath; return m_testFolderPath;
} }
} } // namespace Status::Testing

View File

@ -4,36 +4,39 @@
#include <StatusGo/Utils.h> #include <StatusGo/Utils.h>
#include <string>
#include <filesystem> #include <filesystem>
#include <string>
#include <QString> #include <QString>
class QCoreApplication; class QCoreApplication;
namespace Status::Onboarding { namespace Status::Onboarding
class OnboardingController; {
class MultiAccount; class OnboardingController;
} class MultiAccount;
} // namespace Status::Onboarding
namespace Wallet = Status::StatusGo::Wallet; namespace Wallet = Status::StatusGo::Wallet;
namespace Accounts = Status::StatusGo::Accounts; namespace Accounts = Status::StatusGo::Accounts;
namespace GoUtils = Status::StatusGo::Utils; namespace GoUtils = Status::StatusGo::Utils;
namespace Status::Testing { namespace Status::Testing
{
class AutoCleanTempTestDir; class AutoCleanTempTestDir;
class ScopedTestAccount final { class ScopedTestAccount final
{
public: public:
/*! /*!
* \brief Create and logs in a new test account * \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 * \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 * \todo make it more flexible by splitting into create account, login and wait for events
*/ */
explicit ScopedTestAccount(const std::string &tempTestSubfolderName, explicit ScopedTestAccount(const std::string& tempTestSubfolderName,
const QString &accountName = defaultAccountName, const QString& accountName = defaultAccountName,
const QString &accountPassword = defaultAccountPassword); const QString& accountPassword = defaultAccountPassword);
~ScopedTestAccount(); ~ScopedTestAccount();
void processMessages(size_t millis, std::function<bool()> shouldWaitUntilTimeout); void processMessages(size_t millis, std::function<bool()> shouldWaitUntilTimeout);
@ -42,10 +45,16 @@ public:
static Accounts::ChatOrWalletAccount firstChatAccount(); static Accounts::ChatOrWalletAccount firstChatAccount();
static Accounts::ChatOrWalletAccount firstWalletAccount(); static Accounts::ChatOrWalletAccount firstWalletAccount();
/// Root account /// Root account
const Status::Onboarding::MultiAccount &loggedInAccount() const; const Status::Onboarding::MultiAccount& loggedInAccount() const;
QString password() const { return m_accountPassword; }; QString password() const
StatusGo::HashedPassword hashedPassword() const { return GoUtils::hashPassword(m_accountPassword); }; {
return m_accountPassword;
};
StatusGo::HashedPassword hashedPassword() const
{
return GoUtils::hashPassword(m_accountPassword);
};
Status::Onboarding::OnboardingController* onboardingController() const; Status::Onboarding::OnboardingController* onboardingController() const;
@ -65,4 +74,4 @@ private:
static constexpr auto defaultAccountPassword = "test_pwd*"; static constexpr auto defaultAccountPassword = "test_pwd*";
}; };
} } // namespace Status::Testing

View File

@ -18,7 +18,7 @@ namespace Status::Testing
class AccountsServiceMock final : public Onboarding::AccountsServiceInterface class AccountsServiceMock final : public Onboarding::AccountsServiceInterface
{ {
public: public:
virtual ~AccountsServiceMock() override {}; virtual ~AccountsServiceMock() override{};
MOCK_METHOD(bool, init, (const fs::path&), (override)); MOCK_METHOD(bool, init, (const fs::path&), (override));
MOCK_METHOD(std::vector<Onboarding::MultiAccount>, openAndListAccounts, (), (override)); MOCK_METHOD(std::vector<Onboarding::MultiAccount>, openAndListAccounts, (), (override));
@ -34,4 +34,4 @@ public:
MOCK_METHOD(void, deleteMultiAccount, (const Onboarding::MultiAccount&), (override)); MOCK_METHOD(void, deleteMultiAccount, (const Onboarding::MultiAccount&), (override));
}; };
} } // namespace Status::Testing

View File

@ -1,7 +1,7 @@
#include "ServiceMock.h" #include "ServiceMock.h"
#include <IOTestHelpers.h>
#include <Constants.h> #include <Constants.h>
#include <IOTestHelpers.h>
#include <StatusGo/Accounts/Accounts.h> #include <StatusGo/Accounts/Accounts.h>
@ -15,7 +15,8 @@ namespace Onboarding = Status::Onboarding;
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace Status::Testing { namespace Status::Testing
{
class AccountsService : public ::testing::Test class AccountsService : public ::testing::Test
{ {
@ -23,19 +24,20 @@ protected:
std::unique_ptr<Onboarding::AccountsService> m_accountsService; std::unique_ptr<Onboarding::AccountsService> m_accountsService;
std::unique_ptr<Testing::AutoCleanTempTestDir> m_fusedTestFolder; std::unique_ptr<Testing::AutoCleanTempTestDir> m_fusedTestFolder;
void SetUp() override { void SetUp() override
{
m_fusedTestFolder = std::make_unique<Testing::AutoCleanTempTestDir>("TestAccountsService"); m_fusedTestFolder = std::make_unique<Testing::AutoCleanTempTestDir>("TestAccountsService");
m_accountsService = std::make_unique<Onboarding::AccountsService>(); m_accountsService = std::make_unique<Onboarding::AccountsService>();
m_accountsService->init(m_fusedTestFolder->tempFolder() / Constants::statusGoDataDirName); m_accountsService->init(m_fusedTestFolder->tempFolder() / Constants::statusGoDataDirName);
} }
void TearDown() override { void TearDown() override
{
m_fusedTestFolder.reset(); m_fusedTestFolder.reset();
m_accountsService.reset(); m_accountsService.reset();
} }
}; };
TEST_F(AccountsService, GeneratedAccounts) TEST_F(AccountsService, GeneratedAccounts)
{ {
auto genAccounts = m_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); auto alias = m_accountsService->generateAlias(testPubKey);
ASSERT_NE(alias, QString("")); ASSERT_NE(alias, QString(""));
} }
} // namespace } // namespace Status::Testing

View File

@ -17,7 +17,8 @@ namespace Onboarding = Status::Onboarding;
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace Status::Testing { namespace Status::Testing
{
class LoginTest : public ::testing::Test class LoginTest : public ::testing::Test
{ {
@ -27,20 +28,24 @@ protected:
std::unique_ptr<Onboarding::AccountsService> m_accountsService; std::unique_ptr<Onboarding::AccountsService> m_accountsService;
std::unique_ptr<Testing::AutoCleanTempTestDir> m_fusedTestFolder; std::unique_ptr<Testing::AutoCleanTempTestDir> m_fusedTestFolder;
static void SetUpTestSuite() { static void SetUpTestSuite()
{
m_accountsServiceMock = std::make_shared<AccountsServiceMock>(); m_accountsServiceMock = std::make_shared<AccountsServiceMock>();
} }
static void TearDownTestSuite() { static void TearDownTestSuite()
{
m_accountsServiceMock.reset(); m_accountsServiceMock.reset();
} }
void SetUp() override { void SetUp() override
{
m_fusedTestFolder = std::make_unique<Testing::AutoCleanTempTestDir>("LoginTest"); m_fusedTestFolder = std::make_unique<Testing::AutoCleanTempTestDir>("LoginTest");
m_accountsService = std::make_unique<Onboarding::AccountsService>(); m_accountsService = std::make_unique<Onboarding::AccountsService>();
m_accountsService->init(m_fusedTestFolder->tempFolder() / Constants::statusGoDataDirName); m_accountsService->init(m_fusedTestFolder->tempFolder() / Constants::statusGoDataDirName);
} }
void TearDown() override { void TearDown() override
{
m_fusedTestFolder.release(); m_fusedTestFolder.release();
m_accountsService.release(); m_accountsService.release();
} }
@ -54,4 +59,4 @@ TEST_F(LoginTest, DISABLED_TestLoginController)
auto controller = Helpers::makeSharedQObject<Onboarding::OnboardingController>(m_accountsServiceMock); auto controller = Helpers::makeSharedQObject<Onboarding::OnboardingController>(m_accountsServiceMock);
} }
} // namespace } // namespace Status::Testing

View File

@ -7,8 +7,8 @@
#include <Onboarding/Accounts/AccountsService.h> #include <Onboarding/Accounts/AccountsService.h>
#include <Onboarding/OnboardingController.h> #include <Onboarding/OnboardingController.h>
#include <StatusGo/SignalsManager.h>
#include <StatusGo/Accounts/Accounts.h> #include <StatusGo/Accounts/Accounts.h>
#include <StatusGo/SignalsManager.h>
#include <ScopedTestAccount.h> #include <ScopedTestAccount.h>
@ -21,7 +21,8 @@ namespace Onboarding = Status::Onboarding;
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace Status::Testing { namespace Status::Testing
{
static std::unique_ptr<Onboarding::AccountsService> m_accountsServiceMock; static std::unique_ptr<Onboarding::AccountsService> m_accountsServiceMock;
@ -89,8 +90,9 @@ TEST(OnboardingModule, TestCreateAndLoginAccountEndToEnd)
using namespace std::chrono_literals; using namespace std::chrono_literals;
auto maxWaitTime = 2000ms; auto maxWaitTime = 2000ms;
auto iterationSleepTime = 2ms; auto iterationSleepTime = 2ms;
auto remainingIterations = maxWaitTime/iterationSleepTime; auto remainingIterations = maxWaitTime / iterationSleepTime;
while (remainingIterations-- > 0 && accountLoggedInCount == 0) { while(remainingIterations-- > 0 && accountLoggedInCount == 0)
{
std::this_thread::sleep_for(iterationSleepTime); std::this_thread::sleep_for(iterationSleepTime);
QCoreApplication::sendPostedEvents(); QCoreApplication::sendPostedEvents();
@ -110,20 +112,23 @@ TEST(OnboardingModule, TestLoginEndToEnd)
// Create test account and login // Create test account and login
// //
bool createAndLogin = false; bool createAndLogin = false;
QObject::connect(StatusGo::SignalsManager::instance(), &StatusGo::SignalsManager::nodeLogin, [&createAndLogin](const QString& error) { QObject::connect(StatusGo::SignalsManager::instance(),
if(error.isEmpty()) { &StatusGo::SignalsManager::nodeLogin,
if(createAndLogin) { [&createAndLogin](const QString& error) {
createAndLogin = false; if(error.isEmpty())
} else {
createAndLogin = true; if(createAndLogin)
} {
}); createAndLogin = false;
}
else
createAndLogin = true;
}
});
constexpr auto accountName = "TestLoginAccountName"; constexpr auto accountName = "TestLoginAccountName";
ScopedTestAccount testAccount(test_info_->name(), accountName); ScopedTestAccount testAccount(test_info_->name(), accountName);
testAccount.processMessages(1000, [createAndLogin]() { testAccount.processMessages(1000, [createAndLogin]() { return !createAndLogin; });
return !createAndLogin;
});
ASSERT_TRUE(createAndLogin); ASSERT_TRUE(createAndLogin);
testAccount.logOut(); testAccount.logOut();
@ -148,14 +153,15 @@ TEST(OnboardingModule, TestLoginEndToEnd)
accountLoggedInCount++; accountLoggedInCount++;
}); });
bool accountLoggedInError = false; bool accountLoggedInError = false;
QObject::connect(onboarding.get(), &Onboarding::OnboardingController::accountLoginError, QObject::connect(onboarding.get(),
&Onboarding::OnboardingController::accountLoginError,
[&accountLoggedInError](const QString& error) { [&accountLoggedInError](const QString& error) {
accountLoggedInError = true; accountLoggedInError = true;
qDebug() << "Failed logging in in test" << test_info_->name() << "with error:" << error; 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()); auto errorString = accountsService->login(*ourAccountRes, testAccount.password());
ASSERT_EQ(errorString.length(), 0); ASSERT_EQ(errorString.length(), 0);
@ -186,13 +192,16 @@ TEST(OnboardingModule, TestLoginEndToEnd_WrongPassword)
}); });
bool accountLoggedInError = false; bool accountLoggedInError = false;
QString loginErrorMessage; QString loginErrorMessage;
QObject::connect(onboarding.get(), &Onboarding::OnboardingController::accountLoginError, QObject::connect(onboarding.get(),
&Onboarding::OnboardingController::accountLoginError,
[&loginErrorMessage, &accountLoggedInError](const QString& error) { [&loginErrorMessage, &accountLoggedInError](const QString& error) {
accountLoggedInError = true; accountLoggedInError = true;
loginErrorMessage = error; 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"); auto errorString = accountsService->login(*ourAccountRes, testAccount.password() + "extra");
ASSERT_EQ(errorString.length(), 0); ASSERT_EQ(errorString.length(), 0);
@ -204,4 +213,4 @@ TEST(OnboardingModule, TestLoginEndToEnd_WrongPassword)
ASSERT_EQ(loginErrorMessage, "file is not a database"); ASSERT_EQ(loginErrorMessage, "file is not a database");
} }
} // namespace } // namespace Status::Testing

View File

@ -7,16 +7,15 @@
const int NUMBER_OF_ADDRESSES_TO_GENERATE = 5; const int NUMBER_OF_ADDRESSES_TO_GENERATE = 5;
const int MNEMONIC_PHRASE_LENGTH = 12; const int MNEMONIC_PHRASE_LENGTH = 12;
namespace Status::StatusGo::Accounts { namespace Status::StatusGo::Accounts
{
RpcResponse<QJsonArray> generateAddresses(const std::vector<Accounts::DerivationPath>& paths) RpcResponse<QJsonArray> generateAddresses(const std::vector<Accounts::DerivationPath>& paths)
{ {
QJsonObject payload{ QJsonObject payload{{"n", NUMBER_OF_ADDRESSES_TO_GENERATE},
{"n", NUMBER_OF_ADDRESSES_TO_GENERATE}, {"mnemonicPhraseLength", MNEMONIC_PHRASE_LENGTH},
{"mnemonicPhraseLength", MNEMONIC_PHRASE_LENGTH}, {"bip32Passphrase", ""},
{"bip32Passphrase", ""}, {"paths", Utils::toJsonArray(paths)}};
{"paths", Utils::toJsonArray(paths)}
};
try try
{ {
@ -30,13 +29,13 @@ RpcResponse<QJsonArray> generateAddresses(const std::vector<Accounts::Derivation
return Utils::buildPrivateRPCResponse(jsonResult); return Utils::buildPrivateRPCResponse(jsonResult);
} }
catch (std::exception& e) catch(std::exception& e)
{ {
auto response = RpcResponse<QJsonArray>(QJsonArray()); auto response = RpcResponse<QJsonArray>(QJsonArray());
response.error.message = QObject::tr("an error generating address occurred, msg: %1").arg(e.what()); response.error.message = QObject::tr("an error generating address occurred, msg: %1").arg(e.what());
return response; return response;
} }
catch (...) catch(...)
{ {
auto response = RpcResponse<QJsonArray>(QJsonArray()); auto response = RpcResponse<QJsonArray>(QJsonArray());
response.error.message = QObject::tr("an error generating address occurred"); response.error.message = QObject::tr("an error generating address occurred");
@ -56,7 +55,7 @@ RpcResponse<QString> generateAlias(const QString& publicKey)
return Utils::buildPrivateRPCResponse(alias); return Utils::buildPrivateRPCResponse(alias);
} }
catch (...) catch(...)
{ {
auto response = RpcResponse<QString>(QString()); auto response = RpcResponse<QString>(QString());
response.error.message = QObject::tr("an error generating alias occurred"); 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{ QJsonObject payload{{"accountID", id}, {"paths", Utils::toJsonArray(paths)}, {"password", password.get()}};
{"accountID", id},
{"paths", Utils::toJsonArray(paths)},
{"password", password.get()}
};
try try
{ {
@ -86,13 +83,13 @@ RpcResponse<QJsonObject> storeDerivedAccounts(const QString& id, const HashedPas
rpcResponse.error = Utils::getRPCErrorInJson(jsonResult).value_or(RpcError()); rpcResponse.error = Utils::getRPCErrorInJson(jsonResult).value_or(RpcError());
return rpcResponse; return rpcResponse;
} }
catch (std::exception& e) catch(std::exception& e)
{ {
auto response = RpcResponse<QJsonObject>(QJsonObject()); auto response = RpcResponse<QJsonObject>(QJsonObject());
response.error.message = QObject::tr("an error storing derived accounts occurred, msg: %1").arg(e.what()); response.error.message = QObject::tr("an error storing derived accounts occurred, msg: %1").arg(e.what());
return response; return response;
} }
catch (...) catch(...)
{ {
auto response = RpcResponse<QJsonObject>(QJsonObject()); auto response = RpcResponse<QJsonObject>(QJsonObject());
response.error.message = QObject::tr("an error storing derived accounts occurred"); 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) RpcResponse<QJsonObject> storeAccount(const QString& id, const HashedPassword& password)
{ {
QJsonObject payload{ QJsonObject payload{{"accountID", id}, {"password", password.get()}};
{"accountID", id},
{"password", password.get()}
};
try try
{ {
@ -121,13 +115,13 @@ RpcResponse<QJsonObject> storeAccount(const QString& id, const HashedPassword& p
rpcResponse.error = Utils::getRPCErrorInJson(jsonResult).value_or(RpcError()); rpcResponse.error = Utils::getRPCErrorInJson(jsonResult).value_or(RpcError());
return rpcResponse; return rpcResponse;
} }
catch (std::exception& e) catch(std::exception& e)
{ {
auto response = RpcResponse<QJsonObject>(QJsonObject()); auto response = RpcResponse<QJsonObject>(QJsonObject());
response.error.message = QObject::tr("an error storing account occurred, msg: %1").arg(e.what()); response.error.message = QObject::tr("an error storing account occurred, msg: %1").arg(e.what());
return response; return response;
} }
catch (...) catch(...)
{ {
auto response = RpcResponse<QJsonObject>(QJsonObject()); auto response = RpcResponse<QJsonObject>(QJsonObject());
response.error.message = QObject::tr("an error storing account occurred"); 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, bool saveAccountAndLogin(const HashedPassword& password,
const QJsonArray& subaccounts, const QJsonObject& settings, const QJsonObject& account,
const QJsonArray& subaccounts,
const QJsonObject& settings,
const QJsonObject& nodeConfig) const QJsonObject& nodeConfig)
{ {
try try
@ -154,9 +150,13 @@ bool saveAccountAndLogin(const HashedPassword& password, const QJsonObject& acco
} }
return !Utils::getRPCErrorInJson(jsonResult).has_value(); 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()); qWarning() << QString("an error saving account and login occurred, msg: %1").arg(e.what());
} catch (...) { }
catch(...)
{
qWarning() << "an error saving account and login occurred"; qWarning() << "an error saving account and login occurred";
} }
return false; return false;
@ -167,24 +167,24 @@ RpcResponse<QJsonArray> openAccounts(const char* dataDirPath)
try try
{ {
auto result = QString(OpenAccounts(const_cast<char*>(dataDirPath))); auto result = QString(OpenAccounts(const_cast<char*>(dataDirPath)));
if(result == "null") if(result == "null") return RpcResponse<QJsonArray>(QJsonArray());
return RpcResponse<QJsonArray>(QJsonArray());
QJsonArray jsonResult; QJsonArray jsonResult;
if(!Utils::checkReceivedResponse(result, jsonResult)) { if(!Utils::checkReceivedResponse(result, jsonResult))
{
throw std::domain_error("parsing response failed"); throw std::domain_error("parsing response failed");
} }
return Utils::buildPrivateRPCResponse(jsonResult); return Utils::buildPrivateRPCResponse(jsonResult);
} }
catch (std::exception& e) catch(std::exception& e)
{ {
auto response = RpcResponse<QJsonArray>(QJsonArray()); auto response = RpcResponse<QJsonArray>(QJsonArray());
// TODO: don't translate exception messages. Exceptions are for developers and should never reach users // 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()); response.error.message = QObject::tr("an error opening accounts occurred, msg: %1").arg(e.what());
return response; return response;
} }
catch (...) catch(...)
{ {
auto response = RpcResponse<QJsonArray>(QJsonArray()); auto response = RpcResponse<QJsonArray>(QJsonArray());
response.error.message = QObject::tr("an error opening accounts occurred"); 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, RpcResponse<QJsonObject> login(const QString& name,
const QString& thumbnail, const QString& large) const QString& keyUid,
const HashedPassword& password,
const QString& thumbnail,
const QString& large)
{ {
QJsonObject payload{ QJsonObject payload{{"name", name}, {"key-uid", keyUid}, {"identityImage", QJsonValue()}};
{"name", name},
{"key-uid", keyUid},
{"identityImage", QJsonValue()}
};
if(!thumbnail.isEmpty() && !large.isEmpty()) if(!thumbnail.isEmpty() && !large.isEmpty())
{ {
@ -219,13 +218,13 @@ RpcResponse<QJsonObject> login(const QString& name, const QString& keyUid, const
return Utils::buildPrivateRPCResponse(jsonResult); return Utils::buildPrivateRPCResponse(jsonResult);
} }
catch (std::exception& e) catch(std::exception& e)
{ {
auto response = RpcResponse<QJsonObject>(QJsonObject()); auto response = RpcResponse<QJsonObject>(QJsonObject());
response.error.message = QObject::tr("an error logining in account occurred, msg: %1").arg(e.what()); response.error.message = QObject::tr("an error logining in account occurred, msg: %1").arg(e.what());
return response; return response;
} }
catch (...) catch(...)
{ {
auto response = RpcResponse<QJsonObject>(QJsonObject()); auto response = RpcResponse<QJsonObject>(QJsonObject());
response.error.message = QObject::tr("an error logining in account occurred"); 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, RpcResponse<QJsonObject> loginWithConfig(const QString& name,
const QString& thumbnail, const QString& large, const QJsonObject& nodeConfig) const QString& keyUid,
const HashedPassword& password,
const QString& thumbnail,
const QString& large,
const QJsonObject& nodeConfig)
{ {
QJsonObject payload{ QJsonObject payload{
{"name", name}, {"name", name},
@ -261,13 +264,13 @@ RpcResponse<QJsonObject> loginWithConfig(const QString& name, const QString& key
return Utils::buildPrivateRPCResponse(jsonResult); return Utils::buildPrivateRPCResponse(jsonResult);
} }
catch (std::exception& e) catch(std::exception& e)
{ {
auto response = RpcResponse<QJsonObject>(QJsonObject()); auto response = RpcResponse<QJsonObject>(QJsonObject());
response.error.message = QObject::tr("an error logining in account occurred, msg: %1").arg(e.what()); response.error.message = QObject::tr("an error logining in account occurred, msg: %1").arg(e.what());
return response; return response;
} }
catch (...) catch(...)
{ {
auto response = RpcResponse<QJsonObject>(QJsonObject()); auto response = RpcResponse<QJsonObject>(QJsonObject());
response.error.message = QObject::tr("an error logining in account occurred"); 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()); rpcResponse.error = Utils::getRPCErrorInJson(jsonResult).value_or(RpcError());
return rpcResponse; return rpcResponse;
} }
catch (std::exception& e) catch(std::exception& e)
{ {
auto response = RpcResponse<QJsonObject>(QJsonObject()); auto response = RpcResponse<QJsonObject>(QJsonObject());
response.error.message = QObject::tr("an error logging out account occurred, msg: %1").arg(e.what()); response.error.message = QObject::tr("an error logging out account occurred, msg: %1").arg(e.what());
return response; return response;
} }
catch (...) catch(...)
{ {
auto response = RpcResponse<QJsonObject>(QJsonObject()); auto response = RpcResponse<QJsonObject>(QJsonObject());
response.error.message = QObject::tr("an error logging out account occurred"); response.error.message = QObject::tr("an error logging out account occurred");
@ -305,4 +308,4 @@ RpcResponse<QJsonObject> logout()
} }
} }
} } // namespace Status::StatusGo::Accounts

View File

@ -7,25 +7,35 @@
namespace Status::StatusGo::Accounts 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, RpcResponse<QJsonObject> storeDerivedAccounts(const QString& accountId,
const std::vector<Accounts::DerivationPath>& paths); 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, bool saveAccountAndLogin(const StatusGo::HashedPassword& password,
const QJsonArray& subaccounts, const QJsonObject& settings, const QJsonObject& account,
const QJsonObject& nodeConfig); const QJsonArray& subaccounts,
const QJsonObject& settings,
const QJsonObject& nodeConfig);
/// opens database and returns accounts list. /// opens database and returns accounts list.
RpcResponse<QJsonArray> openAccounts(const char* dataDirPath); RpcResponse<QJsonArray> openAccounts(const char* dataDirPath);
RpcResponse<QJsonObject> login(const QString& name, const QString& keyUid, const HashedPassword& password, RpcResponse<QJsonObject> login(const QString& name,
const QString& thumbnail, const QString& large); const QString& keyUid,
RpcResponse<QJsonObject> loginWithConfig(const QString& name, const QString& keyUid, const HashedPassword& password, const HashedPassword& password,
const QString& thumbnail, const QString& large, const QJsonObject& nodeConfig); const QString& thumbnail,
RpcResponse<QJsonObject> logout(); 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

View File

@ -1,7 +1,7 @@
#include "AccountsAPI.h" #include "AccountsAPI.h"
#include "Utils.h"
#include "Metadata/api_response.h" #include "Metadata/api_response.h"
#include "Utils.h"
#include <libstatus.h> #include <libstatus.h>
@ -14,13 +14,10 @@ using json = nlohmann::json;
namespace Status::StatusGo::Accounts namespace Status::StatusGo::Accounts
{ {
Accounts::ChatOrWalletAccounts getAccounts() { Accounts::ChatOrWalletAccounts getAccounts()
{
// or even nicer with a raw string literal // or even nicer with a raw string literal
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "accounts_getAccounts"}, {"params", json::array()}};
{"jsonrpc", "2.0"},
{"method", "accounts_getAccounts"},
{"params", json::array()}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
auto resultJson = json::parse(result); auto resultJson = json::parse(result);
@ -29,71 +26,63 @@ Accounts::ChatOrWalletAccounts getAccounts() {
return resultJson.get<CallPrivateRpcResponse>().result; return resultJson.get<CallPrivateRpcResponse>().result;
} }
void generateAccountWithDerivedPath(const HashedPassword &password, const QString &name, const QColor &color, const QString &emoji, void generateAccountWithDerivedPath(const HashedPassword& password,
const DerivationPath &path, const EOAddress &derivedFrom) 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}; std::vector<json> params = {password, name, color, emoji, path, derivedFrom};
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "accounts_generateAccountWithDerivedPath"}, {"params", params}};
{"jsonrpc", "2.0"},
{"method", "accounts_generateAccountWithDerivedPath"},
{"params", params}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
auto resultJson = json::parse(result); auto resultJson = json::parse(result);
checkPrivateRpcCallResultAndReportError(resultJson); checkPrivateRpcCallResultAndReportError(resultJson);
} }
void addAccountWithMnemonicAndPath(const QString &mnemonic, const HashedPassword &password, const QString &name, void addAccountWithMnemonicAndPath(const QString& mnemonic,
const QColor &color, const QString &emoji, const DerivationPath &path) 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}; std::vector<json> params = {mnemonic, password, name, color, emoji, path};
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "accounts_addAccountWithMnemonicAndPath"}, {"params", params}};
{"jsonrpc", "2.0"},
{"method", "accounts_addAccountWithMnemonicAndPath"},
{"params", params}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
auto resultJson = json::parse(result); auto resultJson = json::parse(result);
checkPrivateRpcCallResultAndReportError(resultJson); 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}; std::vector<json> params = {address, name, color, emoji};
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "accounts_addAccountWatch"}, {"params", params}};
{"jsonrpc", "2.0"},
{"method", "accounts_addAccountWatch"},
{"params", params}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
auto resultJson = json::parse(result); auto resultJson = json::parse(result);
checkPrivateRpcCallResultAndReportError(resultJson); checkPrivateRpcCallResultAndReportError(resultJson);
} }
void deleteAccount(const EOAddress &address) void deleteAccount(const EOAddress& address)
{ {
std::vector<json> params = {address}; std::vector<json> params = {address};
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "accounts_deleteAccount"}, {"params", params}};
{"jsonrpc", "2.0"},
{"method", "accounts_deleteAccount"},
{"params", params}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
auto resultJson = json::parse(result); auto resultJson = json::parse(result);
checkPrivateRpcCallResultAndReportError(resultJson); 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 // 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); auto resultJson = json::parse(result);
checkApiError(resultJson); checkApiError(resultJson);
} }
} } // namespace Status::StatusGo::Accounts

View File

@ -5,8 +5,8 @@
#include "Accounts/ChatOrWalletAccount.h" #include "Accounts/ChatOrWalletAccount.h"
#include "Accounts/accounts_types.h" #include "Accounts/accounts_types.h"
#include <vector>
#include <filesystem> #include <filesystem>
#include <vector>
namespace Accounts = Status::StatusGo::Accounts; 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 /// \note the underlying status-go API, SaveAccounts@accounts.go, returns `nil` for \c CallPrivateRpcResponse.result
/// \see \c getAccounts /// \see \c getAccounts
/// \throws \c CallPrivateRpcError /// \throws \c CallPrivateRpcError
void generateAccountWithDerivedPath(const HashedPassword &password, const QString &name, void generateAccountWithDerivedPath(const HashedPassword& password,
const QColor &color, const QString &emoji, const QString& name,
const DerivationPath &path, const Accounts::EOAddress &derivedFrom); const QColor& color,
const QString& emoji,
const DerivationPath& path,
const Accounts::EOAddress& derivedFrom);
/// \brief Add a new account from an existing mnemonic /// \brief Add a new account from an existing mnemonic
/// \note the underlying status-go api, SaveAccounts@accounts.go, returns `nil` for \c CallPrivateRpcResponse.result /// \note the underlying status-go api, SaveAccounts@accounts.go, returns `nil` for \c CallPrivateRpcResponse.result
/// \see \c getAccounts /// \see \c getAccounts
/// \throws \c CallPrivateRpcError /// \throws \c CallPrivateRpcError
void addAccountWithMnemonicAndPath(const QString &mnemonic, const HashedPassword &password, const QString &name, void addAccountWithMnemonicAndPath(const QString& mnemonic,
const QColor &color, const QString &emoji, const DerivationPath &path); const HashedPassword& password,
const QString& name,
const QColor& color,
const QString& emoji,
const DerivationPath& path);
/// \brief Add a watch only account /// \brief Add a watch only account
/// \note the underlying status-go api, SaveAccounts@accounts.go, returns `nil` for \c CallPrivateRpcResponse.result /// \note the underlying status-go api, SaveAccounts@accounts.go, returns `nil` for \c CallPrivateRpcResponse.result
/// \see \c getAccounts /// \see \c getAccounts
/// \throws \c CallPrivateRpcError /// \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 /// \brief Delete an existing account
/// \note the underlying status-go api, DeleteAccount@accounts.go, returns `os.Remove(keyFile)` /// \note the underlying status-go api, DeleteAccount@accounts.go, returns `os.Remove(keyFile)`
/// \see \c getAccounts /// \see \c getAccounts
/// \throws \c CallPrivateRpcError /// \throws \c CallPrivateRpcError
void deleteAccount(const EOAddress &address); void deleteAccount(const EOAddress& address);
/// \brief Delete an existing account /// \brief Delete an existing account
/// \note the underlying status-go api, DeleteAccount@accounts.go, returns `os.Remove(keyFile)` /// \note the underlying status-go api, DeleteAccount@accounts.go, returns `os.Remove(keyFile)`
/// \see \c getAccounts /// \see \c getAccounts
/// \throws \c CallPrivateRpcError /// \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

View File

@ -1,27 +1,30 @@
#include "ChatOrWalletAccount.h" #include "ChatOrWalletAccount.h"
namespace Status::StatusGo::Accounts { namespace Status::StatusGo::Accounts
{
void to_json(json& j, const ChatOrWalletAccount& d) { void to_json(json& j, const ChatOrWalletAccount& d)
j = {{"address", d.address}, {
{"chat", d.isChat}, j = {
{"clock", d.clock}, {"address", d.address},
{"color", d.color}, {"chat", d.isChat},
{"emoji", d.emoji}, {"clock", d.clock},
{"hidden", d.isHidden}, {"color", d.color},
{"mixedcase-address", d.mixedcaseAddress}, {"emoji", d.emoji},
{"name", d.name}, {"hidden", d.isHidden},
{"path", d.path}, {"mixedcase-address", d.mixedcaseAddress},
{"public-key", d.publicKey}, {"name", d.name},
{"removed", d.isRemoved}, {"path", d.path},
{"wallet", d.isWallet}, {"public-key", d.publicKey},
{"removed", d.isRemoved},
{"wallet", d.isWallet},
}; };
if(d.derivedFrom != std::nullopt) if(d.derivedFrom != std::nullopt) j["derived-from"] = d.derivedFrom.value();
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("address").get_to(d.address);
j.at("chat").get_to(d.isChat); j.at("chat").get_to(d.isChat);
j.at("clock").get_to(d.clock); 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); j.at("wallet").get_to(d.isWallet);
constexpr auto pathKey = "path"; constexpr auto pathKey = "path";
if(j.contains(pathKey)) if(j.contains(pathKey)) j.at(pathKey).get_to(d.path);
j.at(pathKey).get_to(d.path);
constexpr auto publicKeyKey = "public-key"; constexpr auto publicKeyKey = "public-key";
if(j.contains(publicKeyKey)) if(j.contains(publicKeyKey)) j.at(publicKeyKey).get_to(d.publicKey);
j.at(publicKeyKey).get_to(d.publicKey);
if(d.isWallet && !j.at("derived-from").get<std::string>().empty()) if(d.isWallet && !j.at("derived-from").get<std::string>().empty())
d.derivedFrom = j.at("derived-from").get<std::optional<EOAddress>>(); d.derivedFrom = j.at("derived-from").get<std::optional<EOAddress>>();
} }
} } // namespace Status::StatusGo::Accounts

View File

@ -12,8 +12,8 @@
using json = nlohmann::json; using json = nlohmann::json;
namespace Status::StatusGo::Accounts { namespace Status::StatusGo::Accounts
{
/// \brief Unique wallet account entity /// \brief Unique wallet account entity
/// \note equivalent of status-go's accounts.Account@multiaccounts/accounts/database.go /// \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 to_json(json& j, const ChatOrWalletAccount& d);
void from_json(const json& j, ChatOrWalletAccount& d); void from_json(const json& j, ChatOrWalletAccount& d);
} } // namespace Status::StatusGo::Accounts

View File

@ -7,10 +7,11 @@
using json = nlohmann::json; using json = nlohmann::json;
/// Defines phantom types for strong typing /// 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 /// The 20 byte address of an Ethereum account prefixed with 0x
using EOAddress = Helpers::NamedType<QString, struct EOAddressTag>; using EOAddress = Helpers::NamedType<QString, struct EOAddressTag>;
using DerivationPath = Helpers::NamedType<QString, struct DerivationPathTag>; using DerivationPath = Helpers::NamedType<QString, struct DerivationPathTag>;
} } // namespace Status::StatusGo::Accounts

View File

@ -1,7 +1,7 @@
#include "ChatAPI.h" #include "ChatAPI.h"
#include "Utils.h"
#include "Metadata/api_response.h" #include "Metadata/api_response.h"
#include "Utils.h"
#include <libstatus.h> #include <libstatus.h>
@ -13,11 +13,7 @@ using namespace Status::StatusGo;
Chats::AllChannelGroupsDto Chats::getChats() Chats::AllChannelGroupsDto Chats::getChats()
{ {
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "chat_getChats"}, {"params", json::array()}};
{"jsonrpc", "2.0"},
{"method", "chat_getChats"},
{"params", json::array()}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
const auto resultJson = json::parse(result); const auto resultJson = json::parse(result);

View File

@ -4,6 +4,6 @@
namespace Status::StatusGo::Chats namespace Status::StatusGo::Chats
{ {
/// \brief Retrieve all available channel groups /// \brief Retrieve all available channel groups
AllChannelGroupsDto getChats(); AllChannelGroupsDto getChats();
} } // namespace Status::StatusGo::Chats

View File

@ -1,105 +1,118 @@
#include "ChatDto.h" #include "ChatDto.h"
#include <Helpers/conversions.h>
#include <Helpers/JsonMacros.h> #include <Helpers/JsonMacros.h>
#include <Helpers/conversions.h>
using namespace Status::StatusGo; using namespace Status::StatusGo;
void Chats::to_json(json& j, const Category& d) { void Chats::to_json(json& j, const Category& d)
j = {{"id", d.id}, {
{"name", d.name}, j = {
{"position", d.position}, {"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(name)
STATUS_READ_NLOHMAN_JSON_PROPERTY(position) STATUS_READ_NLOHMAN_JSON_PROPERTY(position)
STATUS_READ_NLOHMAN_JSON_PROPERTY(id, "category_id", false) 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) STATUS_READ_NLOHMAN_JSON_PROPERTY(id, "id", false)
} }
} }
void Chats::to_json(json& j, const Permission& d) { void Chats::to_json(json& j, const Permission& d)
j = {{"access", d.access}, {
{"ens_only", d.ensOnly}, 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(access, "access", false)
STATUS_READ_NLOHMAN_JSON_PROPERTY(ensOnly, "ens_only", false) STATUS_READ_NLOHMAN_JSON_PROPERTY(ensOnly, "ens_only", false)
} }
void Chats::to_json(json& j, const Images& d) { void Chats::to_json(json& j, const Images& d)
j = {{"large", d.large}, {
{"thumbnail", d.thumbnail}, j = {
{"banner", d.banner}, {"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"; constexpr auto large = "large";
if(j.contains(large)) if(j.contains(large)) j[large].at("uri").get_to(d.large);
j[large].at("uri").get_to(d.large);
constexpr auto thumbnail = "thumbnail"; constexpr auto thumbnail = "thumbnail";
if(j.contains(thumbnail)) if(j.contains(thumbnail)) j[thumbnail].at("uri").get_to(d.thumbnail);
j[thumbnail].at("uri").get_to(d.thumbnail);
constexpr auto banner = "banner"; constexpr auto banner = "banner";
if(j.contains(banner)) if(j.contains(banner)) j[banner].at("uri").get_to(d.banner);
j[banner].at("uri").get_to(d.banner);
} }
void Chats::to_json(json& j, const ChatMember& d) { void Chats::to_json(json& j, const ChatMember& d)
j = {{"id", d.id}, {
{"admin", d.admin}, j = {
{"joined", d.joined}, {"id", d.id},
{"roles", d.roles}, {"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(id)
STATUS_READ_NLOHMAN_JSON_PROPERTY(joined) STATUS_READ_NLOHMAN_JSON_PROPERTY(joined)
STATUS_READ_NLOHMAN_JSON_PROPERTY(roles) STATUS_READ_NLOHMAN_JSON_PROPERTY(roles)
STATUS_READ_NLOHMAN_JSON_PROPERTY(admin, "admin", false) STATUS_READ_NLOHMAN_JSON_PROPERTY(admin, "admin", false)
} }
void Chats::to_json(json& j, const ChatDto& d) { void Chats::to_json(json& j, const ChatDto& d)
j = {{"id", d.id}, {
{"name", d.name}, j = {
{"description", d.description}, {"id", d.id},
{"color", d.color}, {"name", d.name},
{"emoji", d.emoji}, {"description", d.description},
{"active", d.active}, {"color", d.color},
{"timestamp", d.timestamp}, {"emoji", d.emoji},
{"lastClockValue", d.lastClockValue}, {"active", d.active},
{"deletedAtClockValue", d.deletedAtClockValue}, {"timestamp", d.timestamp},
{"readMessagesAtClockValue", d.readMessagesAtClockValue}, {"lastClockValue", d.lastClockValue},
{"unviewedMessagesCount", d.unviewedMessagesCount}, {"deletedAtClockValue", d.deletedAtClockValue},
{"unviewedMentionsCount", d.unviewedMentionsCount}, {"readMessagesAtClockValue", d.readMessagesAtClockValue},
{"canPost", d.canPost}, {"unviewedMessagesCount", d.unviewedMessagesCount},
{"alias", d.alias}, {"unviewedMentionsCount", d.unviewedMentionsCount},
{"identicon", d.icon}, {"canPost", d.canPost},
{"muted", d.muted}, {"alias", d.alias},
{"position", d.position}, {"identicon", d.icon},
{"communityId", d.communityId}, {"muted", d.muted},
{"profile", d.profile}, {"position", d.position},
{"joined", d.joined}, {"communityId", d.communityId},
{"syncedTo", d.syncedTo}, {"profile", d.profile},
{"syncedFrom", d.syncedFrom}, {"joined", d.joined},
{"highlight", d.highlight}, {"syncedTo", d.syncedTo},
{"categoryId", d.categoryId}, {"syncedFrom", d.syncedFrom},
{"permissions", d.permissions}, {"highlight", d.highlight},
{"chatType", d.chatType}, {"categoryId", d.categoryId},
{"members", d.members}, {"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(id)
STATUS_READ_NLOHMAN_JSON_PROPERTY(name) STATUS_READ_NLOHMAN_JSON_PROPERTY(name)
STATUS_READ_NLOHMAN_JSON_PROPERTY(description) 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(chatType)
STATUS_READ_NLOHMAN_JSON_PROPERTY(categoryId, "categoryId", false) STATUS_READ_NLOHMAN_JSON_PROPERTY(categoryId, "categoryId", false)
if (!j.contains("categoryId")) { if(!j.contains("categoryId"))
{
// Communities have `categoryID` and chats have `categoryId` // Communities have `categoryID` and chats have `categoryId`
// This should be fixed in status-go, but would be a breaking change // This should be fixed in status-go, but would be a breaking change
STATUS_READ_NLOHMAN_JSON_PROPERTY(categoryId, "categoryID", false) STATUS_READ_NLOHMAN_JSON_PROPERTY(categoryId, "categoryID", false)
} }
// Add community ID if needed // 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; d.id = d.communityId + d.id;
} }
constexpr auto membersKey = "members"; constexpr auto membersKey = "members";
if (j.contains(membersKey)) { if(j.contains(membersKey))
if (j[membersKey].is_array()) { {
if(j[membersKey].is_array())
{
j.at(membersKey).get_to(d.members); j.at(membersKey).get_to(d.members);
} }
else if (j[membersKey].is_object()) { else if(j[membersKey].is_object())
{
auto obj = j[membersKey]; 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; ChatMember chatMember;
it.value().get_to(chatMember); it.value().get_to(chatMember);
chatMember.id = it.key().c_str(); 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) { void Chats::to_json(json& j, const ChannelGroupDto& d)
j = {{"id", d.id}, {
{"admin", d.admin}, j = {
{"verified", d.verified}, {"id", d.id},
{"name", d.name}, {"admin", d.admin},
{"description", d.description}, {"verified", d.verified},
{"introMessage", d.introMessage}, {"name", d.name},
{"outroMessage", d.outroMessage}, {"description", d.description},
{"canManageUsers", d.canManageUsers}, {"introMessage", d.introMessage},
{"color", d.color}, {"outroMessage", d.outroMessage},
{"muted", d.muted}, {"canManageUsers", d.canManageUsers},
{"images", d.images}, {"color", d.color},
{"permissions", d.permissions}, {"muted", d.muted},
{"channelGroupType", d.channelGroupType}, {"images", d.images},
{"chats", d.chats}, {"permissions", d.permissions},
{"categories", d.categories}, {"channelGroupType", d.channelGroupType},
{"members", d.members}, {"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(admin)
STATUS_READ_NLOHMAN_JSON_PROPERTY(verified) STATUS_READ_NLOHMAN_JSON_PROPERTY(verified)
STATUS_READ_NLOHMAN_JSON_PROPERTY(name) 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(permissions, "permissions", false)
STATUS_READ_NLOHMAN_JSON_PROPERTY(channelGroupType) STATUS_READ_NLOHMAN_JSON_PROPERTY(channelGroupType)
if (d.channelGroupType.isEmpty()) if(d.channelGroupType.isEmpty()) d.channelGroupType = ChannelGroupTypeUnknown;
d.channelGroupType = ChannelGroupTypeUnknown;
constexpr auto chats = "chats"; constexpr auto chats = "chats";
if (j.contains(chats)) { if(j.contains(chats))
{
auto obj = j[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; ChatDto chatDto;
it.value().get_to(chatDto); it.value().get_to(chatDto);
d.chats.emplace_back(std::move(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"; constexpr auto categories = "categories";
if (j.contains(categories)) { if(j.contains(categories))
{
auto obj = j[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; Category category;
it.value().get_to(category); it.value().get_to(category);
d.categories.emplace_back(std::move(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"; constexpr auto membersKey = "members";
if (j.contains(membersKey)) { if(j.contains(membersKey))
if (j[membersKey].is_object()) { {
if(j[membersKey].is_object())
{
auto obj = j[membersKey]; 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; ChatMember chatMember;
it.value().get_to(chatMember); it.value().get_to(chatMember);
chatMember.id = it.key().c_str(); 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}}; j = {{"id", d.allChannelGroups}};
} }
void Chats::from_json(const json& j, AllChannelGroupsDto& d) { void Chats::from_json(const json& j, AllChannelGroupsDto& d)
for (json::const_iterator it = j.cbegin(); it != j.cend(); ++it) { {
for(json::const_iterator it = j.cbegin(); it != j.cend(); ++it)
{
ChannelGroupDto channelGroupDto; ChannelGroupDto channelGroupDto;
it.value().get_to(channelGroupDto); it.value().get_to(channelGroupDto);
channelGroupDto.id = it.key().c_str(); channelGroupDto.id = it.key().c_str();
d.allChannelGroups.emplace_back(std::move(channelGroupDto)); d.allChannelGroups.emplace_back(std::move(channelGroupDto));
} }
} }

View File

@ -8,125 +8,135 @@
using json = nlohmann::json; using json = nlohmann::json;
namespace Status::StatusGo::Chats { namespace Status::StatusGo::Chats
{
constexpr auto ChannelGroupTypeUnknown = "unknown"; constexpr auto ChannelGroupTypeUnknown = "unknown";
constexpr auto ChannelGroupTypePersonal = "personal"; constexpr auto ChannelGroupTypePersonal = "personal";
constexpr auto ChannelGroupTypeCommunity = "community"; constexpr auto ChannelGroupTypeCommunity = "community";
enum ChatType enum ChatType
{ {
Unknown = 0, Unknown = 0,
OneToOne = 1, OneToOne = 1,
Public = 2, Public = 2,
PrivateGroupChat = 3, PrivateGroupChat = 3,
Profile = 4, Profile = 4,
CommunityChat = 6 CommunityChat = 6
}; };
struct Category { struct Category
QString id; {
QString name; QString id;
int position; QString name;
}; int position;
};
struct Permission { struct Permission
int access; {
bool ensOnly; int access;
}; bool ensOnly;
};
struct Images { struct Images
QString thumbnail; {
QString large; QString thumbnail;
QString banner; QString large;
}; QString banner;
};
struct ChatMember { struct ChatMember
QString id; {
bool admin; QString id;
bool joined; bool admin;
std::vector<int> roles; bool joined;
}; std::vector<int> roles;
};
struct ChatDto { 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 QString id; // ID is the id of the chat, for public chats it is the name e.g. status,
// uuid appended with the hex encoded pk of the creator of the chat // for one-to-one is the hex encoded public key and for group chats is a random
QString name; // uuid appended with the hex encoded pk of the creator of the chat
QString description; QString name;
QColor color; QString description;
QString emoji; QColor color;
bool active; // indicates whether the chat has been soft deleted QString emoji;
ChatType chatType; bool active; // indicates whether the chat has been soft deleted
quint64 timestamp; // indicates the last time this chat has received/sent a message ChatType chatType;
quint64 lastClockValue; // indicates the last clock value to be used when sending messages quint64 timestamp; // indicates the last time this chat has received/sent a message
quint64 deletedAtClockValue; // indicates the clock value at time of deletion, messages with lower clock value of this should be discarded quint64 lastClockValue; // indicates the last clock value to be used when sending messages
quint64 readMessagesAtClockValue; quint64
int unviewedMessagesCount; deletedAtClockValue; // indicates the clock value at time of deletion, messages with lower clock value of this should be discarded
int unviewedMentionsCount; quint64 readMessagesAtClockValue;
std::vector<ChatMember> members; int unviewedMessagesCount;
QString alias; int unviewedMentionsCount;
QString icon; std::vector<ChatMember> members;
bool muted; QString alias;
QString communityId; // set if chat belongs to a community QString icon;
QString profile; bool muted;
quint64 joined; // indicates when the user joined the chat last time QString communityId; // set if chat belongs to a community
quint64 syncedTo; QString profile;
quint64 syncedFrom; quint64 joined; // indicates when the user joined the chat last time
bool canPost; quint64 syncedTo;
int position; quint64 syncedFrom;
QString categoryId; bool canPost;
bool highlight; int position;
Permission permissions; QString categoryId;
}; bool highlight;
Permission permissions;
};
struct ChannelGroupDto { struct ChannelGroupDto
QString id; {
QString channelGroupType; QString id;
bool admin; QString channelGroupType;
bool verified; bool admin;
QString name; bool verified;
QString ensName; QString name;
QString description; QString ensName;
QString introMessage; QString description;
QString outroMessage; QString introMessage;
std::vector<ChatDto> chats; QString outroMessage;
std::vector<Category> categories; std::vector<ChatDto> chats;
Images images; std::vector<Category> categories;
Permission permissions; Images images;
std::vector<ChatMember> members; Permission permissions;
bool canManageUsers; std::vector<ChatMember> members;
QColor color; bool canManageUsers;
bool muted; QColor color;
bool historyArchiveSupportEnabled; bool muted;
bool pinMessageAllMembersEnabled; bool historyArchiveSupportEnabled;
}; bool pinMessageAllMembersEnabled;
};
struct AllChannelGroupsDto { struct AllChannelGroupsDto
std::vector<ChannelGroupDto> allChannelGroups; {
}; std::vector<ChannelGroupDto> allChannelGroups;
};
NLOHMANN_JSON_SERIALIZE_ENUM(ChatType, { NLOHMANN_JSON_SERIALIZE_ENUM(ChatType,
{Unknown, "Unknown"}, {
{OneToOne, "OneToOne"}, {Unknown, "Unknown"},
{Public, "Public"}, {OneToOne, "OneToOne"},
{PrivateGroupChat, "PrivateGroupChat"}, {Public, "Public"},
{Profile, "Profile"}, {PrivateGroupChat, "PrivateGroupChat"},
{CommunityChat, "CommunityChat"}, {Profile, "Profile"},
}) {CommunityChat, "CommunityChat"},
})
void to_json(json& j, const Category& d); void to_json(json& j, const Category& d);
void from_json(const json& j, Category& d); void from_json(const json& j, Category& d);
void to_json(json& j, const Permission& d); void to_json(json& j, const Permission& d);
void from_json(const json& j, Permission& d); void from_json(const json& j, Permission& d);
void to_json(json& j, const Images& d); void to_json(json& j, const Images& d);
void from_json(const json& j, Images& d); void from_json(const json& j, Images& d);
void to_json(json& j, const ChatMember& d); void to_json(json& j, const ChatMember& d);
void from_json(const json& j, ChatMember& d); void from_json(const json& j, ChatMember& d);
void to_json(json& j, const ChatDto& d); void to_json(json& j, const ChatDto& d);
void from_json(const json& j, ChatDto& d); void from_json(const json& j, ChatDto& d);
void to_json(json& j, const ChannelGroupDto& d); void to_json(json& j, const ChannelGroupDto& d);
void from_json(const json& j, ChannelGroupDto& d); void from_json(const json& j, ChannelGroupDto& d);
void to_json(json& j, const AllChannelGroupsDto& d); void to_json(json& j, const AllChannelGroupsDto& d);
void from_json(const json& j, AllChannelGroupsDto& d); void from_json(const json& j, AllChannelGroupsDto& d);
} } // namespace Status::StatusGo::Chats

View File

@ -13,13 +13,14 @@ RpcResponse<QJsonObject> initKeystore(const char* keystoreDir)
{ {
auto result = InitKeystore(const_cast<char*>(keystoreDir)); auto result = InitKeystore(const_cast<char*>(keystoreDir));
QJsonObject jsonResult; QJsonObject jsonResult;
if(!Utils::checkReceivedResponse(result, jsonResult)) { if(!Utils::checkReceivedResponse(result, jsonResult))
{
throw std::domain_error("parsing response failed"); throw std::domain_error("parsing response failed");
} }
return Utils::buildPrivateRPCResponse(jsonResult); return Utils::buildPrivateRPCResponse(jsonResult);
} }
catch (std::exception& e) catch(std::exception& e)
{ {
// TODO: either use optional/smartpointers or exceptions instead of plain objects // TODO: either use optional/smartpointers or exceptions instead of plain objects
auto response = RpcResponse<QJsonObject>(QJsonObject()); 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()); response.error.message = QObject::tr("an error opening accounts occurred, msg: %1").arg(e.what());
return response; return response;
} }
catch (...) catch(...)
{ {
auto response = RpcResponse<QJsonObject>(QJsonObject()); auto response = RpcResponse<QJsonObject>(QJsonObject());
response.error.message = QObject::tr("an error opening accounts occurred"); response.error.message = QObject::tr("an error opening accounts occurred");
@ -35,4 +36,4 @@ RpcResponse<QJsonObject> initKeystore(const char* keystoreDir)
} }
} }
} } // namespace Status::StatusGo::General

View File

@ -7,11 +7,7 @@ namespace Status::StatusGo::Messenger
bool startMessenger() bool startMessenger()
{ {
QJsonObject payload{ QJsonObject payload{{"jsonrpc", "2.0"}, {"method", "wakuext_startMessenger"}, {"params", QJsonArray()}};
{"jsonrpc", "2.0"},
{"method", "wakuext_startMessenger"},
{"params", QJsonArray()}
};
auto callResult = Utils::callPrivateRpc<QJsonObject>(Utils::jsonToByteArray(payload)); auto callResult = Utils::callPrivateRpc<QJsonObject>(Utils::jsonToByteArray(payload));
if(callResult.containsError()) if(callResult.containsError())
@ -19,4 +15,4 @@ bool startMessenger()
return !callResult.containsError(); return !callResult.containsError();
} }
} } // namespace Status::StatusGo::Messenger

View File

@ -1,25 +1,28 @@
#include "api_response.h" #include "api_response.h"
namespace Status::StatusGo { namespace Status::StatusGo
{
void checkApiError(const json &response) { void checkApiError(const json& response)
if(response.contains("error")) { {
const auto &error = response["error"]; if(response.contains("error"))
if(error.is_object()) { {
const auto& error = response["error"];
if(error.is_object())
{
const auto apiErr = response["error"].get<ApiErrorResponseWithCode>(); const auto apiErr = response["error"].get<ApiErrorResponseWithCode>();
throw CallGenericPrepareJsonError(apiErr); throw CallGenericPrepareJsonError(apiErr);
} }
assert(error.is_string()); assert(error.is_string());
const auto apiError = response.get<ApiErrorResponse>(); const auto apiError = response.get<ApiErrorResponse>();
if(!apiError.error.empty()) if(!apiError.error.empty()) throw CallGenericMakeJsonError(response.get<ApiErrorResponse>());
throw CallGenericMakeJsonError(response.get<ApiErrorResponse>());
} }
} }
/// \throws \c CallPrivateRpcError, \c nlohmann::exception /// \throws \c CallPrivateRpcError, \c nlohmann::exception
void checkPrivateRpcCallResultAndReportError(const json &response) { void checkPrivateRpcCallResultAndReportError(const json& response)
if(response.contains("error")) {
throw CallPrivateRpcError(response.get<CallPrivateRpcErrorResponse>()); if(response.contains("error")) throw CallPrivateRpcError(response.get<CallPrivateRpcErrorResponse>());
} }
} // namespace } // namespace Status::StatusGo

View File

@ -8,7 +8,8 @@
using json = nlohmann::json; using json = nlohmann::json;
namespace Status::StatusGo { namespace Status::StatusGo
{
/*! /*!
* \brief General API response if an internal status-go error occured * \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 * \note update NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE when changing structure's content
*/ */
struct ApiErrorResponse { struct ApiErrorResponse
{
std::string error; 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 * \note update NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE when changing structure's content
*/ */
struct JsonError { struct JsonError
{
int code{0}; int code{0};
std::string message; std::string message;
}; };
@ -45,7 +48,8 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(JsonError, code, message)
* \see jsonrpcSuccessfulResponse@response.go * \see jsonrpcSuccessfulResponse@response.go
* \note update NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE when changing structure's content * \note update NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE when changing structure's content
*/ */
struct ApiErrorResponseWithCode { struct ApiErrorResponseWithCode
{
JsonError error; 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 * \note update NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE when changing structure's content
*/ */
struct ApiResponse { struct ApiResponse
{
json result; json result;
}; };
@ -116,38 +121,53 @@ void checkApiError(const json& response);
constexpr int defaultErrorCode = -32000; constexpr int defaultErrorCode = -32000;
class CallGenericMakeJsonError: public std::runtime_error { class CallGenericMakeJsonError : public std::runtime_error
{
public: public:
CallGenericMakeJsonError(const ApiErrorResponse error) CallGenericMakeJsonError(const ApiErrorResponse error)
: std::runtime_error("CallGenericMakeJsonError@status-go failed") : std::runtime_error("CallGenericMakeJsonError@status-go failed")
, m_error(std::move(error)) , m_error(std::move(error))
{} { }
const ApiErrorResponse& errorResponse() const
{
return m_error;
};
const ApiErrorResponse &errorResponse() const { return m_error; };
private: private:
const ApiErrorResponse m_error; const ApiErrorResponse m_error;
}; };
class CallGenericPrepareJsonError: public std::runtime_error { class CallGenericPrepareJsonError : public std::runtime_error
{
public: public:
CallGenericPrepareJsonError(const ApiErrorResponseWithCode error) CallGenericPrepareJsonError(const ApiErrorResponseWithCode error)
: std::runtime_error("CallGenericPrepareJsonError@status-go failed") : std::runtime_error("CallGenericPrepareJsonError@status-go failed")
, m_error(std::move(error)) , m_error(std::move(error))
{} { }
const ApiErrorResponseWithCode& errorResponse() const
{
return m_error;
};
const ApiErrorResponseWithCode &errorResponse() const { return m_error; };
private: private:
const ApiErrorResponseWithCode m_error; const ApiErrorResponseWithCode m_error;
}; };
class CallPrivateRpcError: public std::runtime_error { class CallPrivateRpcError : public std::runtime_error
{
public: public:
CallPrivateRpcError(const CallPrivateRpcErrorResponse error) CallPrivateRpcError(const CallPrivateRpcErrorResponse error)
: std::runtime_error("CallPrivateRPC@status-go failed") : std::runtime_error("CallPrivateRPC@status-go failed")
, m_error(std::move(error)) , m_error(std::move(error))
{} { }
const CallPrivateRpcErrorResponse& errorResponse() const
{
return m_error;
};
const CallPrivateRpcErrorResponse &errorResponse() const { return m_error; };
private: private:
const CallPrivateRpcErrorResponse m_error; const CallPrivateRpcErrorResponse m_error;
}; };
@ -160,4 +180,4 @@ private:
*/ */
void checkPrivateRpcCallResultAndReportError(const json& response); void checkPrivateRpcCallResultAndReportError(const json& response);
} } // namespace Status::StatusGo

View File

@ -1,7 +1,7 @@
#include "SettingsAPI.h" #include "SettingsAPI.h"
#include "Utils.h"
#include "Metadata/api_response.h" #include "Metadata/api_response.h"
#include "Utils.h"
#include <libstatus.h> #include <libstatus.h>
@ -13,11 +13,7 @@ using namespace Status::StatusGo;
Settings::SettingsDto Settings::getSettings() Settings::SettingsDto Settings::getSettings()
{ {
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "settings_getSettings"}, {"params", json::array()}};
{"jsonrpc", "2.0"},
{"method", "settings_getSettings"},
{"params", json::array()}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
const auto resultJson = json::parse(result); const auto resultJson = json::parse(result);

View File

@ -4,6 +4,6 @@
namespace Status::StatusGo::Settings namespace Status::StatusGo::Settings
{ {
/// \brief Retrieve settings /// \brief Retrieve settings
SettingsDto getSettings(); SettingsDto getSettings();
} } // namespace Status::StatusGo::Settings

View File

@ -1,20 +1,23 @@
#include "SettingsDto.h" #include "SettingsDto.h"
#include <Helpers/conversions.h>
#include <Helpers/JsonMacros.h> #include <Helpers/JsonMacros.h>
#include <Helpers/conversions.h>
using namespace Status::StatusGo; using namespace Status::StatusGo;
void Settings::to_json(json& j, const SettingsDto& d) { void Settings::to_json(json& j, const SettingsDto& d)
j = {{"address", d.address}, {
{"display-name", d.displayName}, j = {
{"preferred-name", d.preferredName}, {"address", d.address},
{"key-uid", d.keyUid}, {"display-name", d.displayName},
{"public-key", d.publicKey}, {"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(address)
STATUS_READ_NLOHMAN_JSON_PROPERTY(displayName, "display-name") STATUS_READ_NLOHMAN_JSON_PROPERTY(displayName, "display-name")
STATUS_READ_NLOHMAN_JSON_PROPERTY(preferredName, "preferred-name", false) STATUS_READ_NLOHMAN_JSON_PROPERTY(preferredName, "preferred-name", false)

View File

@ -8,16 +8,18 @@
using json = nlohmann::json; using json = nlohmann::json;
namespace Status::StatusGo::Settings { namespace Status::StatusGo::Settings
{
struct SettingsDto { struct SettingsDto
QString address; {
QString displayName; QString address;
QString preferredName; QString displayName;
QString keyUid; QString preferredName;
QString publicKey; QString keyUid;
}; QString publicKey;
};
void to_json(json& j, const SettingsDto& d); void to_json(json& j, const SettingsDto& d);
void from_json(const json& j, SettingsDto& d); void from_json(const json& j, SettingsDto& d);
} } // namespace Status::StatusGo::Settings

View File

@ -6,7 +6,8 @@
using namespace std::string_literals; using namespace std::string_literals;
namespace Status::StatusGo { namespace Status::StatusGo
{
std::map<std::string, SignalType> SignalsManager::signalMap; std::map<std::string, SignalType> SignalsManager::signalMap;
@ -22,29 +23,25 @@ SignalsManager::SignalsManager()
{ {
SetSignalEventCallback((void*)&SignalsManager::signalCallback); SetSignalEventCallback((void*)&SignalsManager::signalCallback);
signalMap = { signalMap = {{"node.ready"s, SignalType::NodeReady},
{"node.ready"s, SignalType::NodeReady}, {"node.started"s, SignalType::NodeStarted},
{"node.started"s, SignalType::NodeStarted}, {"node.stopped"s, SignalType::NodeStopped},
{"node.stopped"s, SignalType::NodeStopped}, {"node.login"s, SignalType::NodeLogin},
{"node.login"s, SignalType::NodeLogin}, {"node.crashed"s, SignalType::NodeCrashed},
{"node.crashed"s, SignalType::NodeCrashed},
{"discovery.started"s, SignalType::DiscoveryStarted}, {"discovery.started"s, SignalType::DiscoveryStarted},
{"discovery.stopped"s, SignalType::DiscoveryStopped}, {"discovery.stopped"s, SignalType::DiscoveryStopped},
{"discovery.summary"s, SignalType::DiscoverySummary}, {"discovery.summary"s, SignalType::DiscoverySummary},
{"mailserver.changed"s, SignalType::MailserverChanged}, {"mailserver.changed"s, SignalType::MailserverChanged},
{"mailserver.available"s, SignalType::MailserverAvailable}, {"mailserver.available"s, SignalType::MailserverAvailable},
{"history.request.started"s, SignalType::HistoryRequestStarted}, {"history.request.started"s, SignalType::HistoryRequestStarted},
{"history.request.batch.processed"s, SignalType::HistoryRequestBatchProcessed}, {"history.request.batch.processed"s, SignalType::HistoryRequestBatchProcessed},
{"history.request.completed"s, SignalType::HistoryRequestCompleted} {"history.request.completed"s, SignalType::HistoryRequestCompleted}};
};
} }
SignalsManager::~SignalsManager() SignalsManager::~SignalsManager() { }
{
}
void SignalsManager::processSignal(const QString& statusSignal) void SignalsManager::processSignal(const QString& statusSignal)
{ {
@ -82,46 +79,22 @@ void SignalsManager::decode(const QJsonObject& signalEvent)
switch(signalType) switch(signalType)
{ {
// TODO: create extractor functions like in nim // TODO: create extractor functions like in nim
case NodeLogin: case NodeLogin: emit nodeLogin(signalError); break;
emit nodeLogin(signalError); case NodeReady: emit nodeReady(signalError); break;
break; case NodeStarted: emit nodeStarted(signalError); break;
case NodeReady: case NodeStopped: emit nodeStopped(signalError); break;
emit nodeReady(signalError);
break;
case NodeStarted:
emit nodeStarted(signalError);
break;
case NodeStopped:
emit nodeStopped(signalError);
break;
case NodeCrashed: case NodeCrashed:
qWarning() << "node.crashed, error: " << signalError; qWarning() << "node.crashed, error: " << signalError;
emit nodeCrashed(signalError); emit nodeCrashed(signalError);
break; break;
case DiscoveryStarted: case DiscoveryStarted: emit discoveryStarted(signalError); break;
emit discoveryStarted(signalError); case DiscoveryStopped: emit discoveryStopped(signalError); break;
break; case DiscoverySummary: emit discoverySummary(signalEvent["event"].toArray().count(), signalError); break;
case DiscoveryStopped: case MailserverChanged: emit mailserverChanged(signalError); break;
emit discoveryStopped(signalError); case MailserverAvailable: emit mailserverAvailable(signalError); break;
break; case HistoryRequestStarted: emit historyRequestStarted(signalError); break;
case DiscoverySummary: case HistoryRequestBatchProcessed: emit historyRequestBatchProcessed(signalError); break;
emit discoverySummary(signalEvent["event"].toArray().count(), signalError); case HistoryRequestCompleted: emit historyRequestCompleted(signalError); break;
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; case Unknown: assert(false); break;
} }
} }
@ -130,9 +103,8 @@ void SignalsManager::signalCallback(const char* data)
{ {
// TODO: overkill, use some kind of message broker // TODO: overkill, use some kind of message broker
auto dataStrPtr = std::make_shared<QString>(data); auto dataStrPtr = std::make_shared<QString>(data);
QFuture<void> future = QtConcurrent::run([dataStrPtr](){ QFuture<void> future =
SignalsManager::instance()->processSignal(*dataStrPtr); QtConcurrent::run([dataStrPtr]() { SignalsManager::instance()->processSignal(*dataStrPtr); });
});
} }
} } // namespace Status::StatusGo

View File

@ -2,7 +2,8 @@
#include <QObject> #include <QObject>
namespace Status::StatusGo { namespace Status::StatusGo
{
enum SignalType enum SignalType
{ {
@ -35,7 +36,6 @@ class SignalsManager final : public QObject
Q_OBJECT Q_OBJECT
public: public:
static SignalsManager* instance(); static SignalsManager* instance();
void processSignal(const QString& ev); void processSignal(const QString& ev);
@ -57,6 +57,7 @@ signals:
void historyRequestStarted(const QString& error); void historyRequestStarted(const QString& error);
void historyRequestBatchProcessed(const QString& error); void historyRequestBatchProcessed(const QString& error);
void historyRequestCompleted(const QString& error); void historyRequestCompleted(const QString& error);
private: private:
explicit SignalsManager(); explicit SignalsManager();
~SignalsManager(); ~SignalsManager();
@ -67,4 +68,4 @@ private:
void decode(const QJsonObject& signalEvent); void decode(const QJsonObject& signalEvent);
}; };
} } // namespace Status::StatusGo

View File

@ -30,18 +30,20 @@ struct RpcResponse
int id; int id;
RpcError error; RpcError error;
explicit explicit RpcResponse(T result,
RpcResponse(T result, QString version = RpcError::UnknownVersion, int id = RpcError::UnknownId, QString version = RpcError::UnknownVersion,
RpcError error = RpcError()) int id = RpcError::UnknownId,
RpcError error = RpcError())
: result(std::move(result)) : result(std::move(result))
, jsonRpcVersion(std::move(version)) , jsonRpcVersion(std::move(version))
, id(id) , id(id)
, error(std::move(error)) , error(std::move(error))
{ } { }
bool containsError() const { bool containsError() const
{
return !error.message.isEmpty() || error.code != RpcError::NoError; return !error.message.isEmpty() || error.code != RpcError::NoError;
} }
}; };
} } // namespace Status::StatusGo

View File

@ -15,35 +15,35 @@ QJsonArray toJsonArray(const std::vector<Accounts::DerivationPath>& value)
return array; 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 // Evil done here! status-go API doesn't follow the proper const conventions
return CallPrivateRPC(const_cast<char*>(inputJSON)); 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? // 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(), return HashedPassword(
QCryptographicHash::Keccak_256).toHex().toUpper())); "0x" +
QString::fromUtf8(QCryptographicHash::hash(str.toUtf8(), QCryptographicHash::Keccak_256).toHex().toUpper()));
} }
std::optional<RpcError> getRPCErrorInJson(const QJsonObject& json) std::optional<RpcError> getRPCErrorInJson(const QJsonObject& json)
{ {
auto errVal = json[Param::Error]; auto errVal = json[Param::Error];
if (errVal.isNull() || errVal.isUndefined()) if(errVal.isNull() || errVal.isUndefined()) return std::nullopt;
return std::nullopt; if(errVal.isString() && errVal.toString().length() == 0) return std::nullopt;
if(errVal.isString() && errVal.toString().length() == 0)
return std::nullopt;
RpcError response; RpcError response;
auto errObj = json[Param::Id].toObject(); 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(); 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(); response.message = errObj[Param::ErrorMessage].toString();
else else
response.message = errVal.toString(); response.message = errVal.toString();
return response; return response;
} }
} } // namespace Status::StatusGo::Utils

View File

@ -1,29 +1,30 @@
#pragma once #pragma once
#include "Types.h"
#include "Accounts/accounts_types.h" #include "Accounts/accounts_types.h"
#include "Types.h"
#include <QJsonArray>
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
#include <QJsonArray>
namespace Status::StatusGo::Utils namespace Status::StatusGo::Utils
{ {
namespace Param { namespace Param
static constexpr auto Id{"id"}; {
static constexpr auto JsonRpc{"jsonrpc"}; static constexpr auto Id{"id"};
static constexpr auto Result{"result"}; static constexpr auto JsonRpc{"jsonrpc"};
static constexpr auto Error{"error"}; static constexpr auto Result{"result"};
static constexpr auto ErrorMessage{"message"}; static constexpr auto Error{"error"};
static constexpr auto ErrorCode{"code"}; static constexpr auto ErrorMessage{"message"};
} static constexpr auto ErrorCode{"code"};
} // namespace Param
template<class T> template <class T>
QByteArray jsonToByteArray(const T& json) QByteArray jsonToByteArray(const T& json)
{ {
static_assert(std::is_same_v<T, QJsonObject> || static_assert(std::is_same_v<T, QJsonObject> || std::is_same_v<T, QJsonArray>,
std::is_same_v<T, QJsonArray>, "Wrong Json type. Supported: Object, Array"); "Wrong Json type. Supported: Object, Array");
return QJsonDocument(json).toJson(QJsonDocument::Compact); 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 /// Check if json contains a standard status-go error and
std::optional<RpcError> getRPCErrorInJson(const QJsonObject& json); std::optional<RpcError> getRPCErrorInJson(const QJsonObject& json);
template<class T> template <class T>
bool checkReceivedResponse(const QString& response, T& json) bool checkReceivedResponse(const QString& response, T& json)
{ {
QJsonParseError error; QJsonParseError error;
auto jsonDocument = QJsonDocument::fromJson(response.toUtf8(), &error); auto jsonDocument = QJsonDocument::fromJson(response.toUtf8(), &error);
if (error.error != QJsonParseError::NoError) if(error.error != QJsonParseError::NoError) return false;
return false;
if constexpr (std::is_same_v<T, QJsonObject>) if constexpr(std::is_same_v<T, QJsonObject>)
{ {
json = jsonDocument.object(); json = jsonDocument.object();
return true; return true;
} }
else if constexpr (std::is_same_v<T, QJsonArray>) else if constexpr(std::is_same_v<T, QJsonArray>)
{ {
json = jsonDocument.array(); json = jsonDocument.array();
return true; 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. // 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) RpcResponse<T> buildPrivateRPCResponse(const T& json)
{ {
auto response = RpcResponse<T>(T()); 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()) if(!json[Param::Id].isNull() && !json[Param::Id].isUndefined()) response.id = json[Param::Id].toInt();
response.id = json[Param::Id].toInt();
if (!json[Param::JsonRpc].isNull() && !json[Param::JsonRpc].isUndefined()) if(!json[Param::JsonRpc].isNull() && !json[Param::JsonRpc].isUndefined())
response.jsonRpcVersion = json[Param::JsonRpc].toString(); 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()) if(!json[Param::Result].isNull() && !json[Param::Result].isUndefined())
response.result = json[Param::Result].toObject(); 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; response.result = json;
} }
@ -83,7 +82,7 @@ RpcResponse<T> buildPrivateRPCResponse(const T& json)
const char* statusGoCallPrivateRPC(const char* inputJSON); const char* statusGoCallPrivateRPC(const char* inputJSON);
template<class T> template <class T>
RpcResponse<T> callPrivateRpc(const QByteArray& payload) RpcResponse<T> callPrivateRpc(const QByteArray& payload)
{ {
try try
@ -98,13 +97,13 @@ RpcResponse<T> callPrivateRpc(const QByteArray& payload)
return Utils::buildPrivateRPCResponse(jsonResult); return Utils::buildPrivateRPCResponse(jsonResult);
} }
catch (std::exception& e) catch(std::exception& e)
{ {
auto response = RpcResponse<T>(T()); auto response = RpcResponse<T>(T());
response.error.message = QObject::tr("an error executing rpc call occurred, msg: %1").arg(e.what()); response.error.message = QObject::tr("an error executing rpc call occurred, msg: %1").arg(e.what());
return response; return response;
} }
catch (...) catch(...)
{ {
auto response = RpcResponse<T>(T()); auto response = RpcResponse<T>(T());
response.error.message = QObject::tr("an error executing rpc call"); 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

View File

@ -1,42 +1,42 @@
#include "BigInt.h" #include "BigInt.h"
#include <locale>
#include <iostream> #include <iostream>
#include <locale>
#include <Helpers/helpers.h> #include <Helpers/helpers.h>
namespace Status { namespace Status
namespace StatusGo::Wallet { {
namespace StatusGo::Wallet
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)));
}
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; using namespace QtLiterals;
bool has0xPrefix(const QByteArray &in) { bool has0xPrefix(const QByteArray& in)
{
return in.size() >= 2 && Helpers::iequals(in.first(2), "0x"_qba); 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()); auto data = QByteArray::fromRawData(value.c_str(), value.size());
if (!has0xPrefix(data)) if(!has0xPrefix(data)) throw std::runtime_error("BigInt::parseHex missing 0x prefix");
throw std::runtime_error("BigInt::parseHex missing 0x prefix"); if(data.size() == 2) throw std::runtime_error("BigInt::parseHex empty number");
if (data.size() == 2) if(data.size() > 3 && data[2] == '0') throw std::runtime_error("BigInt::parseHex leading zero");
throw std::runtime_error("BigInt::parseHex empty number"); if(data.size() > 66) throw std::runtime_error("BigInt::parseHex more than 256 bits");
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()}; return BigInt{data.data()};
} }
} // namespace StatusGo::Wallet } // 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)); return QString::fromStdString(num.str(0, std::ios_base::dec));
} }

View File

@ -11,37 +11,43 @@
using json = nlohmann::json; using json = nlohmann::json;
namespace Status { namespace Status
namespace StatusGo::Wallet { {
namespace StatusGo::Wallet
{
using BigInt = boost::multiprecision::uint256_t; using BigInt = boost::multiprecision::uint256_t;
/// Converts into the 0x prefixed hexadecimal display required by status-go (also uppercase) /// 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 /// \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) /// or value is higher than 2^64 (numbers larger than 256 bits are not accepted)
/// \see toHexData /// \see toHexData
BigInt parseHex(const std::string &value); BigInt parseHex(const std::string& value);
} } // namespace StatusGo::Wallet
/// Human readable form /// 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; namespace GoWallet = Status::StatusGo::Wallet;
template<> template <>
struct adl_serializer<GoWallet::BigInt> { struct adl_serializer<GoWallet::BigInt>
static void to_json(json& j, const GoWallet::BigInt& num) { {
static void to_json(json& j, const GoWallet::BigInt& num)
{
j = GoWallet::toHexData(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>()); num = GoWallet::BigInt(j.get<std::string>());
} }
}; };

View File

@ -14,7 +14,8 @@ namespace Accounts = Status::StatusGo::Accounts;
using json = nlohmann::json; using json = nlohmann::json;
namespace Status::StatusGo::Wallet { namespace Status::StatusGo::Wallet
{
/// \brief Define a derived address as returned by the corresponding API /// \brief Define a derived address as returned by the corresponding API
/// \note equivalent of status-go's DerivedAddress@api.go /// \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); NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(DerivedAddress, address, path, hasActivity, alreadyCreated);
} } // namespace Status::StatusGo::Wallet

View File

@ -12,7 +12,8 @@
using json = nlohmann::json; using json = nlohmann::json;
/// \note not sure if this is the best namespace, ok for now /// \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) /// \note equivalent of status-go's Network@config.go (params package)
struct NetworkConfiguration struct NetworkConfiguration
@ -34,9 +35,19 @@ struct NetworkConfiguration
using NetworkConfigurations = std::vector<NetworkConfiguration>; using NetworkConfigurations = std::vector<NetworkConfiguration>;
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(NetworkConfiguration, chainId, chainName, rpcUrl, blockExplorerUrl, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(NetworkConfiguration,
iconUrl, nativeCurrencyName, nativeCurrencySymbol, chainId,
nativeCurrencyDecimals, isTest, layer, enabled, chainColor, chainName,
rpcUrl,
blockExplorerUrl,
iconUrl,
nativeCurrencyName,
nativeCurrencySymbol,
nativeCurrencyDecimals,
isTest,
layer,
enabled,
chainColor,
shortName); shortName);
} } // namespace Status::StatusGo::Wallet

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "wallet_types.h"
#include "Accounts/accounts_types.h" #include "Accounts/accounts_types.h"
#include "wallet_types.h"
#include <Helpers/conversions.h> #include <Helpers/conversions.h>
@ -11,7 +11,8 @@
namespace Accounts = Status::StatusGo::Accounts; 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 /// \brief Define a saved wallet address as returned by the corresponding API
/// \note equivalent of status-go's SavedAddress@api.go /// \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); NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SavedAddress, address, name, favourite, chainId);
} } // namespace Status::StatusGo::Wallet

View File

@ -14,24 +14,24 @@ namespace Accounts = Status::StatusGo::Accounts;
using json = nlohmann::json; using json = nlohmann::json;
namespace Status::StatusGo::Wallet { namespace Status::StatusGo::Wallet
{
/// \note equivalent of status-go's Token@token.go /// \note equivalent of status-go's Token@token.go
/// \see \c getDerivedAddressesForPath /// \see \c getDerivedAddressesForPath
struct Token struct Token
{ {
Accounts::EOAddress address; Accounts::EOAddress address;
QString name; QString name;
QString symbol; QString symbol;
QColor color; QColor color;
unsigned int decimals; unsigned int decimals;
ChainID chainId; ChainID chainId;
}; };
using TokenPtr = std::shared_ptr<Token>; using TokenPtr = std::shared_ptr<Token>;
using Tokens = std::vector<Token>; using Tokens = std::vector<Token>;
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Token, address, name,symbol, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Token, address, name, symbol, color, decimals, chainId);
color, decimals, chainId);
} } // namespace Status::StatusGo::Wallet

View File

@ -1,7 +1,7 @@
#include "WalletApi.h" #include "WalletApi.h"
#include "Utils.h"
#include "Metadata/api_response.h" #include "Metadata/api_response.h"
#include "Utils.h"
#include "Accounts/accounts_types.h" #include "Accounts/accounts_types.h"
@ -18,14 +18,14 @@ using json = nlohmann::json;
namespace Status::StatusGo::Wallet 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}; std::vector<json> params = {password, derivedFrom, path, pageSize, pageNumber};
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "wallet_getDerivedAddressesForPath"}, {"params", params}};
{"jsonrpc", "2.0"},
{"method", "wallet_getDerivedAddressesForPath"},
{"params", params}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
const auto resultJson = json::parse(result); const auto resultJson = json::parse(result);
@ -36,27 +36,20 @@ DerivedAddresses getDerivedAddressesForPath(const HashedPassword &password, cons
SavedAddresses getSavedAddresses() SavedAddresses getSavedAddresses()
{ {
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "wallet_getSavedAddresses"}};
{"jsonrpc", "2.0"},
{"method", "wallet_getSavedAddresses"}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
const auto resultJson = json::parse(result); const auto resultJson = json::parse(result);
checkPrivateRpcCallResultAndReportError(resultJson); checkPrivateRpcCallResultAndReportError(resultJson);
const auto &data = resultJson.get<CallPrivateRpcResponse>().result; const auto& data = resultJson.get<CallPrivateRpcResponse>().result;
return data.is_null() ? json::array() : data; return data.is_null() ? json::array() : data;
} }
void saveAddress(const SavedAddress &address) void saveAddress(const SavedAddress& address)
{ {
std::vector<json> params = { address }; std::vector<json> params = {address};
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "wakuext_upsertSavedAddress"}, {"params", params}};
{"jsonrpc", "2.0"},
{"method", "wakuext_upsertSavedAddress"},
{"params", params}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
auto resultJson = json::parse(result); auto resultJson = json::parse(result);
@ -66,64 +59,53 @@ void saveAddress(const SavedAddress &address)
NetworkConfigurations getEthereumChains(bool onlyEnabled) NetworkConfigurations getEthereumChains(bool onlyEnabled)
{ {
std::vector<json> params = {onlyEnabled}; std::vector<json> params = {onlyEnabled};
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "wallet_getEthereumChains"}, {"params", params}};
{"jsonrpc", "2.0"},
{"method", "wallet_getEthereumChains"},
{"params", params}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
const auto resultJson = json::parse(result); const auto resultJson = json::parse(result);
checkPrivateRpcCallResultAndReportError(resultJson); checkPrivateRpcCallResultAndReportError(resultJson);
const auto &data = resultJson.get<CallPrivateRpcResponse>().result; const auto& data = resultJson.get<CallPrivateRpcResponse>().result;
return data.is_null() ? json::array() : data; return data.is_null() ? json::array() : data;
} }
Tokens getTokens(const ChainID &chainId) Tokens getTokens(const ChainID& chainId)
{ {
std::vector<json> params = {chainId}; std::vector<json> params = {chainId};
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "wallet_getTokens"}, {"params", params}};
{"jsonrpc", "2.0"},
{"method", "wallet_getTokens"},
{"params", params}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
const auto resultJson = json::parse(result); const auto resultJson = json::parse(result);
checkPrivateRpcCallResultAndReportError(resultJson); checkPrivateRpcCallResultAndReportError(resultJson);
const auto &data = resultJson.get<CallPrivateRpcResponse>().result; const auto& data = resultJson.get<CallPrivateRpcResponse>().result;
return data.is_null() ? json::array() : data; 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> accounts,
const std::vector<Accounts::EOAddress> tokens) const std::vector<Accounts::EOAddress> tokens)
{ {
std::vector<json> params = {chainIds, accounts, tokens}; std::vector<json> params = {chainIds, accounts, tokens};
json inputJson = { json inputJson = {{"jsonrpc", "2.0"}, {"method", "wallet_getTokensBalancesForChainIDs"}, {"params", params}};
{"jsonrpc", "2.0"},
{"method", "wallet_getTokensBalancesForChainIDs"},
{"params", params}
};
auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str()); auto result = Utils::statusGoCallPrivateRPC(inputJson.dump().c_str());
const auto resultJson = json::parse(result); const auto resultJson = json::parse(result);
checkPrivateRpcCallResultAndReportError(resultJson); checkPrivateRpcCallResultAndReportError(resultJson);
TokenBalances resultData; 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 // Workaround to exception "type must be array, but is object" for custom key-types
// TODO: find out why // TODO: find out why
std::map<std::string, std::map<std::string, BigInt>> dataMap = data.is_null() ? nlohmann::json() : data; 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; 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); val.emplace(QString::fromStdString(valIt.first), valIt.second);
resultData.emplace(QString::fromStdString(keyIt.first), std::move(val)); resultData.emplace(QString::fromStdString(keyIt.first), std::move(val));
} }
return resultData; return resultData;
} }
} // namespaces } // namespace Status::StatusGo::Wallet

View File

@ -6,8 +6,8 @@
#include "DerivedAddress.h" #include "DerivedAddress.h"
#include "NetworkConfiguration.h" #include "NetworkConfiguration.h"
#include "Token.h"
#include "SavedAddress.h" #include "SavedAddress.h"
#include "Token.h"
#include "Types.h" #include "Types.h"
@ -20,10 +20,11 @@ namespace Status::StatusGo::Wallet
/// \brief Retrieve a list of derived account addresses /// \brief Retrieve a list of derived account addresses
/// \see \c generateAccountWithDerivedPath /// \see \c generateAccountWithDerivedPath
/// \throws \c CallPrivateRpcError /// \throws \c CallPrivateRpcError
DerivedAddresses getDerivedAddressesForPath(const HashedPassword &password, DerivedAddresses getDerivedAddressesForPath(const HashedPassword& password,
const Accounts::EOAddress &derivedFrom, const Accounts::EOAddress& derivedFrom,
const Accounts::DerivationPath &path, const Accounts::DerivationPath& path,
int pageSize, int pageNumber); int pageSize,
int pageNumber);
/// \brief Retrieve a list of saved wallet addresses /// \brief Retrieve a list of saved wallet addresses
/// \see \c getSavedAddresses /// \see \c getSavedAddresses
@ -33,7 +34,7 @@ SavedAddresses getSavedAddresses();
/// \brief Add a new or update existing saved wallet address /// \brief Add a new or update existing saved wallet address
/// \see wakuext_upsertSavedAddress RPC method /// \see wakuext_upsertSavedAddress RPC method
/// \throws \c CallPrivateRpcError /// \throws \c CallPrivateRpcError
void saveAddress(const SavedAddress &address); void saveAddress(const SavedAddress& address);
/// \note status-go's GetEthereumChains@api.go which calls /// \note status-go's GetEthereumChains@api.go which calls
/// NetworkManager@client.go -> network.Manager.get() /// NetworkManager@client.go -> network.Manager.get()
@ -46,15 +47,14 @@ NetworkConfigurations getEthereumChains(bool onlyEnabled);
/// \throws \c CallPrivateRpcError for general RPC call failure /// \throws \c CallPrivateRpcError for general RPC call failure
NetworkConfigurations getEthereumChains(bool onlyEnabled); NetworkConfigurations getEthereumChains(bool onlyEnabled);
/// \note status-go's GetTokens@api.go -> TokenManager.getTokens@token.go /// \note status-go's GetTokens@api.go -> TokenManager.getTokens@token.go
/// \throws \c CallPrivateRpcError with /// \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>>; using TokenBalances = std::map<Accounts::EOAddress, std::map<Accounts::EOAddress, BigInt>>;
/// \note status-go's @api.go -> <xx>@<xx>.go /// \note status-go's @api.go -> <xx>@<xx>.go
/// \throws \c CallPrivateRpcError /// \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> accounts,
const std::vector<Accounts::EOAddress> tokens); const std::vector<Accounts::EOAddress> tokens);
} // namespaces } // namespace Status::StatusGo::Wallet

View File

@ -3,13 +3,13 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <QString> #include <QString>
using json = nlohmann::json; using json = nlohmann::json;
/// Defines phantom types for strong typing /// Defines phantom types for strong typing
namespace Status::StatusGo::Wallet { namespace Status::StatusGo::Wallet
{
using ChainID = Helpers::NamedType<unsigned long long int, struct ChainIDTag>; using ChainID = Helpers::NamedType<unsigned long long int, struct ChainIDTag>;

View File

@ -6,7 +6,8 @@
using json = nlohmann::json; using json = nlohmann::json;
namespace StatusGo = Status::StatusGo; namespace StatusGo = Status::StatusGo;
namespace Status::Testing { namespace Status::Testing
{
TEST(StatusGoQt, TestJsonParsing) TEST(StatusGoQt, TestJsonParsing)
{ {
@ -19,13 +20,15 @@ TEST(StatusGoQt, TestJsonParsing)
ASSERT_EQ(callRawRPCJson.error.message, expectedJsonError.message); ASSERT_EQ(callRawRPCJson.error.message, expectedJsonError.message);
auto callRawRPCBadJsonKeyStr = R"({"unknown":"2.0","id":42,"error":{"code":-32601,"message":"Method not found"}})"; 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})"; 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 statusGoWithResultJsonStr = R"({"result":"0x123"})";
auto statusGoWithResultJson = json::parse(statusGoWithResultJsonStr).get<StatusGo::ApiResponse>(); auto statusGoWithResultJson = json::parse(statusGoWithResultJsonStr).get<StatusGo::ApiResponse>();
ASSERT_EQ(statusGoWithResultJson.result, "0x123"); ASSERT_EQ(statusGoWithResultJson.result, "0x123");
} }
} // namespace } // namespace Status::Testing

View File

@ -4,7 +4,8 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace Status::Testing { namespace Status::Testing
{
fs::path createTestFolder(const std::string& testName) fs::path createTestFolder(const std::string& testName)
{ {
@ -12,14 +13,13 @@ fs::path createTestFolder(const std::string& testName)
auto tm = *std::localtime(&t); auto tm = *std::localtime(&t);
std::ostringstream timeOss; std::ostringstream timeOss;
timeOss << std::put_time(&tm, "%d-%m-%Y_%H-%M-%S"); 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)) : m_testFolder(createTestFolder(testName))
{ {
if(createDir) if(createDir) fs::create_directories(m_testFolder);
fs::create_directories(m_testFolder);
} }
AutoCleanTempTestDir::~AutoCleanTempTestDir() AutoCleanTempTestDir::~AutoCleanTempTestDir()
@ -33,4 +33,4 @@ const std::filesystem::path& AutoCleanTempTestDir::tempFolder()
return m_testFolder; return m_testFolder;
} }
} } // namespace Status::Testing

View File

@ -4,9 +4,11 @@
#include <string> #include <string>
namespace Status::Testing { namespace Status::Testing
{
class AutoCleanTempTestDir { class AutoCleanTempTestDir
{
public: public:
/// Creates a temporary folder to be used in tests. The folder content's will /// Creates a temporary folder to be used in tests. The folder content's will
/// be removed when out of scope /// be removed when out of scope
@ -19,4 +21,4 @@ private:
const std::filesystem::path m_testFolder; const std::filesystem::path m_testFolder;
}; };
} } // namespace Status::Testing

View File

@ -3,13 +3,13 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
namespace Status::Testing { namespace Status::Testing
{
std::weak_ptr<QString> MonitorQtOutput::m_qtMessageOutputForSharing; std::weak_ptr<QString> MonitorQtOutput::m_qtMessageOutputForSharing;
std::mutex MonitorQtOutput::m_mutex; std::mutex MonitorQtOutput::m_mutex;
QtMessageHandler MonitorQtOutput::m_previousHandler = nullptr; QtMessageHandler MonitorQtOutput::m_previousHandler = nullptr;
MonitorQtOutput::MonitorQtOutput() MonitorQtOutput::MonitorQtOutput()
{ {
// Ensure only one instance registers a handler // Ensure only one instance registers a handler
@ -17,13 +17,14 @@ MonitorQtOutput::MonitorQtOutput()
std::unique_lock<std::mutex> localLock(m_mutex); std::unique_lock<std::mutex> localLock(m_mutex);
auto globalMsgOut = m_qtMessageOutputForSharing.lock(); auto globalMsgOut = m_qtMessageOutputForSharing.lock();
auto prev = qInstallMessageHandler(qtMessageOutput); auto prev = qInstallMessageHandler(qtMessageOutput);
if(prev != qtMessageOutput) if(prev != qtMessageOutput) m_previousHandler = prev;
m_previousHandler = prev; if(!globalMsgOut)
if(!globalMsgOut) { {
m_thisMessageOutput = std::make_shared<QString>(); m_thisMessageOutput = std::make_shared<QString>();
m_qtMessageOutputForSharing = m_thisMessageOutput; m_qtMessageOutputForSharing = m_thisMessageOutput;
} }
else { else
{
m_thisMessageOutput = globalMsgOut; m_thisMessageOutput = globalMsgOut;
m_start = m_thisMessageOutput->length(); m_start = m_thisMessageOutput->length();
} }
@ -32,15 +33,15 @@ MonitorQtOutput::MonitorQtOutput()
MonitorQtOutput::~MonitorQtOutput() MonitorQtOutput::~MonitorQtOutput()
{ {
std::unique_lock<std::mutex> localLock(m_mutex); 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 // Last instance, deregister the handler
qInstallMessageHandler(0); qInstallMessageHandler(0);
m_thisMessageOutput.reset(); m_thisMessageOutput.reset();
} }
} }
void void MonitorQtOutput::qtMessageOutput(QtMsgType type, const QMessageLogContext& context, const QString& msg)
MonitorQtOutput::qtMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{ {
std::unique_lock<std::mutex> localLock(m_mutex); std::unique_lock<std::mutex> localLock(m_mutex);
auto globalMsgOut = m_qtMessageOutputForSharing.lock(); auto globalMsgOut = m_qtMessageOutputForSharing.lock();
@ -50,23 +51,20 @@ MonitorQtOutput::qtMessageOutput(QtMsgType type, const QMessageLogContext &conte
m_previousHandler(type, context, msg); m_previousHandler(type, context, msg);
} }
QString QString MonitorQtOutput::qtOuput()
MonitorQtOutput::qtOuput()
{ {
std::unique_lock<std::mutex> localLock(m_mutex); std::unique_lock<std::mutex> localLock(m_mutex);
assert(m_thisMessageOutput->length() >= m_start); assert(m_thisMessageOutput->length() >= m_start);
return m_thisMessageOutput->right(m_thisMessageOutput->length() - m_start); return m_thisMessageOutput->right(m_thisMessageOutput->length() - m_start);
} }
void void MonitorQtOutput::restartCapturing()
MonitorQtOutput::restartCapturing()
{ {
std::unique_lock<std::mutex> localLock(m_mutex); std::unique_lock<std::mutex> localLock(m_mutex);
// Ensure the messageHandler is installed. Foun to be reset at test initializaiton // Ensure the messageHandler is installed. Foun to be reset at test initializaiton
auto prev = qInstallMessageHandler(qtMessageOutput); auto prev = qInstallMessageHandler(qtMessageOutput);
if(prev != qtMessageOutput) if(prev != qtMessageOutput) m_previousHandler = prev;
m_previousHandler = prev;
m_start = m_thisMessageOutput->length(); m_start = m_thisMessageOutput->length();
} }
} } // namespace Status::Testing

View File

@ -6,7 +6,8 @@
#include <memory> #include <memory>
#include <mutex> #include <mutex>
namespace Status::Testing { namespace Status::Testing
{
/// ///
/// \brief Monitor output for tests and declaratively control message handler availability /// \brief Monitor output for tests and declaratively control message handler availability
@ -36,7 +37,7 @@ public:
signals: signals:
private: 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; static QtMessageHandler m_previousHandler;
// Use it to keep track of qInstallMessageHandler call // Use it to keep track of qInstallMessageHandler call
@ -46,4 +47,4 @@ private:
int m_start = 0; int m_start = 0;
}; };
} } // namespace Status::Testing

View File

@ -7,7 +7,8 @@
#include <QtQmlIntegration> #include <QtQmlIntegration>
namespace Status::Wallet { namespace Status::Wallet
{
/// Controlls asset for an account using hardcoded network and token lists /// 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 impliement \c AccountsBalanceService to fetch and cache realtime balance (or better implement this in status-go)
/// \todo implement native token fetching /// \todo implement native token fetching
/// \todo double responsibility, split functionality in asset management and balance /// \todo double responsibility, split functionality in asset management and balance
class AccountAssetsController: public QObject class AccountAssetsController : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT

View File

@ -6,7 +6,8 @@
namespace WalletGo = Status::StatusGo::Wallet; namespace WalletGo = Status::StatusGo::Wallet;
namespace Status::Wallet { namespace Status::Wallet
{
class DerivedWalletAddress : public QObject class DerivedWalletAddress : public QObject
{ {
@ -18,11 +19,14 @@ class DerivedWalletAddress : public QObject
Q_PROPERTY(bool alreadyCreated READ alreadyCreated CONSTANT) Q_PROPERTY(bool alreadyCreated READ alreadyCreated CONSTANT)
public: public:
explicit DerivedWalletAddress(WalletGo::DerivedAddress address, QObject *parent = nullptr); explicit DerivedWalletAddress(WalletGo::DerivedAddress address, QObject* parent = nullptr);
QString address() const; QString address() const;
const WalletGo::DerivedAddress &data() const { return m_derivedAddress; }; const WalletGo::DerivedAddress& data() const
{
return m_derivedAddress;
};
bool alreadyCreated() const; bool alreadyCreated() const;
@ -32,4 +36,4 @@ private:
using DerivedWalletAddressPtr = std::shared_ptr<DerivedWalletAddress>; using DerivedWalletAddressPtr = std::shared_ptr<DerivedWalletAddress>;
} } // namespace Status::Wallet

View File

@ -1,17 +1,18 @@
#pragma once #pragma once
#include "Status/Wallet/WalletAccount.h"
#include "Status/Wallet/DerivedWalletAddress.h" #include "Status/Wallet/DerivedWalletAddress.h"
#include "Status/Wallet/WalletAccount.h"
#include <Helpers/QObjectVectorModel.h> #include <Helpers/QObjectVectorModel.h>
#include <QtQmlIntegration> #include <QtQmlIntegration>
namespace Status::Wallet { namespace Status::Wallet
{
/// \note the following values are kept in sync \c selectedDerivedAddress, \c derivedAddressIndex and \c derivationPath /// \note the following values are kept in sync \c selectedDerivedAddress, \c derivedAddressIndex and \c derivationPath
/// and \c customDerivationPath; \see connascence.io/value /// and \c customDerivationPath; \see connascence.io/value
class NewWalletAccountController: public QObject class NewWalletAccountController : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
@ -20,7 +21,8 @@ class NewWalletAccountController: public QObject
Q_PROPERTY(QAbstractListModel* mainAccountsModel READ mainAccountsModel CONSTANT) Q_PROPERTY(QAbstractListModel* mainAccountsModel READ mainAccountsModel CONSTANT)
Q_PROPERTY(QAbstractItemModel* currentDerivedAddressModel READ currentDerivedAddressModel 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(int derivedAddressIndex MEMBER m_derivedAddressIndex NOTIFY selectedDerivedAddressChanged)
Q_PROPERTY(QString derivationPath READ derivationPath WRITE setDerivationPath NOTIFY derivationPathChanged) 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 /// \note On account creation \c accounts are updated with the newly created wallet account
NewWalletAccountController(std::shared_ptr<AccountsModel> accounts); NewWalletAccountController(std::shared_ptr<AccountsModel> accounts);
QAbstractListModel *mainAccountsModel(); QAbstractListModel* mainAccountsModel();
QAbstractItemModel *currentDerivedAddressModel(); QAbstractItemModel* currentDerivedAddressModel();
QString derivationPath() const; QString derivationPath() const;
void setDerivationPath(const QString &newDerivationPath); void setDerivationPath(const QString& newDerivationPath);
/// \see \c accountCreatedStatus for async result /// \see \c accountCreatedStatus for async result
Q_INVOKABLE void createAccountAsync(const QString &password, const QString &name, Q_INVOKABLE void createAccountAsync(const QString& password,
const QColor &color, const QString &path, const QString& name,
const Status::Wallet::WalletAccount *derivedFrom); const QColor& color,
const QString& path,
const Status::Wallet::WalletAccount* derivedFrom);
/// \see \c accountCreatedStatus for async result /// \see \c accountCreatedStatus for async result
Q_INVOKABLE void addWatchOnlyAccountAsync(const QString &address, const QString &name, Q_INVOKABLE void addWatchOnlyAccountAsync(const QString& address, const QString& name, const QColor& color);
const QColor &color);
/// \returns \c false if fails (due to incomplete user input) /// \returns \c false if fails (due to incomplete user input)
Q_INVOKABLE bool retrieveAndUpdateDerivedAddresses(const QString &password, Q_INVOKABLE bool retrieveAndUpdateDerivedAddresses(const QString& password,
const Status::Wallet::WalletAccount *derivedFrom); const Status::Wallet::WalletAccount* derivedFrom);
Q_INVOKABLE void clearDerivedAddresses(); Q_INVOKABLE void clearDerivedAddresses();
DerivedWalletAddress *selectedDerivedAddress() const; DerivedWalletAddress* selectedDerivedAddress() const;
void setSelectedDerivedAddress(DerivedWalletAddress *newSelectedDerivedAddress); void setSelectedDerivedAddress(DerivedWalletAddress* newSelectedDerivedAddress);
signals: signals:
void accountCreatedStatus(bool createdSuccessfully); void accountCreatedStatus(bool createdSuccessfully);
@ -68,11 +70,11 @@ signals:
private: private:
void updateSelectedDerivedAddress(int index, std::shared_ptr<DerivedWalletAddress> newEntry); 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(); WalletAccountPtr findMissingAccount();
AccountsModel::ObjectContainer filterMainAccounts(const AccountsModel &accounts); AccountsModel::ObjectContainer filterMainAccounts(const AccountsModel& accounts);
/// Logs a debug message if it fails /// Logs a debug message if it fails
void addNewlyCreatedAccount(WalletAccountPtr newAccount); void addNewlyCreatedAccount(WalletAccountPtr newAccount);

View File

@ -4,7 +4,8 @@
#include <QtQmlIntegration> #include <QtQmlIntegration>
namespace Status::Wallet { namespace Status::Wallet
{
class SavedAddress : public QObject class SavedAddress : public QObject
{ {
@ -16,8 +17,7 @@ class SavedAddress : public QObject
Q_PROPERTY(QString name READ name CONSTANT) Q_PROPERTY(QString name READ name CONSTANT)
public: public:
SavedAddress(const QString &address = QString(), const QString &name = QString(), SavedAddress(const QString& address = QString(), const QString& name = QString(), QObject* parent = nullptr);
QObject *parent = nullptr);
const QString& address() const; const QString& address() const;
const QString& name() const; const QString& name() const;
@ -28,4 +28,4 @@ private:
}; };
using SavedAddressPtr = std::shared_ptr<SavedAddress>; using SavedAddressPtr = std::shared_ptr<SavedAddress>;
} } // namespace Status::Wallet

View File

@ -15,7 +15,7 @@ class SavedAddressesController : public QObject
QML_ELEMENT QML_ELEMENT
QML_UNCREATABLE("C++ only") QML_UNCREATABLE("C++ only")
Q_PROPERTY(QAbstractListModel *savedAddresses READ savedAddresses CONSTANT) Q_PROPERTY(QAbstractListModel* savedAddresses READ savedAddresses CONSTANT)
public: public:
enum Error enum Error
@ -26,11 +26,11 @@ public:
}; };
Q_ENUM(Error) 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(); Q_INVOKABLE void refresh();
signals: signals:

View File

@ -6,9 +6,10 @@
namespace GoAccounts = Status::StatusGo::Accounts; namespace GoAccounts = Status::StatusGo::Accounts;
namespace Status::Wallet { namespace Status::Wallet
{
class WalletAccount: public QObject class WalletAccount : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
@ -19,15 +20,18 @@ class WalletAccount: public QObject
Q_PROPERTY(QColor color READ color CONSTANT) Q_PROPERTY(QColor color READ color CONSTANT)
public: 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; QColor color() const;
const GoAccounts::ChatOrWalletAccount &data() const { return m_data; }; const GoAccounts::ChatOrWalletAccount& data() const
{
return m_data;
};
private: private:
const GoAccounts::ChatOrWalletAccount m_data; const GoAccounts::ChatOrWalletAccount m_data;
@ -36,4 +40,4 @@ private:
using WalletAccountPtr = std::shared_ptr<WalletAccount>; using WalletAccountPtr = std::shared_ptr<WalletAccount>;
using WalletAccounts = std::vector<WalletAccount>; using WalletAccounts = std::vector<WalletAccount>;
} } // namespace Status::Wallet

View File

@ -1,13 +1,14 @@
#pragma once #pragma once
#include <StatusGo/Wallet/Token.h>
#include <StatusGo/Wallet/BigInt.h> #include <StatusGo/Wallet/BigInt.h>
#include <StatusGo/Wallet/Token.h>
#include <QtQmlIntegration> #include <QtQmlIntegration>
namespace WalletGo = Status::StatusGo::Wallet; namespace WalletGo = Status::StatusGo::Wallet;
namespace Status::Wallet { namespace Status::Wallet
{
class WalletAsset : public QObject class WalletAsset : public QObject
{ {
@ -22,7 +23,7 @@ class WalletAsset : public QObject
Q_PROPERTY(float value READ value CONSTANT) Q_PROPERTY(float value READ value CONSTANT)
public: 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; const QString name() const;
@ -42,4 +43,4 @@ private:
int m_count; int m_count;
}; };
} } // namespace Status::Wallet

View File

@ -11,14 +11,15 @@
class QQmlEngine; class QQmlEngine;
class QJSEngine; class QJSEngine;
namespace Status::Wallet { namespace Status::Wallet
{
class NewWalletAccountController; class NewWalletAccountController;
class AccountAssetsController; class AccountAssetsController;
class SavedAddressesController; class SavedAddressesController;
/// \todo move account creation to its own controller /// \todo move account creation to its own controller
class WalletController: public QObject class WalletController : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
@ -31,26 +32,27 @@ public:
WalletController(); WalletController();
/// Called by QML engine to register the instance. QML takes ownership of the instance /// 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 /// To be used in the new wallet account workflow
/// \note caller (QML) takes ownership of the returned object /// \note caller (QML) takes ownership of the returned object
/// \todo consider if complex approach of keeping ownership here and enforcing a unique instance /// \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 /// 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 /// Separated controler for working with wallet saved addresses
/// \note caller (QML) takes ownership of the returned object /// \note caller (QML) takes ownership of the returned object
/// \todo consider if complex approach of keeping ownership here and enforcing a unique instance /// \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 /// 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); Q_INVOKABLE void setCurrentAccountIndex(int index);
/// \note caller (QML) takes ownership of the returned instance /// \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: signals:
void currentAccountChanged(); void currentAccountChanged();

View File

@ -1,8 +1,8 @@
#include "Status/Wallet/AccountAssetsController.h" #include "Status/Wallet/AccountAssetsController.h"
#include <StatusGo/Wallet/WalletApi.h>
#include <StatusGo/Wallet/BigInt.h>
#include <StatusGo/Metadata/api_response.h> #include <StatusGo/Metadata/api_response.h>
#include <StatusGo/Wallet/BigInt.h>
#include <StatusGo/Wallet/WalletApi.h>
#include <Helpers/helpers.h> #include <Helpers/helpers.h>
@ -10,7 +10,8 @@
namespace WalletGo = Status::StatusGo::Wallet; namespace WalletGo = Status::StatusGo::Wallet;
namespace Status::Wallet { namespace Status::Wallet
{
AccountAssetsController::AccountAssetsController(WalletAccount* address, QObject* parent) AccountAssetsController::AccountAssetsController(WalletAccount* address, QObject* parent)
: 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_enabledTokens({u"SNT"_qs, u"ETH"_qs, u"STT"_qs, u"DAI"_qs})
, m_assets(Helpers::makeSharedQObject<AssetModel>("asset")) , m_assets(Helpers::makeSharedQObject<AssetModel>("asset"))
{ {
QtConcurrent::run([this, address]{ updateBalances(); }) QtConcurrent::run([this, address] { updateBalances(); })
.then([this] { .then([this] {
m_assetsReady = true; m_assetsReady = true;
emit assetsReadyChanged(); emit assetsReadyChanged();
@ -30,56 +31,68 @@ AccountAssetsController::AccountAssetsController(WalletAccount* address, QObject
}) })
.onFailed([this] { .onFailed([this] {
emit assetsReadyChanged(); 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() void AccountAssetsController::updateBalances()
{ {
const StatusGo::Accounts::EOAddress& address = m_address->data().address; const StatusGo::Accounts::EOAddress& address = m_address->data().address;
if(m_assets->size() > 0) if(m_assets->size() > 0) m_assets->clear();
m_assets->clear();
// TODO: this should be moved to status-go and exposed as "get balances for account and tokens with currency" // 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::map<Accounts::EOAddress, StatusGo::Wallet::Token> tokens;
std::vector<WalletGo::ChainID> chainIds; std::vector<WalletGo::ChainID> chainIds;
auto allNets = WalletGo::getEthereumChains(false); auto allNets = WalletGo::getEthereumChains(false);
for(const auto &net : allNets) { for(const auto& net : allNets)
if(net.enabled && !net.isTest) { {
try { if(net.enabled && !net.isTest)
{
try
{
const auto allTokens = WalletGo::getTokens(net.chainId); const auto allTokens = WalletGo::getTokens(net.chainId);
for(const auto& tokenToMove : allTokens) { for(const auto& tokenToMove : allTokens)
if(isTokenEnabled(tokenToMove)) { {
if(isTokenEnabled(tokenToMove))
{
auto address = tokenToMove.address; auto address = tokenToMove.address;
tokens.emplace(std::move(address), std::move(tokenToMove)); tokens.emplace(std::move(address), std::move(tokenToMove));
} }
} }
chainIds.push_back(net.chainId); chainIds.push_back(net.chainId);
} }
catch (const StatusGo::CallPrivateRpcError& e) { catch(const StatusGo::CallPrivateRpcError& e)
{
// Most probably "no tokens for this network" // Most probably "no tokens for this network"
if(e.errorResponse().error.message.compare("no tokens for this network") != 0) 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; continue;
} }
} }
} }
auto accountBalances = WalletGo::getTokensBalancesForChainIDs(chainIds, { address }, std::move(Helpers::getKeys(tokens))); auto accountBalances =
if(accountBalances.size() == 1) { WalletGo::getTokensBalancesForChainIDs(chainIds, {address}, std::move(Helpers::getKeys(tokens)));
for(const auto& accountAndBalance : accountBalances.begin()->second) { if(accountBalances.size() == 1)
auto asset = Helpers::makeSharedQObject<WalletAsset>(std::make_shared<WalletGo::Token>(tokens.at(accountAndBalance.first)), accountAndBalance.second); {
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); m_assets->push_back(asset);
} }
} }
else 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 bool AccountAssetsController::isTokenEnabled(const StatusGo::Wallet::Token& token) const
{ {
return find_if(m_enabledTokens.begin(), m_enabledTokens.end(), [&token](const auto& symbol) { return find_if(m_enabledTokens.begin(), m_enabledTokens.end(), [&token](const auto& symbol) {
return token.symbol == symbol; return token.symbol == symbol;
}) != m_enabledTokens.end(); }) != m_enabledTokens.end();
} }
QAbstractItemModel* AccountAssetsController::assetsModel() const QAbstractItemModel* AccountAssetsController::assetsModel() const
@ -97,4 +110,4 @@ bool AccountAssetsController::assetsReady() const
return m_assetsReady; return m_assetsReady;
} }
} } // namespace Status::Wallet

View File

@ -1,12 +1,12 @@
#include "DerivedWalletAddress.h" #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} : QObject{parent}
, m_derivedAddress{std::move(address)} , m_derivedAddress{std::move(address)}
{ { }
}
QString DerivedWalletAddress::address() const QString DerivedWalletAddress::address() const
{ {
@ -18,4 +18,4 @@ bool DerivedWalletAddress::alreadyCreated() const
return m_derivedAddress.alreadyCreated; return m_derivedAddress.alreadyCreated;
} }
} } // namespace Status::Wallet

View File

@ -2,17 +2,17 @@
#include <StatusGo/Wallet/WalletApi.h> #include <StatusGo/Wallet/WalletApi.h>
#include <StatusGo/Accounts/AccountsAPI.h>
#include <StatusGo/Accounts/Accounts.h> #include <StatusGo/Accounts/Accounts.h>
#include <StatusGo/Accounts/AccountsAPI.h>
#include <StatusGo/Accounts/accounts_types.h> #include <StatusGo/Accounts/accounts_types.h>
#include <StatusGo/Metadata/api_response.h> #include <StatusGo/Metadata/api_response.h>
#include <StatusGo/Utils.h>
#include <StatusGo/Types.h> #include <StatusGo/Types.h>
#include <StatusGo/Utils.h>
#include <Onboarding/Common/Constants.h> #include <Onboarding/Common/Constants.h>
#include <QQmlEngine>
#include <QJSEngine> #include <QJSEngine>
#include <QQmlEngine>
#include <ranges> #include <ranges>
@ -21,22 +21,23 @@ namespace WalletGo = Status::StatusGo::Wallet;
namespace UtilsSG = Status::StatusGo::Utils; namespace UtilsSG = Status::StatusGo::Utils;
namespace StatusGo = Status::StatusGo; 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_accounts(accounts)
, m_mainAccounts(std::move(filterMainAccounts(*accounts)), "account") , m_mainAccounts(std::move(filterMainAccounts(*accounts)), "account")
, m_derivedAddress("derivedAddress") , m_derivedAddress("derivedAddress")
, m_derivationPath(Status::Constants::General::PathWalletRoot) , m_derivationPath(Status::Constants::General::PathWalletRoot)
{ { }
}
QAbstractListModel* NewWalletAccountController::mainAccountsModel() QAbstractListModel* NewWalletAccountController::mainAccountsModel()
{ {
return &m_mainAccounts; return &m_mainAccounts;
} }
QAbstractItemModel *NewWalletAccountController::currentDerivedAddressModel() QAbstractItemModel* NewWalletAccountController::currentDerivedAddressModel()
{ {
return &m_derivedAddress; return &m_derivedAddress;
} }
@ -46,77 +47,92 @@ QString NewWalletAccountController::derivationPath() const
return m_derivationPath.get(); return m_derivationPath.get();
} }
void NewWalletAccountController::setDerivationPath(const QString &newDerivationPath) void NewWalletAccountController::setDerivationPath(const QString& newDerivationPath)
{ {
if (m_derivationPath.get() == newDerivationPath) if(m_derivationPath.get() == newDerivationPath) return;
return;
m_derivationPath = GoAccounts::DerivationPath(newDerivationPath); m_derivationPath = GoAccounts::DerivationPath(newDerivationPath);
emit derivationPathChanged(); emit derivationPathChanged();
auto oldCustom = m_customDerivationPath; auto oldCustom = m_customDerivationPath;
const auto &[derivedPath, index]= searchDerivationPath(m_derivationPath); const auto& [derivedPath, index] = searchDerivationPath(m_derivationPath);
m_customDerivationPath = derivedPath == nullptr; m_customDerivationPath = derivedPath == nullptr;
if(!m_customDerivationPath && !derivedPath.get()->alreadyCreated()) if(!m_customDerivationPath && !derivedPath.get()->alreadyCreated())
updateSelectedDerivedAddress(index, derivedPath); updateSelectedDerivedAddress(index, derivedPath);
if(m_customDerivationPath != oldCustom) if(m_customDerivationPath != oldCustom) emit customDerivationPathChanged();
emit customDerivationPathChanged();
} }
void NewWalletAccountController::createAccountAsync(const QString &password, const QString &name, void NewWalletAccountController::createAccountAsync(const QString& password,
const QColor &color, const QString &path, const QString& name,
const WalletAccount *derivedFrom) const QColor& color,
const QString& path,
const WalletAccount* derivedFrom)
{ {
try { try
{
GoAccounts::generateAccountWithDerivedPath(StatusGo::HashedPassword(UtilsSG::hashPassword(password)), GoAccounts::generateAccountWithDerivedPath(StatusGo::HashedPassword(UtilsSG::hashPassword(password)),
name, color, "", GoAccounts::DerivationPath(path), name,
color,
"",
GoAccounts::DerivationPath(path),
derivedFrom->data().derivedFrom.value()); derivedFrom->data().derivedFrom.value());
addNewlyCreatedAccount(findMissingAccount()); addNewlyCreatedAccount(findMissingAccount());
} }
catch(const StatusGo::CallPrivateRpcError& e) { catch(const StatusGo::CallPrivateRpcError& e)
{
qWarning() << "StatusGoQt.generateAccountWithDerivedPath error: " << e.errorResponse().error.message.c_str(); qWarning() << "StatusGoQt.generateAccountWithDerivedPath error: " << e.errorResponse().error.message.c_str();
emit accountCreatedStatus(false); 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); GoAccounts::addAccountWatch(Accounts::EOAddress(address), name, color, u""_qs);
addNewlyCreatedAccount(findMissingAccount()); addNewlyCreatedAccount(findMissingAccount());
} }
catch(const StatusGo::CallPrivateRpcError& e) { catch(const StatusGo::CallPrivateRpcError& e)
{
qWarning() << "StatusGoQt.generateAccountWithDerivedPath error: " << e.errorResponse().error.message.c_str(); qWarning() << "StatusGoQt.generateAccountWithDerivedPath error: " << e.errorResponse().error.message.c_str();
emit accountCreatedStatus(false); emit accountCreatedStatus(false);
} }
} }
bool NewWalletAccountController::retrieveAndUpdateDerivedAddresses(const QString &password, bool NewWalletAccountController::retrieveAndUpdateDerivedAddresses(const QString& password,
const WalletAccount *derivedFrom) const WalletAccount* derivedFrom)
{ {
assert(derivedFrom->data().derivedFrom.has_value()); assert(derivedFrom->data().derivedFrom.has_value());
try { try
{
int currentPage = 1; int currentPage = 1;
int foundIndex = -1; int foundIndex = -1;
int currentIndex = 0; 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; std::shared_ptr<DerivedWalletAddress> foundEntry;
while(currentPage <= maxPageCount && foundIndex < 0) { while(currentPage <= maxPageCount && foundIndex < 0)
{
auto all = WalletGo::getDerivedAddressesForPath(StatusGo::HashedPassword(UtilsSG::hashPassword(password)), auto all = WalletGo::getDerivedAddressesForPath(StatusGo::HashedPassword(UtilsSG::hashPassword(password)),
derivedFrom->data().derivedFrom.value(), derivedFrom->data().derivedFrom.value(),
Status::Constants::General::PathWalletRoot, Status::Constants::General::PathWalletRoot,
m_derivedAddressesPageSize, currentPage); m_derivedAddressesPageSize,
currentPage);
if((currentIndex + all.size()) > m_derivedAddress.size()) if((currentIndex + all.size()) > m_derivedAddress.size())
m_derivedAddress.resize(currentIndex + all.size()); m_derivedAddress.resize(currentIndex + all.size());
for(auto newDerived : all) { for(auto newDerived : all)
{
auto newEntry = Helpers::makeSharedQObject<DerivedWalletAddress>(std::move(newDerived)); auto newEntry = Helpers::makeSharedQObject<DerivedWalletAddress>(std::move(newDerived));
m_derivedAddress.set(currentIndex, newEntry); m_derivedAddress.set(currentIndex, newEntry);
if(foundIndex < 0 && !newEntry->data().alreadyCreated) { if(foundIndex < 0 && !newEntry->data().alreadyCreated)
{
foundIndex = currentIndex; foundIndex = currentIndex;
foundEntry = newEntry; foundEntry = newEntry;
} }
@ -124,11 +140,12 @@ bool NewWalletAccountController::retrieveAndUpdateDerivedAddresses(const QString
} }
currentPage++; currentPage++;
} }
if(foundIndex > 0) if(foundIndex > 0) updateSelectedDerivedAddress(foundIndex, foundEntry);
updateSelectedDerivedAddress(foundIndex, foundEntry);
return true; return true;
} catch(const StatusGo::CallPrivateRpcError &e) { }
catch(const StatusGo::CallPrivateRpcError& e)
{
return false; return false;
} }
} }
@ -142,19 +159,20 @@ WalletAccountPtr NewWalletAccountController::findMissingAccount()
{ {
auto accounts = GoAccounts::getAccounts(); auto accounts = GoAccounts::getAccounts();
// TODO: consider using a QObjectSetModel and a proxy sort model on top instead // 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) { 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(), return std::none_of(m_accounts->objects().begin(), m_accounts->objects().end(), [&a](const auto& eA) {
[&a](const auto &eA) { return a.address == eA->data().address; }); return a.address == eA->data().address;
});
}); });
return it != accounts.end() ? Helpers::makeSharedQObject<WalletAccount>(*it) : nullptr; return it != accounts.end() ? Helpers::makeSharedQObject<WalletAccount>(*it) : nullptr;
} }
NewWalletAccountController::AccountsModel::ObjectContainer NewWalletAccountController::AccountsModel::ObjectContainer
NewWalletAccountController::filterMainAccounts(const AccountsModel &accounts) NewWalletAccountController::filterMainAccounts(const AccountsModel& accounts)
{ {
AccountsModel::ObjectContainer out; AccountsModel::ObjectContainer out;
const auto &c = accounts.objects(); const auto& c = accounts.objects();
std::copy_if(c.begin(), c.end(), std::back_inserter(out), [](const auto &a){ return a->data().isWallet; }); std::copy_if(c.begin(), c.end(), std::back_inserter(out), [](const auto& a) { return a->data().isWallet; });
return out; return out;
} }
@ -168,36 +186,41 @@ void NewWalletAccountController::addNewlyCreatedAccount(WalletAccountPtr newAcco
emit accountCreatedStatus(newAccount != nullptr); emit accountCreatedStatus(newAccount != nullptr);
} }
DerivedWalletAddress *NewWalletAccountController::selectedDerivedAddress() const DerivedWalletAddress* NewWalletAccountController::selectedDerivedAddress() const
{ {
return m_selectedDerivedAddress.get(); return m_selectedDerivedAddress.get();
} }
void NewWalletAccountController::setSelectedDerivedAddress(DerivedWalletAddress *newSelectedDerivedAddress) void NewWalletAccountController::setSelectedDerivedAddress(DerivedWalletAddress* newSelectedDerivedAddress)
{ {
if (m_selectedDerivedAddress.get() == newSelectedDerivedAddress) if(m_selectedDerivedAddress.get() == newSelectedDerivedAddress) return;
return; auto& objs = m_derivedAddress.objects();
auto &objs = m_derivedAddress.objects(); auto foundIt = std::find_if(objs.begin(), objs.end(), [newSelectedDerivedAddress](const auto& a) {
auto foundIt = std::find_if(objs.begin(), objs.end(), [newSelectedDerivedAddress](const auto &a) { return a.get() == newSelectedDerivedAddress; }); return a.get() == newSelectedDerivedAddress;
});
updateSelectedDerivedAddress(std::distance(objs.begin(), foundIt), *foundIt); 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_derivedAddressIndex = index;
m_selectedDerivedAddress = newEntry; m_selectedDerivedAddress = newEntry;
emit selectedDerivedAddressChanged(); emit selectedDerivedAddressChanged();
if(m_derivationPath != newEntry->data().path) { if(m_derivationPath != newEntry->data().path)
{
m_derivationPath = newEntry->data().path; m_derivationPath = newEntry->data().path;
emit derivationPathChanged(); emit derivationPathChanged();
} }
} }
std::tuple<DerivedWalletAddressPtr, int> NewWalletAccountController::searchDerivationPath(const GoAccounts::DerivationPath &derivationPath) { std::tuple<DerivedWalletAddressPtr, int>
const auto &c = m_derivedAddress.objects(); NewWalletAccountController::searchDerivationPath(const GoAccounts::DerivationPath& derivationPath)
auto foundIt = find_if(c.begin(), c.end(), [&derivationPath](const auto &a) { return a->data().path == derivationPath; }); {
if(foundIt != c.end()) const auto& c = m_derivedAddress.objects();
return {*foundIt, std::distance(c.begin(), foundIt)}; 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}; return {nullptr, -1};
} }
} } // namespace Status::Wallet

View File

@ -3,12 +3,11 @@
namespace Status::Wallet 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) : QObject(parent)
, m_address(address) , m_address(address)
, m_name(name) , m_name(name)
{ { }
}
const QString& SavedAddress::address() const const QString& SavedAddress::address() const
{ {
@ -20,4 +19,4 @@ const QString& SavedAddress::name() const
return m_name; return m_name;
} }
} } // namespace Status::Wallet

Some files were not shown because too many files have changed in this diff Show More