From d838e58a3fd94a04d9db82560f7004433300b77e Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Tue, 15 Mar 2016 14:44:06 +0100 Subject: Added support for accounts --- common/domain/applicationdomaintype.cpp | 11 ++++ common/domain/applicationdomaintype.h | 13 ++++- common/resourceconfig.cpp | 93 +++++++++++++++++++++++++++---- common/resourceconfig.h | 12 ++++ common/resourcefacade.cpp | 99 +++++++++++++++++++++++++++++++++ common/resourcefacade.h | 11 ++++ docs/applicationdomaintypes.md | 46 +++++++++------ 7 files changed, 257 insertions(+), 28 deletions(-) diff --git a/common/domain/applicationdomaintype.cpp b/common/domain/applicationdomaintype.cpp index df10327..462585e 100644 --- a/common/domain/applicationdomaintype.cpp +++ b/common/domain/applicationdomaintype.cpp @@ -141,6 +141,11 @@ SinkResource::~SinkResource() } +SinkAccount::~SinkAccount() +{ + +} + template<> QByteArray getTypeName() { @@ -159,6 +164,12 @@ QByteArray getTypeName() return "sinkresource"; } +template<> +QByteArray getTypeName() +{ + return "sinkaccount"; +} + template<> QByteArray getTypeName() { diff --git a/common/domain/applicationdomaintype.h b/common/domain/applicationdomaintype.h index 32d8999..d17ad75 100644 --- a/common/domain/applicationdomaintype.h +++ b/common/domain/applicationdomaintype.h @@ -135,7 +135,7 @@ struct SINK_EXPORT Folder : public Entity { /** * Represents an sink resource. - * + * * This type is used for configuration of resources, * and for creating and removing resource instances. */ @@ -145,6 +145,12 @@ struct SINK_EXPORT SinkResource : public ApplicationDomainType { virtual ~SinkResource(); }; +struct SINK_EXPORT SinkAccount : public ApplicationDomainType { + typedef QSharedPointer Ptr; + using ApplicationDomainType::ApplicationDomainType; + virtual ~SinkAccount(); +}; + /** * All types need to be registered here an MUST return a different name. * @@ -162,6 +168,9 @@ QByteArray SINK_EXPORT getTypeName(); template<> QByteArray SINK_EXPORT getTypeName(); +template<> +QByteArray SINK_EXPORT getTypeName(); + template<> QByteArray SINK_EXPORT getTypeName(); @@ -192,3 +201,5 @@ Q_DECLARE_METATYPE(Sink::ApplicationDomain::Folder) Q_DECLARE_METATYPE(Sink::ApplicationDomain::Folder::Ptr) Q_DECLARE_METATYPE(Sink::ApplicationDomain::SinkResource) Q_DECLARE_METATYPE(Sink::ApplicationDomain::SinkResource::Ptr) +Q_DECLARE_METATYPE(Sink::ApplicationDomain::SinkAccount) +Q_DECLARE_METATYPE(Sink::ApplicationDomain::SinkAccount::Ptr) diff --git a/common/resourceconfig.cpp b/common/resourceconfig.cpp index b988718..4b33990 100644 --- a/common/resourceconfig.cpp +++ b/common/resourceconfig.cpp @@ -23,19 +23,20 @@ #include #include -static QSharedPointer getSettings() +static QSharedPointer getConfig(const QByteArray &identifier) { - return QSharedPointer::create(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/sink/resources.ini", QSettings::IniFormat); + return QSharedPointer::create(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/sink/" + identifier + ".ini", QSettings::IniFormat); } -static QSharedPointer getResourceConfig(const QByteArray &identifier) +static QSharedPointer getSettings() { - return QSharedPointer::create(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/sink/" + identifier, QSettings::IniFormat); + return getConfig("resources"); } + QByteArray ResourceConfig::newIdentifier(const QByteArray &type) { - auto settings = getSettings(); + auto settings = getConfig("resources"); const auto counter = settings->value("instanceCounter", 0).toInt() + 1; const QByteArray identifier = type + ".instance" + QByteArray::number(counter); settings->setValue("instanceCounter", counter); @@ -45,7 +46,7 @@ QByteArray ResourceConfig::newIdentifier(const QByteArray &type) void ResourceConfig::addResource(const QByteArray &identifier, const QByteArray &type) { - auto settings = getSettings(); + auto settings = getConfig("resources"); settings->beginGroup(QString::fromLatin1(identifier)); settings->setValue("type", type); settings->endGroup(); @@ -54,18 +55,18 @@ void ResourceConfig::addResource(const QByteArray &identifier, const QByteArray void ResourceConfig::removeResource(const QByteArray &identifier) { - auto settings = getSettings(); + auto settings = getConfig("resources"); settings->beginGroup(QString::fromLatin1(identifier)); settings->remove(""); settings->endGroup(); settings->sync(); - QFile::remove(getResourceConfig(identifier)->fileName()); + QFile::remove(getConfig(identifier)->fileName()); } QMap ResourceConfig::getResources() { QMap resources; - auto settings = getSettings(); + auto settings = getConfig("resources"); for (const auto &identifier : settings->childGroups()) { settings->beginGroup(identifier); const auto type = settings->value("type").toByteArray(); @@ -84,7 +85,7 @@ void ResourceConfig::clear() void ResourceConfig::configureResource(const QByteArray &identifier, const QMap &configuration) { - auto config = getResourceConfig(identifier); + auto config = getConfig(identifier); config->clear(); for (const auto &key : configuration.keys()) { config->setValue(key, configuration.value(key)); @@ -95,7 +96,77 @@ void ResourceConfig::configureResource(const QByteArray &identifier, const QMap< QMap ResourceConfig::getConfiguration(const QByteArray &identifier) { QMap configuration; - auto config = getResourceConfig(identifier); + auto config = getConfig(identifier); + for (const auto &key : config->allKeys()) { + configuration.insert(key.toLatin1(), config->value(key)); + } + return configuration; +} + + +QByteArray AccountConfig::newIdentifier(const QByteArray &type) +{ + auto settings = getConfig("accounts"); + const auto counter = settings->value("instanceCounter", 0).toInt() + 1; + const QByteArray identifier = type + ".instance" + QByteArray::number(counter); + settings->setValue("instanceCounter", counter); + settings->sync(); + return identifier; +} + +void AccountConfig::addAccount(const QByteArray &identifier, const QByteArray &type) +{ + auto settings = getConfig("accounts"); + settings->beginGroup(QString::fromLatin1(identifier)); + settings->setValue("type", type); + settings->endGroup(); + settings->sync(); +} + +void AccountConfig::removeAccount(const QByteArray &identifier) +{ + auto settings = getConfig("accounts"); + settings->beginGroup(QString::fromLatin1(identifier)); + settings->remove(""); + settings->endGroup(); + settings->sync(); + QFile::remove(getConfig(identifier)->fileName()); +} + +QMap AccountConfig::getAccounts() +{ + QMap accounts; + auto settings = getConfig("accounts"); + for (const auto &identifier : settings->childGroups()) { + settings->beginGroup(identifier); + const auto type = settings->value("type").toByteArray(); + accounts.insert(identifier.toLatin1(), type); + settings->endGroup(); + } + return accounts; +} + +void AccountConfig::clear() +{ + auto settings = getSettings(); + settings->clear(); + settings->sync(); +} + +void AccountConfig::configureAccount(const QByteArray &identifier, const QMap &configuration) +{ + auto config = getConfig(identifier); + config->clear(); + for (const auto &key : configuration.keys()) { + config->setValue(key, configuration.value(key)); + } + config->sync(); +} + +QMap AccountConfig::getConfiguration(const QByteArray &identifier) +{ + QMap configuration; + auto config = getConfig(identifier); for (const auto &key : config->allKeys()) { configuration.insert(key.toLatin1(), config->value(key)); } diff --git a/common/resourceconfig.h b/common/resourceconfig.h index 2108caa..505b5ec 100644 --- a/common/resourceconfig.h +++ b/common/resourceconfig.h @@ -36,3 +36,15 @@ public: static void configureResource(const QByteArray &identifier, const QMap &configuration); static QMap getConfiguration(const QByteArray &identifier); }; + +class SINK_EXPORT AccountConfig +{ +public: + static QMap getAccounts(); + static QByteArray newIdentifier(const QByteArray &type); + static void addAccount(const QByteArray &identifier, const QByteArray &type); + static void removeAccount(const QByteArray &identifier); + static void clear(); + static void configureAccount(const QByteArray &identifier, const QMap &configuration); + static QMap getConfiguration(const QByteArray &identifier); +}; diff --git a/common/resourcefacade.cpp b/common/resourcefacade.cpp index 3095c2e..d91c974 100644 --- a/common/resourcefacade.cpp +++ b/common/resourcefacade.cpp @@ -126,3 +126,102 @@ QPair, typename Sink::ResultEmitter() +{ +} + +AccountFacade::~AccountFacade() +{ +} + +KAsync::Job AccountFacade::create(const Sink::ApplicationDomain::SinkAccount &account) +{ + return KAsync::start([account, this]() { + const QByteArray type = account.getProperty("type").toByteArray(); + const QByteArray providedIdentifier = account.getProperty("identifier").toByteArray(); + // It is currently a requirement that the account starts with the type + const QByteArray identifier = providedIdentifier.isEmpty() ? AccountConfig::newIdentifier(type) : providedIdentifier; + AccountConfig::addAccount(identifier, type); + auto changedProperties = account.changedProperties(); + changedProperties.removeOne("identifier"); + changedProperties.removeOne("type"); + if (!changedProperties.isEmpty()) { + // We have some configuration values + QMap configurationValues; + for (const auto &property : changedProperties) { + configurationValues.insert(property, account.getProperty(property)); + } + AccountConfig::configureAccount(identifier, configurationValues); + } + }); +} + +KAsync::Job AccountFacade::modify(const Sink::ApplicationDomain::SinkAccount &account) +{ + return KAsync::start([account, this]() { + const QByteArray identifier = account.identifier(); + if (identifier.isEmpty()) { + Warning() << "We need an \"identifier\" property to identify the account to configure."; + return; + } + auto changedProperties = account.changedProperties(); + changedProperties.removeOne("identifier"); + changedProperties.removeOne("type"); + if (!changedProperties.isEmpty()) { + // We have some configuration values + QMap configurationValues; + for (const auto &property : changedProperties) { + configurationValues.insert(property, account.getProperty(property)); + } + AccountConfig::configureAccount(identifier, configurationValues); + } + }); +} + +KAsync::Job AccountFacade::remove(const Sink::ApplicationDomain::SinkAccount &account) +{ + return KAsync::start([account, this]() { + const QByteArray identifier = account.identifier(); + if (identifier.isEmpty()) { + Warning() << "We need an \"identifier\" property to identify the account to configure"; + return; + } + AccountConfig::removeAccount(identifier); + }); +} + +QPair, typename Sink::ResultEmitter::Ptr> AccountFacade::load(const Sink::Query &query) +{ + auto resultProvider = new Sink::ResultProvider(); + auto emitter = resultProvider->emitter(); + resultProvider->setFetcher([](const QSharedPointer &) {}); + resultProvider->onDone([resultProvider]() { delete resultProvider; }); + auto job = KAsync::start([query, resultProvider]() { + const auto configuredAccounts = AccountConfig::getAccounts(); + for (const auto &res : configuredAccounts.keys()) { + const auto type = configuredAccounts.value(res); + if (query.propertyFilter.contains("type") && query.propertyFilter.value("type").toByteArray() != type) { + continue; + } + if (!query.ids.isEmpty() && !query.ids.contains(res)) { + continue; + } + + auto account = Sink::ApplicationDomain::SinkAccount::Ptr::create("", res, 0, QSharedPointer::create()); + account->setProperty("type", type); + + const auto configurationValues = AccountConfig::getConfiguration(res); + for (auto it = configurationValues.constBegin(); it != configurationValues.constEnd(); it++) { + account->setProperty(it.key(), it.value()); + } + + resultProvider->add(account); + } + // TODO initialResultSetComplete should be implicit + resultProvider->initialResultSetComplete(Sink::ApplicationDomain::SinkAccount::Ptr()); + resultProvider->complete(); + }); + return qMakePair(job, emitter); +} diff --git a/common/resourcefacade.h b/common/resourcefacade.h index 3de0e25..48ff2a5 100644 --- a/common/resourcefacade.h +++ b/common/resourcefacade.h @@ -40,3 +40,14 @@ public: KAsync::Job remove(const Sink::ApplicationDomain::SinkResource &resource) Q_DECL_OVERRIDE; QPair, typename Sink::ResultEmitter::Ptr> load(const Sink::Query &query) Q_DECL_OVERRIDE; }; + +class AccountFacade : public Sink::StoreFacade +{ +public: + AccountFacade(const QByteArray &instanceIdentifier); + virtual ~AccountFacade(); + KAsync::Job create(const Sink::ApplicationDomain::SinkAccount &resource) Q_DECL_OVERRIDE; + KAsync::Job modify(const Sink::ApplicationDomain::SinkAccount &resource) Q_DECL_OVERRIDE; + KAsync::Job remove(const Sink::ApplicationDomain::SinkAccount &resource) Q_DECL_OVERRIDE; + QPair, typename Sink::ResultEmitter::Ptr> load(const Sink::Query &query) Q_DECL_OVERRIDE; +}; diff --git a/docs/applicationdomaintypes.md b/docs/applicationdomaintypes.md index 798fa13..56e3032 100644 --- a/docs/applicationdomaintypes.md +++ b/docs/applicationdomaintypes.md @@ -9,7 +9,7 @@ The definition of the domain model directly affects: The purpose of these domain types is strictly to be the interface and the types are not meant to be used by applications directly, or to be restricted by any other specifications (such as ical). By nature these types will be part of the evolving interface, and will need to be adjusted for every new property that an application accesses. ### Application Domain Types -This is a proposed set of types that we will need to evolve into what we actually require. Hierarchical types are required to be able to query for a result set of mixed types. +This is the currently defined set of types. Hierarchical types are required to be able to query for a result set of mixed types, but are not necessarily structured as such in the inheritance model. * Entity * Domain Object @@ -34,40 +34,54 @@ This is a proposed set of types that we will need to evolve into what we actuall * Thread * Sink Resource * Maildir Resource + * IMAP Resource + * Account #### Properties ```no-highlight Entity: The smallest unit in the sink universe - id: unique identifier in the sink storage. Not persistant over db recreations and can therefore only be referenced from within the sink database. + id [QByteArray]: unique identifier in the sink storage. Not persistant over db recreations and can therefore only be referenced from within the sink database. ``` ```no-highlight Domain Object: - uid: unique identifier of the domain object. - revision: revision of the entity - resource: reference to SinkResource:id of the parent resource. + uid [QByteArray}: unique identifier of the domain object. + revision [int]: revision of the entity + resource [SinkResource.id]: The parent resource. ``` ```no-highlight Event: - summary: A string containing a short summary of the event. - startDate: The start date of the event. - startTime: The start time of the event. Optional. + summary [QString]: A string containing a short summary of the event. + startDate [QDateTime]: The start date of the event. + startTime [QDateTime]: The start time of the event. Optional. ``` ```no-highlight Mail: - uid: The message id. - subject: The subject of the email. - folder: The identifier of the parent folder. - date: The date of the email. - mimeMessage: A string containing the path to the mime message + uid [QByteArray]: The message id. + subject [QString]: The subject of the email. + folder [MailFolder.id]: The parent folder. + date [QDateTime]: The date of the email. + mimeMessage [QString]: A string containing the path to the mime message +``` +```no-highlight +Mail Folder: + parent [MailFolder.id]: The parent folder. + name [QString]: The user visible name of the folder. + icon [QString]: The name of the icon of the folder. ``` ```no-highlight Sink Resource: - type: The type of the resource. - name: The name of the resource. + type [QByteArray]: The type of the resource. + name [QString]: The name of the resource. + account [Account.id]: The identifier of the associated account. ``` ```no-highlight Maildir Resource: - path: The path to the maildir. + path [QString]: The path to the maildir. +``` +```no-highlight +Account: + name [QString]: The name of the account. + icon [QString]: The name of the icon of the account. ``` ### References/Hierachies -- cgit v1.2.3