summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2016-05-03 20:24:09 +0200
committerChristian Mollekopf <chrigi_1@fastmail.fm>2016-05-03 20:24:26 +0200
commite06e1dad4a4570e5c1181d05ab6ed7a5d74c6c91 (patch)
treeef606d36ee693eff087292a1950fe122a7376f19
parent21f7851f044cd8b6e38c821ce12d7e1b291cae27 (diff)
downloadkube-e06e1dad4a4570e5c1181d05ab6ed7a5d74c6c91.tar.gz
kube-e06e1dad4a4570e5c1181d05ab6ed7a5d74c6c91.zip
A save-as-draft action & action results
This patch introduces tracking of actions, so they can be tested. It also provides a save-as-draft action, that looks for the draft folder, and stores the mail accordingly.
-rw-r--r--CMakeLists.txt1
-rw-r--r--framework/CMakeLists.txt1
-rw-r--r--framework/actions/CMakeLists.txt1
-rw-r--r--framework/actions/action.cpp4
-rw-r--r--framework/actions/action.h3
-rw-r--r--framework/actions/actionbroker.cpp9
-rw-r--r--framework/actions/actionbroker.h3
-rw-r--r--framework/actions/actionhandler.cpp37
-rw-r--r--framework/actions/actionhandler.h14
-rw-r--r--framework/actions/actionresult.cpp20
-rw-r--r--framework/actions/actionresult.h66
-rw-r--r--framework/domain/CMakeLists.txt4
-rw-r--r--framework/domain/actions/sinkactions.cpp101
-rw-r--r--framework/domain/actions/tests/CMakeLists.txt6
-rw-r--r--framework/domain/actions/tests/sinkactiontest.cpp60
-rw-r--r--framework/domain/composercontroller.cpp5
-rw-r--r--framework/domain/maillistmodel.cpp2
17 files changed, 271 insertions, 66 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bb3d0941..a3784ad6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,7 @@
1project(kube) 1project(kube)
2 2
3cmake_minimum_required(VERSION 2.8.12) 3cmake_minimum_required(VERSION 2.8.12)
4enable_testing()
4 5
5add_subdirectory(framework) 6add_subdirectory(framework)
6add_subdirectory(components) 7add_subdirectory(components)
diff --git a/framework/CMakeLists.txt b/framework/CMakeLists.txt
index c216d3c0..4fecaf14 100644
--- a/framework/CMakeLists.txt
+++ b/framework/CMakeLists.txt
@@ -27,6 +27,7 @@ find_package(KF5Codecs CONFIG REQUIRED)
27set(CMAKE_AUTOMOC ON) 27set(CMAKE_AUTOMOC ON)
28add_definitions("-Wall -std=c++0x -g") 28add_definitions("-Wall -std=c++0x -g")
29include_directories(.) 29include_directories(.)
30include_directories(SYSTEM ${KDE_INSTALL_FULL_INCLUDEDIR}/KF5/)
30include_directories(SYSTEM ${KDE_INSTALL_FULL_INCLUDEDIR}/KF5/KMime) 31include_directories(SYSTEM ${KDE_INSTALL_FULL_INCLUDEDIR}/KF5/KMime)
31include_directories(SYSTEM ${KDE_INSTALL_FULL_INCLUDEDIR}/KF5/KIconThemes) 32include_directories(SYSTEM ${KDE_INSTALL_FULL_INCLUDEDIR}/KF5/KIconThemes)
32 33
diff --git a/framework/actions/CMakeLists.txt b/framework/actions/CMakeLists.txt
index a09445b0..d757f654 100644
--- a/framework/actions/CMakeLists.txt
+++ b/framework/actions/CMakeLists.txt
@@ -3,6 +3,7 @@ set(SRCS
3 action.cpp 3 action.cpp
4 actionhandler.cpp 4 actionhandler.cpp
5 actionbroker.cpp 5 actionbroker.cpp
6 actionresult.cpp
6 context.cpp 7 context.cpp
7) 8)
8 9
diff --git a/framework/actions/action.cpp b/framework/actions/action.cpp
index e6ba2daf..28dd5e2a 100644
--- a/framework/actions/action.cpp
+++ b/framework/actions/action.cpp
@@ -85,8 +85,8 @@ bool Action::ready() const
85 return ActionBroker::instance().isActionReady(mActionId, mContext); 85 return ActionBroker::instance().isActionReady(mActionId, mContext);
86} 86}
87 87
88void Action::execute() 88ActionResult Action::execute()
89{ 89{
90 ActionBroker::instance().executeAction(mActionId, mContext); 90 return ActionBroker::instance().executeAction(mActionId, mContext);
91} 91}
92 92
diff --git a/framework/actions/action.h b/framework/actions/action.h
index b820955e..1ad4a47e 100644
--- a/framework/actions/action.h
+++ b/framework/actions/action.h
@@ -20,6 +20,7 @@
20 20
21#include <QObject> 21#include <QObject>
22#include "context.h" 22#include "context.h"
23#include "actionresult.h"
23 24
24namespace Kube { 25namespace Kube {
25 26
@@ -43,7 +44,7 @@ public:
43 44
44 bool ready() const; 45 bool ready() const;
45 46
46 Q_INVOKABLE void execute(); 47 Q_INVOKABLE ActionResult execute();
47 48
48Q_SIGNALS: 49Q_SIGNALS:
49 void readyChanged(); 50 void readyChanged();
diff --git a/framework/actions/actionbroker.cpp b/framework/actions/actionbroker.cpp
index 43a535a1..890a5566 100644
--- a/framework/actions/actionbroker.cpp
+++ b/framework/actions/actionbroker.cpp
@@ -54,17 +54,22 @@ bool ActionBroker::isActionReady(const QByteArray &actionId, Context *context)
54 return false; 54 return false;
55} 55}
56 56
57void ActionBroker::executeAction(const QByteArray &actionId, Context *context) 57ActionResult ActionBroker::executeAction(const QByteArray &actionId, Context *context)
58{ 58{
59 if (context) { 59 if (context) {
60 for (const auto handler : mHandler.values(actionId)) { 60 for (const auto handler : mHandler.values(actionId)) {
61 if (handler) { 61 if (handler) {
62 handler->execute(context); 62 //FIXME All handler together return one result
63 return handler->execute(context);
63 } 64 }
64 } 65 }
65 } else { 66 } else {
66 qWarning() << "Can't execute without context"; 67 qWarning() << "Can't execute without context";
67 } 68 }
69 ActionResult result;
70 result.setDone();
71 result.setError(1);
72 return result;
68} 73}
69 74
70void ActionBroker::registerHandler(const QByteArray &actionId, ActionHandler *handler) 75void ActionBroker::registerHandler(const QByteArray &actionId, ActionHandler *handler)
diff --git a/framework/actions/actionbroker.h b/framework/actions/actionbroker.h
index 08eac742..8f3eaeb2 100644
--- a/framework/actions/actionbroker.h
+++ b/framework/actions/actionbroker.h
@@ -24,6 +24,7 @@
24namespace Kube { 24namespace Kube {
25class Context; 25class Context;
26class ActionHandler; 26class ActionHandler;
27class ActionResult;
27 28
28class ActionBroker : public QObject 29class ActionBroker : public QObject
29{ 30{
@@ -32,7 +33,7 @@ public:
32 static ActionBroker &instance(); 33 static ActionBroker &instance();
33 34
34 bool isActionReady(const QByteArray &actionId, Context *context); 35 bool isActionReady(const QByteArray &actionId, Context *context);
35 void executeAction(const QByteArray &actionId, Context *context); 36 ActionResult executeAction(const QByteArray &actionId, Context *context);
36 37
37 void registerHandler(const QByteArray &actionId, ActionHandler *handler); 38 void registerHandler(const QByteArray &actionId, ActionHandler *handler);
38 39
diff --git a/framework/actions/actionhandler.cpp b/framework/actions/actionhandler.cpp
index d4b01734..4ae8d0a9 100644
--- a/framework/actions/actionhandler.cpp
+++ b/framework/actions/actionhandler.cpp
@@ -45,17 +45,24 @@ bool ActionHandler::isActionReady(Context *context)
45 return false; 45 return false;
46} 46}
47 47
48void ActionHandler::execute(Context *context) 48ActionResult ActionHandler::execute(Context *context)
49{ 49{
50 ActionResult result;
50 QVariant returnedValue; 51 QVariant returnedValue;
51 qWarning() << "Executing the handler"; 52 qWarning() << "Executing the handler";
52 if (context) { 53 if (context) {
54 //The base implementation to call the handler in QML
53 QMetaObject::invokeMethod(this, "handler", 55 QMetaObject::invokeMethod(this, "handler",
54 Q_RETURN_ARG(QVariant, returnedValue), 56 Q_RETURN_ARG(QVariant, returnedValue),
55 Q_ARG(QVariant, QVariant::fromValue(context))); 57 Q_ARG(QVariant, QVariant::fromValue(context)));
58 //TODO: support async handlers in QML
59 result.setDone();
56 } else { 60 } else {
57 qWarning() << "The handler didn't get a context"; 61 qWarning() << "The handler didn't get a context";
62 result.setDone();
63 result.setError(1);
58 } 64 }
65 return result;
59} 66}
60 67
61void ActionHandler::setActionId(const QByteArray &actionId) 68void ActionHandler::setActionId(const QByteArray &actionId)
@@ -79,12 +86,36 @@ ActionHandlerHelper::ActionHandlerHelper(const QByteArray &actionId, const IsRea
79 setActionId(actionId); 86 setActionId(actionId);
80} 87}
81 88
89ActionHandlerHelper::ActionHandlerHelper(const QByteArray &actionId, const IsReadyFunction &isReady, const JobHandler &handler)
90 : ActionHandler(nullptr),
91 isReadyFunction(isReady),
92 jobHandlerFunction(handler)
93{
94 setActionId(actionId);
95}
96
82bool ActionHandlerHelper::isActionReady(Context *context) 97bool ActionHandlerHelper::isActionReady(Context *context)
83{ 98{
84 return isReadyFunction(context); 99 return isReadyFunction(context);
85} 100}
86 101
87void ActionHandlerHelper::execute(Context *context) 102ActionResult ActionHandlerHelper::execute(Context *context)
88{ 103{
89 handlerFunction(context); 104 ActionResult result;
105 if (handlerFunction) {
106 handlerFunction(context);
107 result.setDone();
108 } else {
109 jobHandlerFunction(context).then<void>([=]() {
110 auto modifyableResult = result;
111 modifyableResult.setDone();
112 },
113 [=](int errorCode, const QString &string) {
114 qWarning() << "Job failed: " << errorCode << string;
115 auto modifyableResult = result;
116 modifyableResult.setError(1);
117 modifyableResult.setDone();
118 }).exec();
119 }
120 return result;
90} 121}
diff --git a/framework/actions/actionhandler.h b/framework/actions/actionhandler.h
index 1820bfd4..c8c10dc7 100644
--- a/framework/actions/actionhandler.h
+++ b/framework/actions/actionhandler.h
@@ -21,6 +21,9 @@
21#include <QObject> 21#include <QObject>
22#include <QMultiMap> 22#include <QMultiMap>
23#include <functional> 23#include <functional>
24#include <Async/Async>
25
26#include "actionresult.h"
24 27
25namespace Kube { 28namespace Kube {
26class Context; 29class Context;
@@ -36,7 +39,7 @@ public:
36 virtual bool isActionReady(Context *context); 39 virtual bool isActionReady(Context *context);
37 40
38 // void pre(Context *context); 41 // void pre(Context *context);
39 virtual void execute(Context *context); 42 virtual ActionResult execute(Context *context);
40 // void post(Context *context); 43 // void post(Context *context);
41 44
42 void setActionId(const QByteArray &); 45 void setActionId(const QByteArray &);
@@ -52,14 +55,17 @@ class ActionHandlerHelper : public ActionHandler
52public: 55public:
53 typedef std::function<bool(Context*)> IsReadyFunction; 56 typedef std::function<bool(Context*)> IsReadyFunction;
54 typedef std::function<void(Context*)> Handler; 57 typedef std::function<void(Context*)> Handler;
58 typedef std::function<KAsync::Job<void>(Context*)> JobHandler;
55 59
56 ActionHandlerHelper(const QByteArray &actionId, const IsReadyFunction &, const Handler &); 60 ActionHandlerHelper(const QByteArray &actionId, const IsReadyFunction &, const Handler &);
61 ActionHandlerHelper(const QByteArray &actionId, const IsReadyFunction &, const JobHandler &);
57 62
58 bool isActionReady(Context *context) Q_DECL_OVERRIDE; 63 bool isActionReady(Context *context) Q_DECL_OVERRIDE;
59 void execute(Context *context) Q_DECL_OVERRIDE; 64 ActionResult execute(Context *context) Q_DECL_OVERRIDE;
60private: 65private:
61 const std::function<bool(Context*)> isReadyFunction; 66 const IsReadyFunction isReadyFunction;
62 const std::function<void(Context*)> handlerFunction; 67 const Handler handlerFunction;
68 const JobHandler jobHandlerFunction;
63}; 69};
64 70
65} 71}
diff --git a/framework/actions/actionresult.cpp b/framework/actions/actionresult.cpp
new file mode 100644
index 00000000..631c61c4
--- /dev/null
+++ b/framework/actions/actionresult.cpp
@@ -0,0 +1,20 @@
1/*
2 Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.com>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19#include "actionresult.h"
20
diff --git a/framework/actions/actionresult.h b/framework/actions/actionresult.h
new file mode 100644
index 00000000..cdc6a160
--- /dev/null
+++ b/framework/actions/actionresult.h
@@ -0,0 +1,66 @@
1/*
2 Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.com>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19#pragma once
20
21#include <QObject>
22#include <QSharedPointer>
23
24namespace Kube {
25
26struct ActionResultData
27{
28 ActionResultData() : mError(0), mDone(false) {}
29 int mError;
30 bool mDone;
31};
32
33class ActionResult : public QObject
34{
35 Q_OBJECT
36public:
37 ActionResult() : QObject(), mData(new ActionResultData()) {}
38 ActionResult(const ActionResult &rhs) : QObject(), mData(rhs.mData) {}
39 ActionResult &operator=(const ActionResult &rhs)
40 {
41 mData = rhs.mData;
42 return *this;
43 }
44 virtual ~ActionResult() {}
45
46 void setDone() {
47 mData->mDone = true;
48 }
49
50 bool isDone() const {
51 return mData->mDone;
52 }
53
54 void setError(int error) {
55 mData->mError = error;
56 }
57
58 int error() const {
59 return mData->mError;
60 }
61
62private:
63 QSharedPointer<ActionResultData> mData;
64};
65
66}
diff --git a/framework/domain/CMakeLists.txt b/framework/domain/CMakeLists.txt
index b3d47750..29385b39 100644
--- a/framework/domain/CMakeLists.txt
+++ b/framework/domain/CMakeLists.txt
@@ -27,7 +27,9 @@ include_directories(${CURL_INCLUDE_DIRS})
27add_library(mailplugin SHARED ${mailplugin_SRCS}) 27add_library(mailplugin SHARED ${mailplugin_SRCS})
28 28
29qt5_use_modules(mailplugin Core Quick Qml WebKitWidgets) 29qt5_use_modules(mailplugin Core Quick Qml WebKitWidgets)
30target_link_libraries(mailplugin actionplugin settingsplugin sink KF5::MimeTreeParser KF5::Codecs KF5::Package ${CURL_LIBRARIES}) 30target_link_libraries(mailplugin actionplugin settingsplugin sink KF5::MimeTreeParser KF5::Codecs KF5::Package KF5::Async ${CURL_LIBRARIES})
31
32add_subdirectory(actions/tests)
31 33
32install(TARGETS mailplugin DESTINATION ${QML_INSTALL_DIR}/org/kube/framework/domain) 34install(TARGETS mailplugin DESTINATION ${QML_INSTALL_DIR}/org/kube/framework/domain)
33install(FILES qmldir DESTINATION ${QML_INSTALL_DIR}/org/kube/framework/domain) 35install(FILES qmldir DESTINATION ${QML_INSTALL_DIR}/org/kube/framework/domain)
diff --git a/framework/domain/actions/sinkactions.cpp b/framework/domain/actions/sinkactions.cpp
index dea6fc72..5dbe623c 100644
--- a/framework/domain/actions/sinkactions.cpp
+++ b/framework/domain/actions/sinkactions.cpp
@@ -81,16 +81,7 @@ static ActionHandlerHelper sendMailHandler("org.kde.kube.actions.sendmail",
81 }, 81 },
82 [](Context *context) { 82 [](Context *context) {
83 auto accountId = context->property("accountId").value<QByteArray>(); 83 auto accountId = context->property("accountId").value<QByteArray>();
84 //For ssl use "smtps://mainserver.example.net
85 // QByteArray cacert; // = "/path/to/certificate.pem";
86 auto message = context->property("message").value<KMime::Message::Ptr>(); 84 auto message = context->property("message").value<KMime::Message::Ptr>();
87 auto mimeMessage = Sink::Store::getTemporaryFilePath();
88 QFile file(mimeMessage);
89 if (!file.open(QIODevice::ReadWrite)) {
90 qWarning() << "Failed to open the file: " << file.errorString() << mimeMessage;
91 return;
92 }
93 file.write(message->encodedContent());
94 qWarning() << "Sending a mail: "; 85 qWarning() << "Sending a mail: ";
95 86
96 Sink::Query query; 87 Sink::Query query;
@@ -98,53 +89,63 @@ static ActionHandlerHelper sendMailHandler("org.kde.kube.actions.sendmail",
98 query += Sink::Query::PropertyFilter("account", QVariant::fromValue(accountId)); 89 query += Sink::Query::PropertyFilter("account", QVariant::fromValue(accountId));
99 Sink::Store::fetchAll<Sink::ApplicationDomain::SinkResource>(query) 90 Sink::Store::fetchAll<Sink::ApplicationDomain::SinkResource>(query)
100 .then<void, QList<Sink::ApplicationDomain::SinkResource::Ptr>>([=](const QList<Sink::ApplicationDomain::SinkResource::Ptr> &resources) { 91 .then<void, QList<Sink::ApplicationDomain::SinkResource::Ptr>>([=](const QList<Sink::ApplicationDomain::SinkResource::Ptr> &resources) {
101 if (resources.isEmpty()) { 92 if (!resources.isEmpty()) {
102 qWarning() << "Failed to find a mailtransport resource";
103 } else {
104 auto resourceId = resources[0]->identifier(); 93 auto resourceId = resources[0]->identifier();
105 qDebug() << "Sending message via resource: " << resourceId; 94 qDebug() << "Sending message via resource: " << resourceId;
106 Sink::ApplicationDomain::Mail mail(resourceId); 95 Sink::ApplicationDomain::Mail mail(resourceId);
107 mail.setProperty("mimeMessage", mimeMessage); 96 mail.setBlobProperty("mimeMessage", message->encodedContent());
108 Sink::Store::create(mail).exec(); 97 return Sink::Store::create(mail);
109 // return Sink::Store::create(mail);
110 } 98 }
99 qWarning() << "Failed to find a mailtransport resource";
111 return KAsync::error<void>(0, "Failed to find a MailTransport resource."); 100 return KAsync::error<void>(0, "Failed to find a MailTransport resource.");
112 }).exec(); 101 }).exec();
113 } 102 }
114); 103);
115 104
116// static ActionHandlerHelper saveAsDraft("org.kde.kube.actions.save-as-draft", 105static ActionHandlerHelper saveAsDraft("org.kde.kube.actions.save-as-draft",
117// [](Context *context) -> bool { 106 [](Context *context) -> bool {
118// return context->property("mail").isValid(); 107 auto accountId = context->property("accountId").value<QByteArray>();
119// }, 108 auto message = context->property("message").value<KMime::Message::Ptr>();
120// [](Context *context) { 109 return !accountId.isEmpty() && message;
121// Sink::Query query; 110 },
122// query += Sink::Query::RequestedProperties(QByteArrayList() << "name") 111 ActionHandlerHelper::JobHandler([](Context *context) -> KAsync::Job<void> {
123// //FIXME do something like specialuse? 112 qWarning() << "executing save as draft";
124// query += Sink::Query::PropertyFilter("name", "Drafts"); 113 const auto accountId = context->property("accountId").value<QByteArray>();
125// // query += Sink::Query::PropertyContainsFilter("specialuser", "drafts"); 114 const auto message = context->property("message").value<KMime::Message::Ptr>();
126// query += Sink::Query::PropertyFilter("drafts", true); 115 auto existingMail = context->property("existingMail").value<Sink::ApplicationDomain::Mail>();
127// //TODO Use drafts folder of that specific account 116 if (!message) {
128// Sink::Store::fetchAll<Sink::ApplicationDomain::Folder>(query) 117 qWarning() << "Failed to get the mail: " << context->property("mail");
129// .then<void, QList<Sink::ApplicationDomain::Folder>>([](const QList<Sink::ApplicationDomain::Folder> folders) { 118 return KAsync::error<void>(1, "Failed to get the mail: " + context->property("mail").toString());
130// if (folders.isEmpty()) { 119 }
131// return KAsync::start([]() { 120
132// //If message is already existing, modify, otherwise create 121 if (existingMail.identifier().isEmpty()) {
133// }); 122 Sink::Query query;
134// } 123 query += Sink::Query::RequestedProperties(QByteArrayList() << "name");
135// }); 124 query += Sink::Query::PropertyContainsFilter("specialpurpose", "drafts");
136// //TODO 125 query += Sink::Query::AccountFilter(accountId);
137// // * Find drafts folder 126 qWarning() << "fetching the drafts folder";
138// // * Store KMime::Message on disk for use in blob property 127 return Sink::Store::fetchAll<Sink::ApplicationDomain::Folder>(query)
139// // * Check if message is already existing and either create or update 128 .then<void, QList<Sink::ApplicationDomain::Folder::Ptr>>([=](const QList<Sink::ApplicationDomain::Folder::Ptr> folders) {
140// // * 129 qWarning() << "fetched a drafts folder" << folders.size();
141// // auto mail = context->property("mail").value<Sink::ApplicationDomain::Mail::Ptr>(); 130 if (folders.isEmpty()) {
142// // if (!mail) { 131 return KAsync::error<void>(1, "Failed to find a drafts folder.");
143// // qWarning() << "Failed to get the mail mail: " << context->property("mail"); 132 }
144// // return; 133 if (folders.size() > 1) {
145// // } 134 qWarning() << "Found too many draft folders (taking the first): " << folders;
146// // mail->setProperty("unread", false); 135 }
147// // qDebug() << "Mark as read " << mail->identifier(); 136 const auto folder = folders.first();
148// // Sink::Store::modify(*mail).exec(); 137 Sink::ApplicationDomain::Mail mail(folder->resourceInstanceIdentifier());
149// } 138 mail.setProperty("folder", folder->identifier());
150// ); 139 mail.setBlobProperty("mimeMessage", message->encodedContent());
140 return Sink::Store::create(mail);
141 })
142 .then<void>([](){
143 qWarning() << "done";
144 });
145 } else {
146 qWarning() << "Modifying an existing mail";
147 existingMail.setBlobProperty("mimeMessage", message->encodedContent());
148 return Sink::Store::modify(existingMail);
149 }
150 })
151);
diff --git a/framework/domain/actions/tests/CMakeLists.txt b/framework/domain/actions/tests/CMakeLists.txt
new file mode 100644
index 00000000..dc9d01b1
--- /dev/null
+++ b/framework/domain/actions/tests/CMakeLists.txt
@@ -0,0 +1,6 @@
1include_directories(${CMAKE_CURRENT_BINARY_DIR})
2cmake_policy(SET CMP0063 NEW)
3add_executable(sinkactiontest sinkactiontest.cpp)
4add_test(sinkactiontest sinkactiontest)
5qt5_use_modules(sinkactiontest Core Test Concurrent)
6target_link_libraries(sinkactiontest sink actionplugin KF5::Mime mailplugin)
diff --git a/framework/domain/actions/tests/sinkactiontest.cpp b/framework/domain/actions/tests/sinkactiontest.cpp
new file mode 100644
index 00000000..3e4567fd
--- /dev/null
+++ b/framework/domain/actions/tests/sinkactiontest.cpp
@@ -0,0 +1,60 @@
1#include <QTest>
2#include <QDebug>
3#include <QSignalSpy>
4#include <sink/test.h>
5#include <sink/store.h>
6#include <sink/log.h>
7#include <KMime/Message>
8
9#include <actions/action.h>
10#include <actions/context.h>
11
12using namespace Sink;
13
14class SinkActionTest : public QObject
15{
16 Q_OBJECT
17private slots:
18
19 void initTestCase()
20 {
21 Sink::Test::initTest();
22 Sink::Log::setDebugOutputLevel(Sink::Log::Trace);
23 }
24
25 void testSaveAsDraftFail()
26 {
27 Kube::Context context;
28 auto future = Kube::Action("org.kde.kube.actions.save-as-draft", context).execute();
29
30 QTRY_VERIFY(future.isDone());
31 //because of empty context
32 QVERIFY(future.error());
33 }
34
35 void testSaveAsDraftNew()
36 {
37 auto message = KMime::Message::Ptr::create();
38 message->subject(true)->fromUnicodeString(QString::fromLatin1("Foobar"), "utf8");
39 message->assemble();
40
41 auto &&account = Test::TestAccount::registerAccount();
42 auto folder = account.createEntity<ApplicationDomain::Folder>();
43 folder->setProperty("specialpurpose", QVariant::fromValue(QByteArrayList() << "drafts"));
44
45 Kube::Context context;
46 context.setProperty("message", QVariant::fromValue(message));
47 context.setProperty("accountId", QVariant::fromValue(account.identifier));
48 auto future = Kube::Action("org.kde.kube.actions.save-as-draft", context).execute();
49
50 QTRY_VERIFY(future.isDone());
51 QVERIFY(!future.error());
52 auto mails = account.entities<Sink::ApplicationDomain::Mail>();
53 QCOMPARE(mails.size(), 1);
54 auto mail = mails.first();
55 QCOMPARE(mail->getProperty("folder").toByteArray(), folder->identifier());
56 }
57};
58
59QTEST_GUILESS_MAIN(SinkActionTest)
60#include "sinkactiontest.moc"
diff --git a/framework/domain/composercontroller.cpp b/framework/domain/composercontroller.cpp
index bca90d33..0cf61442 100644
--- a/framework/domain/composercontroller.cpp
+++ b/framework/domain/composercontroller.cpp
@@ -185,9 +185,12 @@ void ComposerController::send()
185void ComposerController::saveAsDraft() 185void ComposerController::saveAsDraft()
186{ 186{
187 auto mail = assembleMessage(); 187 auto mail = assembleMessage();
188 auto currentAccountId = identityModel()->index(m_currentAccountIndex, 0).data(IdentitiesModel::AccountId).toByteArray();
189
188 Kube::Context context; 190 Kube::Context context;
189 context.setProperty("message", QVariant::fromValue(mail)); 191 context.setProperty("message", QVariant::fromValue(mail));
190 Kube::Action("org.kde.kube.actions.saveasdraft", context).execute(); 192 context.setProperty("accountId", QVariant::fromValue(currentAccountId));
193 Kube::Action("org.kde.kube.actions.save-as-draft", context).execute();
191 clear(); 194 clear();
192} 195}
193 196
diff --git a/framework/domain/maillistmodel.cpp b/framework/domain/maillistmodel.cpp
index 7cbc5587..2df3ecbc 100644
--- a/framework/domain/maillistmodel.cpp
+++ b/framework/domain/maillistmodel.cpp
@@ -111,10 +111,10 @@ void MailListModel::setParentFolder(const QVariant &parentFolder)
111 Sink::Query query; 111 Sink::Query query;
112 query.liveQuery = true; 112 query.liveQuery = true;
113 query.requestedProperties << "subject" << "sender" << "senderName" << "date" << "unread" << "important" << "folder"; 113 query.requestedProperties << "subject" << "sender" << "senderName" << "date" << "unread" << "important" << "folder";
114 query.propertyFilter.insert("folder", folder->identifier());
115 query.resources << folder->resourceInstanceIdentifier(); 114 query.resources << folder->resourceInstanceIdentifier();
116 query.sortProperty = "date"; 115 query.sortProperty = "date";
117 query.limit = 100; 116 query.limit = 100;
117 query += Sink::Query::PropertyFilter("folder", *folder);
118 qWarning() << "Running folder query: " << folder->resourceInstanceIdentifier() << folder->identifier(); 118 qWarning() << "Running folder query: " << folder->resourceInstanceIdentifier() << folder->identifier();
119 runQuery(query); 119 runQuery(query);
120} 120}