summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/CMakeLists.txt2
-rw-r--r--common/domain/applicationdomaintype.cpp13
-rw-r--r--common/domain/applicationdomaintype.h17
-rw-r--r--common/domain/applicationdomaintype_p.h2
-rw-r--r--common/domain/propertyregistry.cpp6
-rw-r--r--common/domain/todo.fbs18
-rw-r--r--common/domain/typeimplementations.cpp35
-rw-r--r--common/domain/typeimplementations.h12
-rw-r--r--common/propertymapper.cpp36
-rw-r--r--common/propertymapper.h8
-rw-r--r--common/synchronizer.cpp7
-rw-r--r--common/synchronizer.h1
-rw-r--r--common/todopreprocessor.cpp67
-rw-r--r--common/todopreprocessor.h35
-rw-r--r--examples/caldavresource/caldavresource.cpp105
-rw-r--r--examples/caldavresource/tests/caldavtest.cpp111
16 files changed, 432 insertions, 43 deletions
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index 40c955e..c8e178a 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -71,6 +71,7 @@ set(command_SRCS
71 contactpreprocessor.cpp 71 contactpreprocessor.cpp
72 mailpreprocessor.cpp 72 mailpreprocessor.cpp
73 eventpreprocessor.cpp 73 eventpreprocessor.cpp
74 todopreprocessor.cpp
74 specialpurposepreprocessor.cpp 75 specialpurposepreprocessor.cpp
75 datastorequery.cpp 76 datastorequery.cpp
76 storage/entitystore.cpp 77 storage/entitystore.cpp
@@ -105,6 +106,7 @@ generate_flatbuffers(
105 domain/contact 106 domain/contact
106 domain/addressbook 107 domain/addressbook
107 domain/event 108 domain/event
109 domain/todo
108 domain/calendar 110 domain/calendar
109 domain/mail 111 domain/mail
110 domain/folder 112 domain/folder
diff --git a/common/domain/applicationdomaintype.cpp b/common/domain/applicationdomaintype.cpp
index 78d46ee..b1469e1 100644
--- a/common/domain/applicationdomaintype.cpp
+++ b/common/domain/applicationdomaintype.cpp
@@ -132,6 +132,19 @@ SINK_REGISTER_PROPERTY(Event, EndTime);
132SINK_REGISTER_PROPERTY(Event, Ical); 132SINK_REGISTER_PROPERTY(Event, Ical);
133SINK_REGISTER_PROPERTY(Event, Calendar); 133SINK_REGISTER_PROPERTY(Event, Calendar);
134 134
135SINK_REGISTER_ENTITY(Todo);
136SINK_REGISTER_PROPERTY(Todo, Uid);
137SINK_REGISTER_PROPERTY(Todo, Summary);
138SINK_REGISTER_PROPERTY(Todo, Description);
139SINK_REGISTER_PROPERTY(Todo, CompletedDate);
140SINK_REGISTER_PROPERTY(Todo, DueDate);
141SINK_REGISTER_PROPERTY(Todo, StartDate);
142SINK_REGISTER_PROPERTY(Todo, Status);
143SINK_REGISTER_PROPERTY(Todo, Priority);
144SINK_REGISTER_PROPERTY(Todo, Categories);
145SINK_REGISTER_PROPERTY(Todo, Ical);
146SINK_REGISTER_PROPERTY(Todo, Calendar);
147
135SINK_REGISTER_ENTITY(Calendar); 148SINK_REGISTER_ENTITY(Calendar);
136SINK_REGISTER_PROPERTY(Calendar, Name); 149SINK_REGISTER_PROPERTY(Calendar, Name);
137 150
diff --git a/common/domain/applicationdomaintype.h b/common/domain/applicationdomaintype.h
index 39e66ab..93de8f5 100644
--- a/common/domain/applicationdomaintype.h
+++ b/common/domain/applicationdomaintype.h
@@ -407,6 +407,17 @@ struct SINK_EXPORT Event : public Entity {
407 407
408struct SINK_EXPORT Todo : public Entity { 408struct SINK_EXPORT Todo : public Entity {
409 SINK_ENTITY(Todo, todo); 409 SINK_ENTITY(Todo, todo);
410 SINK_EXTRACTED_PROPERTY(QString, Uid, uid);
411 SINK_EXTRACTED_PROPERTY(QString, Summary, summary);
412 SINK_EXTRACTED_PROPERTY(QString, Description, description);
413 SINK_EXTRACTED_PROPERTY(QDateTime, CompletedDate, completedDate);
414 SINK_EXTRACTED_PROPERTY(QDateTime, DueDate, dueDate);
415 SINK_EXTRACTED_PROPERTY(QDateTime, StartDate, startDate);
416 SINK_EXTRACTED_PROPERTY(QString, Status, status);
417 SINK_EXTRACTED_PROPERTY(int, Priority, priority);
418 SINK_EXTRACTED_PROPERTY(QStringList, Categories, categories);
419 SINK_PROPERTY(QByteArray, Ical, ical);
420 SINK_REFERENCE_PROPERTY(Calendar, Calendar, calendar);
410}; 421};
411 422
412struct SINK_EXPORT Folder : public Entity { 423struct SINK_EXPORT Folder : public Entity {
@@ -506,6 +517,11 @@ namespace Event {
506 static constexpr const char *calendar = "calendar"; 517 static constexpr const char *calendar = "calendar";
507 static constexpr const char *storage = "event.storage"; 518 static constexpr const char *storage = "event.storage";
508}; 519};
520namespace Todo {
521 static constexpr const char *todo = "todo";
522 static constexpr const char *calendar = "calendar";
523 static constexpr const char *storage = "todo.storage";
524};
509}; 525};
510 526
511namespace SpecialPurpose { 527namespace SpecialPurpose {
@@ -558,6 +574,7 @@ class SINK_EXPORT TypeImplementation;
558 REGISTER_TYPE(Sink::ApplicationDomain::Contact) \ 574 REGISTER_TYPE(Sink::ApplicationDomain::Contact) \
559 REGISTER_TYPE(Sink::ApplicationDomain::Addressbook) \ 575 REGISTER_TYPE(Sink::ApplicationDomain::Addressbook) \
560 REGISTER_TYPE(Sink::ApplicationDomain::Event) \ 576 REGISTER_TYPE(Sink::ApplicationDomain::Event) \
577 REGISTER_TYPE(Sink::ApplicationDomain::Todo) \
561 REGISTER_TYPE(Sink::ApplicationDomain::Calendar) \ 578 REGISTER_TYPE(Sink::ApplicationDomain::Calendar) \
562 REGISTER_TYPE(Sink::ApplicationDomain::Mail) \ 579 REGISTER_TYPE(Sink::ApplicationDomain::Mail) \
563 REGISTER_TYPE(Sink::ApplicationDomain::Folder) \ 580 REGISTER_TYPE(Sink::ApplicationDomain::Folder) \
diff --git a/common/domain/applicationdomaintype_p.h b/common/domain/applicationdomaintype_p.h
index 734ac3e..248f6f0 100644
--- a/common/domain/applicationdomaintype_p.h
+++ b/common/domain/applicationdomaintype_p.h
@@ -38,6 +38,8 @@ struct TypeHelper {
38 return Func<Sink::ApplicationDomain::Mail>{}(std::forward<Args...>(args...)); 38 return Func<Sink::ApplicationDomain::Mail>{}(std::forward<Args...>(args...));
39 } else if (type == Sink::ApplicationDomain::getTypeName<Sink::ApplicationDomain::Event>()) { 39 } else if (type == Sink::ApplicationDomain::getTypeName<Sink::ApplicationDomain::Event>()) {
40 return Func<Sink::ApplicationDomain::Event>{}(std::forward<Args...>(args...)); 40 return Func<Sink::ApplicationDomain::Event>{}(std::forward<Args...>(args...));
41 } else if (type == Sink::ApplicationDomain::getTypeName<Sink::ApplicationDomain::Todo>()) {
42 return Func<Sink::ApplicationDomain::Todo>{}(std::forward<Args...>(args...));
41 } else if (type == Sink::ApplicationDomain::getTypeName<Sink::ApplicationDomain::Calendar>()) { 43 } else if (type == Sink::ApplicationDomain::getTypeName<Sink::ApplicationDomain::Calendar>()) {
42 return Func<Sink::ApplicationDomain::Calendar>{}(std::forward<Args...>(args...)); 44 return Func<Sink::ApplicationDomain::Calendar>{}(std::forward<Args...>(args...));
43 } else if (type == Sink::ApplicationDomain::getTypeName<Sink::ApplicationDomain::Contact>()) { 45 } else if (type == Sink::ApplicationDomain::getTypeName<Sink::ApplicationDomain::Contact>()) {
diff --git a/common/domain/propertyregistry.cpp b/common/domain/propertyregistry.cpp
index d929d68..00bbb1d 100644
--- a/common/domain/propertyregistry.cpp
+++ b/common/domain/propertyregistry.cpp
@@ -75,6 +75,12 @@ QVariant parseString<QList<QByteArray>>(const QString &s)
75} 75}
76 76
77template <> 77template <>
78QVariant parseString<QStringList>(const QString &s)
79{
80 return s.split(',');
81}
82
83template <>
78QVariant parseString<QDateTime>(const QString &s) 84QVariant parseString<QDateTime>(const QString &s)
79{ 85{
80 return QVariant::fromValue(QDateTime::fromString(s, Qt::ISODate)); 86 return QVariant::fromValue(QDateTime::fromString(s, Qt::ISODate));
diff --git a/common/domain/todo.fbs b/common/domain/todo.fbs
new file mode 100644
index 0000000..b448cae
--- /dev/null
+++ b/common/domain/todo.fbs
@@ -0,0 +1,18 @@
1namespace Sink.ApplicationDomain.Buffer;
2
3table Todo {
4 uid:string;
5 summary:string;
6 description:string;
7 completedDate:string;
8 dueDate:string;
9 startDate:string;
10 status:string;
11 priority:int;
12 categories:[string];
13 ical:string;
14 calendar:string;
15}
16
17root_type Todo;
18file_identifier "AKFB";
diff --git a/common/domain/typeimplementations.cpp b/common/domain/typeimplementations.cpp
index 615c8e8..b584138 100644
--- a/common/domain/typeimplementations.cpp
+++ b/common/domain/typeimplementations.cpp
@@ -67,6 +67,10 @@ typedef IndexConfig<Event,
67 ValueIndex<Event::Uid> 67 ValueIndex<Event::Uid>
68 > EventIndexConfig; 68 > EventIndexConfig;
69 69
70typedef IndexConfig<Todo,
71 ValueIndex<Todo::Uid>
72 > TodoIndexConfig;
73
70typedef IndexConfig<Calendar, 74typedef IndexConfig<Calendar,
71 ValueIndex<Calendar::Name> 75 ValueIndex<Calendar::Name>
72 > CalendarIndexConfig; 76 > CalendarIndexConfig;
@@ -218,6 +222,37 @@ void TypeImplementation<Event>::configure(IndexPropertyMapper &)
218} 222}
219 223
220 224
225void TypeImplementation<Todo>::configure(TypeIndex &index)
226{
227 TodoIndexConfig::configure(index);
228}
229
230QMap<QByteArray, int> TypeImplementation<Todo>::typeDatabases()
231{
232 return merge(QMap<QByteArray, int>{{QByteArray{Todo::name} + ".main", 0}}, TodoIndexConfig::databases());
233}
234
235void TypeImplementation<Todo>::configure(PropertyMapper &propertyMapper)
236{
237 SINK_REGISTER_SERIALIZER(propertyMapper, Todo, Uid, uid);
238 SINK_REGISTER_SERIALIZER(propertyMapper, Todo, Summary, summary);
239 SINK_REGISTER_SERIALIZER(propertyMapper, Todo, Description, description);
240 SINK_REGISTER_SERIALIZER(propertyMapper, Todo, CompletedDate, completedDate);
241 SINK_REGISTER_SERIALIZER(propertyMapper, Todo, DueDate, dueDate);
242 SINK_REGISTER_SERIALIZER(propertyMapper, Todo, StartDate, startDate);
243 SINK_REGISTER_SERIALIZER(propertyMapper, Todo, Status, status);
244 SINK_REGISTER_SERIALIZER(propertyMapper, Todo, Priority, priority);
245 SINK_REGISTER_SERIALIZER(propertyMapper, Todo, Categories, categories);
246 SINK_REGISTER_SERIALIZER(propertyMapper, Todo, Ical, ical);
247 SINK_REGISTER_SERIALIZER(propertyMapper, Todo, Calendar, calendar);
248}
249
250void TypeImplementation<Todo>::configure(IndexPropertyMapper &)
251{
252
253}
254
255
221void TypeImplementation<Calendar>::configure(TypeIndex &index) 256void TypeImplementation<Calendar>::configure(TypeIndex &index)
222{ 257{
223 CalendarIndexConfig::configure(index); 258 CalendarIndexConfig::configure(index);
diff --git a/common/domain/typeimplementations.h b/common/domain/typeimplementations.h
index 672e83a..5c6ba14 100644
--- a/common/domain/typeimplementations.h
+++ b/common/domain/typeimplementations.h
@@ -24,6 +24,7 @@
24#include "mail_generated.h" 24#include "mail_generated.h"
25#include "folder_generated.h" 25#include "folder_generated.h"
26#include "event_generated.h" 26#include "event_generated.h"
27#include "todo_generated.h"
27#include "calendar_generated.h" 28#include "calendar_generated.h"
28#include "contact_generated.h" 29#include "contact_generated.h"
29#include "addressbook_generated.h" 30#include "addressbook_generated.h"
@@ -97,6 +98,17 @@ public:
97}; 98};
98 99
99template<> 100template<>
101class SINK_EXPORT TypeImplementation<Sink::ApplicationDomain::Todo> {
102public:
103 typedef Sink::ApplicationDomain::Buffer::Todo Buffer;
104 typedef Sink::ApplicationDomain::Buffer::TodoBuilder BufferBuilder;
105 static void configure(TypeIndex &);
106 static void configure(PropertyMapper &);
107 static void configure(IndexPropertyMapper &indexPropertyMapper);
108 static QMap<QByteArray, int> typeDatabases();
109};
110
111template<>
100class SINK_EXPORT TypeImplementation<Sink::ApplicationDomain::Calendar> { 112class SINK_EXPORT TypeImplementation<Sink::ApplicationDomain::Calendar> {
101public: 113public:
102 typedef Sink::ApplicationDomain::Buffer::Calendar Buffer; 114 typedef Sink::ApplicationDomain::Buffer::Calendar Buffer;
diff --git a/common/propertymapper.cpp b/common/propertymapper.cpp
index 7c313cc..f9f9c9b 100644
--- a/common/propertymapper.cpp
+++ b/common/propertymapper.cpp
@@ -82,6 +82,21 @@ flatbuffers::uoffset_t variantToProperty<QByteArrayList>(const QVariant &propert
82} 82}
83 83
84template <> 84template <>
85flatbuffers::uoffset_t variantToProperty<QStringList>(const QVariant &property, flatbuffers::FlatBufferBuilder &fbb)
86{
87 if (property.isValid()) {
88 const auto list = property.value<QStringList>();
89 std::vector<flatbuffers::Offset<flatbuffers::String>> vector;
90 for (const auto &value : list) {
91 auto offset = fbb.CreateString(value.toStdString());
92 vector.push_back(offset);
93 }
94 return fbb.CreateVector(vector).o;
95 }
96 return 0;
97}
98
99template <>
85flatbuffers::uoffset_t variantToProperty<Sink::ApplicationDomain::Mail::Contact>(const QVariant &property, flatbuffers::FlatBufferBuilder &fbb) 100flatbuffers::uoffset_t variantToProperty<Sink::ApplicationDomain::Mail::Contact>(const QVariant &property, flatbuffers::FlatBufferBuilder &fbb)
86{ 101{
87 if (property.isValid()) { 102 if (property.isValid()) {
@@ -187,6 +202,21 @@ QVariant propertyToVariant<QByteArrayList>(const flatbuffers::Vector<flatbuffers
187} 202}
188 203
189template <> 204template <>
205QVariant propertyToVariant<QStringList>(const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *property)
206{
207 if (property) {
208 QStringList list;
209 for (auto it = property->begin(); it != property->end();) {
210 // We have to copy the memory, otherwise it would become eventually invalid
211 list << QString::fromStdString((*it)->str());
212 it.operator++();
213 }
214 return QVariant::fromValue(list);
215 }
216 return QVariant();
217}
218
219template <>
190QVariant propertyToVariant<Sink::ApplicationDomain::Mail::Contact>(const Sink::ApplicationDomain::Buffer::MailContact *property) 220QVariant propertyToVariant<Sink::ApplicationDomain::Mail::Contact>(const Sink::ApplicationDomain::Buffer::MailContact *property)
191{ 221{
192 if (property) { 222 if (property) {
@@ -232,6 +262,12 @@ QVariant propertyToVariant<bool>(uint8_t property)
232} 262}
233 263
234template <> 264template <>
265QVariant propertyToVariant<int>(uint8_t property)
266{
267 return static_cast<int>(property);
268}
269
270template <>
235QVariant propertyToVariant<QDateTime>(const flatbuffers::String *property) 271QVariant propertyToVariant<QDateTime>(const flatbuffers::String *property)
236{ 272{
237 if (property) { 273 if (property) {
diff --git a/common/propertymapper.h b/common/propertymapper.h
index fd24278..49224fa 100644
--- a/common/propertymapper.h
+++ b/common/propertymapper.h
@@ -131,6 +131,14 @@ private:
131 } 131 }
132 132
133 template <typename T, typename BufferBuilder> 133 template <typename T, typename BufferBuilder>
134 void addWriteMapping(void (BufferBuilder::*f)(int))
135 {
136 addWriteMapping(T::name, [f](const QVariant &value, flatbuffers::FlatBufferBuilder &fbb) -> std::function<void(void *builder)> {
137 return [value, f](void *builder) { (static_cast<BufferBuilder*>(builder)->*f)(value.value<typename T::Type>()); };
138 });
139 }
140
141 template <typename T, typename BufferBuilder>
134 void addWriteMapping(void (BufferBuilder::*f)(bool)) 142 void addWriteMapping(void (BufferBuilder::*f)(bool))
135 { 143 {
136 addWriteMapping(T::name, [f](const QVariant &value, flatbuffers::FlatBufferBuilder &fbb) -> std::function<void(void *builder)> { 144 addWriteMapping(T::name, [f](const QVariant &value, flatbuffers::FlatBufferBuilder &fbb) -> std::function<void(void *builder)> {
diff --git a/common/synchronizer.cpp b/common/synchronizer.cpp
index fa16002..1a5810d 100644
--- a/common/synchronizer.cpp
+++ b/common/synchronizer.cpp
@@ -634,6 +634,8 @@ KAsync::Job<void> Synchronizer::replay(const QByteArray &type, const QByteArray
634 job = replay(store().readEntity<ApplicationDomain::Addressbook>(key), operation, oldRemoteId, modifiedProperties); 634 job = replay(store().readEntity<ApplicationDomain::Addressbook>(key), operation, oldRemoteId, modifiedProperties);
635 } else if (type == ApplicationDomain::getTypeName<ApplicationDomain::Event>()) { 635 } else if (type == ApplicationDomain::getTypeName<ApplicationDomain::Event>()) {
636 job = replay(store().readEntity<ApplicationDomain::Event>(key), operation, oldRemoteId, modifiedProperties); 636 job = replay(store().readEntity<ApplicationDomain::Event>(key), operation, oldRemoteId, modifiedProperties);
637 } else if (type == ApplicationDomain::getTypeName<ApplicationDomain::Todo>()) {
638 job = replay(store().readEntity<ApplicationDomain::Todo>(key), operation, oldRemoteId, modifiedProperties);
637 } else if (type == ApplicationDomain::getTypeName<ApplicationDomain::Calendar>()) { 639 } else if (type == ApplicationDomain::getTypeName<ApplicationDomain::Calendar>()) {
638 job = replay(store().readEntity<ApplicationDomain::Calendar>(key), operation, oldRemoteId, modifiedProperties); 640 job = replay(store().readEntity<ApplicationDomain::Calendar>(key), operation, oldRemoteId, modifiedProperties);
639 } else { 641 } else {
@@ -697,6 +699,11 @@ KAsync::Job<QByteArray> Synchronizer::replay(const ApplicationDomain::Event &, S
697 return KAsync::null<QByteArray>(); 699 return KAsync::null<QByteArray>();
698} 700}
699 701
702KAsync::Job<QByteArray> Synchronizer::replay(const ApplicationDomain::Todo &, Sink::Operation, const QByteArray &, const QList<QByteArray> &)
703{
704 return KAsync::null<QByteArray>();
705}
706
700KAsync::Job<QByteArray> Synchronizer::replay(const ApplicationDomain::Calendar &, Sink::Operation, const QByteArray &, const QList<QByteArray> &) 707KAsync::Job<QByteArray> Synchronizer::replay(const ApplicationDomain::Calendar &, Sink::Operation, const QByteArray &, const QList<QByteArray> &)
701{ 708{
702 return KAsync::null<QByteArray>(); 709 return KAsync::null<QByteArray>();
diff --git a/common/synchronizer.h b/common/synchronizer.h
index 2a3c3d8..fffd705 100644
--- a/common/synchronizer.h
+++ b/common/synchronizer.h
@@ -80,6 +80,7 @@ protected:
80 virtual KAsync::Job<QByteArray> replay(const Sink::ApplicationDomain::Mail &, Sink::Operation, const QByteArray &oldRemoteId, const QList<QByteArray> &); 80 virtual KAsync::Job<QByteArray> replay(const Sink::ApplicationDomain::Mail &, Sink::Operation, const QByteArray &oldRemoteId, const QList<QByteArray> &);
81 virtual KAsync::Job<QByteArray> replay(const Sink::ApplicationDomain::Folder &, Sink::Operation, const QByteArray &oldRemoteId, const QList<QByteArray> &); 81 virtual KAsync::Job<QByteArray> replay(const Sink::ApplicationDomain::Folder &, Sink::Operation, const QByteArray &oldRemoteId, const QList<QByteArray> &);
82 virtual KAsync::Job<QByteArray> replay(const Sink::ApplicationDomain::Event &, Sink::Operation, const QByteArray &oldRemoteId, const QList<QByteArray> &); 82 virtual KAsync::Job<QByteArray> replay(const Sink::ApplicationDomain::Event &, Sink::Operation, const QByteArray &oldRemoteId, const QList<QByteArray> &);
83 virtual KAsync::Job<QByteArray> replay(const Sink::ApplicationDomain::Todo &, Sink::Operation, const QByteArray &oldRemoteId, const QList<QByteArray> &);
83 virtual KAsync::Job<QByteArray> replay(const Sink::ApplicationDomain::Calendar &, Sink::Operation, const QByteArray &oldRemoteId, const QList<QByteArray> &); 84 virtual KAsync::Job<QByteArray> replay(const Sink::ApplicationDomain::Calendar &, Sink::Operation, const QByteArray &oldRemoteId, const QList<QByteArray> &);
84protected: 85protected:
85 QString secret() const; 86 QString secret() const;
diff --git a/common/todopreprocessor.cpp b/common/todopreprocessor.cpp
new file mode 100644
index 0000000..fe99953
--- /dev/null
+++ b/common/todopreprocessor.cpp
@@ -0,0 +1,67 @@
1/*
2 * Copyright (C) 2018 Christian Mollekopf <chrigi_1@fastmail.fm>
3 * Copyright (C) 2018 Rémi Nicole <minijackson@riseup.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the
17 * Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include "todopreprocessor.h"
22
23#include <KCalCore/ICalFormat>
24
25void TodoPropertyExtractor::updatedIndexedProperties(Todo &todo, const QByteArray &rawIcal)
26{
27 auto incidence = KCalCore::ICalFormat().readIncidence(rawIcal);
28
29 if(!incidence) {
30 SinkWarning() << "Invalid ICal to process, ignoring...";
31 return;
32 }
33
34 if(incidence->type() != KCalCore::IncidenceBase::IncidenceType::TypeTodo) {
35 SinkWarning() << "ICal to process is not of type `Todo`, ignoring...";
36 return;
37 }
38
39 auto icalTodo = dynamic_cast<const KCalCore::Todo *>(incidence.data());
40 // Should be guaranteed by the incidence->type() condition above.
41 Q_ASSERT(icalTodo);
42
43 SinkTrace() << "Extracting properties for todo:" << icalTodo->summary();
44
45 todo.setExtractedUid(icalTodo->uid());
46 todo.setExtractedSummary(icalTodo->summary());
47 todo.setExtractedDescription(icalTodo->description());
48
49 // Sets invalid QDateTime if not defined
50 todo.setExtractedCompletedDate(icalTodo->completed());
51 todo.setExtractedDueDate(icalTodo->dtDue());
52 todo.setExtractedStartDate(icalTodo->dtStart());
53
54 todo.setExtractedStatus(icalTodo->customStatus());
55 todo.setExtractedPriority(icalTodo->priority());
56 todo.setExtractedCategories(icalTodo->categories());
57}
58
59void TodoPropertyExtractor::newEntity(Todo &todo)
60{
61 updatedIndexedProperties(todo, todo.getIcal());
62}
63
64void TodoPropertyExtractor::modifiedEntity(const Todo &oldTodo, Todo &newTodo)
65{
66 updatedIndexedProperties(newTodo, newTodo.getIcal());
67}
diff --git a/common/todopreprocessor.h b/common/todopreprocessor.h
new file mode 100644
index 0000000..ccb9f1a
--- /dev/null
+++ b/common/todopreprocessor.h
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2018 Christian Mollekopf <chrigi_1@fastmail.fm>
3 * Copyright (C) 2018 Rémi Nicole <minijackson@riseup.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the
17 * Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include "pipeline.h"
22#include "sink_export.h"
23
24class SINK_EXPORT TodoPropertyExtractor : public Sink::EntityPreprocessor<Sink::ApplicationDomain::Todo>
25{
26 using Todo = Sink::ApplicationDomain::Todo;
27
28public:
29 virtual ~TodoPropertyExtractor() {}
30 virtual void newEntity(Todo &todo) Q_DECL_OVERRIDE;
31 virtual void modifiedEntity(const Todo &oldTodo, Todo &newTodo) Q_DECL_OVERRIDE;
32
33private:
34 static void updatedIndexedProperties(Todo &todo, const QByteArray &rawIcal);
35};
diff --git a/examples/caldavresource/caldavresource.cpp b/examples/caldavresource/caldavresource.cpp
index d9f8c69..d33f625 100644
--- a/examples/caldavresource/caldavresource.cpp
+++ b/examples/caldavresource/caldavresource.cpp
@@ -25,25 +25,29 @@
25#include "applicationdomaintype.h" 25#include "applicationdomaintype.h"
26#include "domainadaptor.h" 26#include "domainadaptor.h"
27#include "eventpreprocessor.h" 27#include "eventpreprocessor.h"
28#include "todopreprocessor.h"
28#include "facade.h" 29#include "facade.h"
29#include "facadefactory.h" 30#include "facadefactory.h"
30 31
31#include <KCalCore/ICalFormat> 32#include <KCalCore/ICalFormat>
32 33
33#define ENTITY_TYPE_EVENT "event" 34#define ENTITY_TYPE_EVENT "event"
35#define ENTITY_TYPE_TODO "todo"
34#define ENTITY_TYPE_CALENDAR "calendar" 36#define ENTITY_TYPE_CALENDAR "calendar"
35 37
36using Sink::ApplicationDomain::getTypeName; 38using Sink::ApplicationDomain::getTypeName;
37 39
38class EventSynchronizer : public WebDavSynchronizer 40class CalDAVSynchronizer : public WebDavSynchronizer
39{ 41{
40 using Event = Sink::ApplicationDomain::Event; 42 using Event = Sink::ApplicationDomain::Event;
43 using Todo = Sink::ApplicationDomain::Todo;
41 using Calendar = Sink::ApplicationDomain::Calendar; 44 using Calendar = Sink::ApplicationDomain::Calendar;
42 45
43public: 46public:
44 explicit EventSynchronizer(const Sink::ResourceContext &context) 47 explicit CalDAVSynchronizer(const Sink::ResourceContext &context)
45 : WebDavSynchronizer(context, KDAV2::CalDav, getTypeName<Calendar>(), getTypeName<Event>()) 48 : WebDavSynchronizer(context, KDAV2::CalDav, getTypeName<Calendar>(), getTypeName<Event>())
46 {} 49 {
50 }
47 51
48protected: 52protected:
49 void updateLocalCollections(KDAV2::DavCollection::List calendarList) Q_DECL_OVERRIDE 53 void updateLocalCollections(KDAV2::DavCollection::List calendarList) Q_DECL_OVERRIDE
@@ -74,21 +78,27 @@ protected:
74 78
75 switch (incidence->type()) { 79 switch (incidence->type()) {
76 case Type::TypeEvent: { 80 case Type::TypeEvent: {
77 auto remoteEvent = dynamic_cast<const KCalCore::Event &>(*incidence);
78
79 Event localEvent; 81 Event localEvent;
80 localEvent.setIcal(ical); 82 localEvent.setIcal(ical);
81 localEvent.setCalendar(calendarLocalId); 83 localEvent.setCalendar(calendarLocalId);
82 84
83 SinkTrace() << "Found an event:" << localEvent.getSummary() << "with id:" << rid; 85 SinkTrace() << "Found an event with id:" << rid;
84 86
85 createOrModify(ENTITY_TYPE_EVENT, rid, localEvent, 87 createOrModify(ENTITY_TYPE_EVENT, rid, localEvent,
86 /* mergeCriteria = */ QHash<QByteArray, Sink::Query::Comparator>{}); 88 /* mergeCriteria = */ QHash<QByteArray, Sink::Query::Comparator>{});
87 break; 89 break;
88 } 90 }
89 case Type::TypeTodo: 91 case Type::TypeTodo: {
90 SinkWarning() << "Unimplemented add of a 'Todo' item in the Store"; 92 Todo localTodo;
93 localTodo.setIcal(ical);
94 localTodo.setCalendar(calendarLocalId);
95
96 SinkTrace() << "Found a Todo with id:" << rid;
97
98 createOrModify(ENTITY_TYPE_TODO, rid, localTodo,
99 /* mergeCriteria = */ QHash<QByteArray, Sink::Query::Comparator>{});
91 break; 100 break;
101 }
92 case Type::TypeJournal: 102 case Type::TypeJournal:
93 SinkWarning() << "Unimplemented add of a 'Journal' item in the Store"; 103 SinkWarning() << "Unimplemented add of a 'Journal' item in the Store";
94 break; 104 break;
@@ -108,58 +118,74 @@ protected:
108 return syncStore().resolveRemoteId(ENTITY_TYPE_CALENDAR, resourceID(calendar)); 118 return syncStore().resolveRemoteId(ENTITY_TYPE_CALENDAR, resourceID(calendar));
109 } 119 }
110 120
111 KAsync::Job<QByteArray> replay(const Event &event, Sink::Operation operation, 121 template<typename Item>
112 const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE 122 KAsync::Job<QByteArray> replayItem(const Item &localItem, Sink::Operation operation,
123 const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties,
124 const QByteArray &entityType)
113 { 125 {
114 SinkLog() << "Replaying event"; 126 SinkLog() << "Replaying" << entityType;
115 127
116 KDAV2::DavItem item; 128 KDAV2::DavItem remoteItem;
117 129
118 switch (operation) { 130 switch (operation) {
119 case Sink::Operation_Creation: { 131 case Sink::Operation_Creation: {
120 auto rawIcal = event.getIcal(); 132 auto rawIcal = localItem.getIcal();
121 if(rawIcal == "") { 133 if (rawIcal == "") {
122 return KAsync::error<QByteArray>("No ICal in event for creation replay"); 134 return KAsync::error<QByteArray>("No ICal in item for creation replay");
123 } 135 }
124 136
125 auto collectionId = syncStore().resolveLocalId(ENTITY_TYPE_CALENDAR, event.getCalendar()); 137 auto collectionId = syncStore().resolveLocalId(ENTITY_TYPE_CALENDAR, localItem.getCalendar());
126 138
127 item.setData(rawIcal); 139 remoteItem.setData(rawIcal);
128 item.setContentType("text/calendar"); 140 remoteItem.setContentType("text/calendar");
129 item.setUrl(urlOf(collectionId, event.getUid())); 141 remoteItem.setUrl(urlOf(collectionId, localItem.getUid()));
130 142
131 SinkLog() << "Creating event:" << event.getSummary(); 143 SinkLog() << "Creating" << entityType << ":" << localItem.getSummary();
132 return createItem(item).then([item] { return resourceID(item); }); 144 return createItem(remoteItem).then([remoteItem] { return resourceID(remoteItem); });
133 } 145 }
134 case Sink::Operation_Removal: { 146 case Sink::Operation_Removal: {
135 // We only need the URL in the DAV item for removal 147 // We only need the URL in the DAV item for removal
136 item.setUrl(urlOf(oldRemoteId)); 148 remoteItem.setUrl(urlOf(oldRemoteId));
137 149
138 SinkLog() << "Removing event:" << oldRemoteId; 150 SinkLog() << "Removing" << entityType << ":" << oldRemoteId;
139 return removeItem(item).then([] { return QByteArray{}; }); 151 return removeItem(remoteItem).then([] { return QByteArray{}; });
140 } 152 }
141 case Sink::Operation_Modification: 153 case Sink::Operation_Modification:
142 auto rawIcal = event.getIcal(); 154 auto rawIcal = localItem.getIcal();
143 if(rawIcal == "") { 155 if (rawIcal == "") {
144 return KAsync::error<QByteArray>("No ICal in event for modification replay"); 156 return KAsync::error<QByteArray>("No ICal in item for modification replay");
145 } 157 }
146 158
147 item.setData(rawIcal); 159 remoteItem.setData(rawIcal);
148 item.setContentType("text/calendar"); 160 remoteItem.setContentType("text/calendar");
149 item.setUrl(urlOf(oldRemoteId)); 161 remoteItem.setUrl(urlOf(oldRemoteId));
150 162
151 SinkLog() << "Modifying event:" << event.getSummary(); 163 SinkLog() << "Modifying" << entityType << ":" << localItem.getSummary();
152 164
153 // It would be nice to check that the URL of the item hasn't 165 // It would be nice to check that the URL of the item hasn't
154 // changed and move he item if it did, but since the URL is 166 // changed and move he item if it did, but since the URL is
155 // pretty much arbitrary, whoe does that anyway? 167 // pretty much arbitrary, whoe does that anyway?
156 return modifyItem(item).then([oldRemoteId] { return oldRemoteId; }); 168 return modifyItem(remoteItem).then([oldRemoteId] { return oldRemoteId; });
157 } 169 }
158 } 170 }
159 171
172 KAsync::Job<QByteArray> replay(const Event &event, Sink::Operation operation,
173 const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE
174 {
175 return replayItem(event, operation, oldRemoteId, changedProperties, ENTITY_TYPE_EVENT);
176 }
177
178 KAsync::Job<QByteArray> replay(const Todo &todo, Sink::Operation operation,
179 const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE
180 {
181 return replayItem(todo, operation, oldRemoteId, changedProperties, ENTITY_TYPE_TODO);
182 }
183
160 KAsync::Job<QByteArray> replay(const Calendar &calendar, Sink::Operation operation, 184 KAsync::Job<QByteArray> replay(const Calendar &calendar, Sink::Operation operation,
161 const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE 185 const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE
162 { 186 {
187 SinkLog() << "Replaying calendar";
188
163 switch (operation) { 189 switch (operation) {
164 case Sink::Operation_Creation: 190 case Sink::Operation_Creation:
165 SinkWarning() << "Unimplemented replay of calendar creation"; 191 SinkWarning() << "Unimplemented replay of calendar creation";
@@ -180,19 +206,23 @@ protected:
180CalDavResource::CalDavResource(const Sink::ResourceContext &context) 206CalDavResource::CalDavResource(const Sink::ResourceContext &context)
181 : Sink::GenericResource(context) 207 : Sink::GenericResource(context)
182{ 208{
183 auto synchronizer = QSharedPointer<EventSynchronizer>::create(context); 209 auto synchronizer = QSharedPointer<CalDAVSynchronizer>::create(context);
184 setupSynchronizer(synchronizer); 210 setupSynchronizer(synchronizer);
185 211
186 setupPreprocessors(ENTITY_TYPE_EVENT, QVector<Sink::Preprocessor*>() << new EventPropertyExtractor); 212 setupPreprocessors(ENTITY_TYPE_EVENT, QVector<Sink::Preprocessor *>() << new EventPropertyExtractor);
213 setupPreprocessors(ENTITY_TYPE_TODO, QVector<Sink::Preprocessor *>() << new TodoPropertyExtractor);
187} 214}
188 215
189CalDavResourceFactory::CalDavResourceFactory(QObject *parent) 216CalDavResourceFactory::CalDavResourceFactory(QObject *parent)
190 : Sink::ResourceFactory(parent, { 217 : Sink::ResourceFactory(parent, {
191 Sink::ApplicationDomain::ResourceCapabilities::Event::event,
192 Sink::ApplicationDomain::ResourceCapabilities::Event::calendar, 218 Sink::ApplicationDomain::ResourceCapabilities::Event::calendar,
219 Sink::ApplicationDomain::ResourceCapabilities::Event::event,
193 Sink::ApplicationDomain::ResourceCapabilities::Event::storage, 220 Sink::ApplicationDomain::ResourceCapabilities::Event::storage,
221 Sink::ApplicationDomain::ResourceCapabilities::Todo::todo,
222 Sink::ApplicationDomain::ResourceCapabilities::Todo::storage,
194 }) 223 })
195{} 224{
225}
196 226
197Sink::Resource *CalDavResourceFactory::createResource(const Sink::ResourceContext &context) 227Sink::Resource *CalDavResourceFactory::createResource(const Sink::ResourceContext &context)
198{ 228{
@@ -201,10 +231,12 @@ Sink::Resource *CalDavResourceFactory::createResource(const Sink::ResourceContex
201 231
202using Sink::ApplicationDomain::Calendar; 232using Sink::ApplicationDomain::Calendar;
203using Sink::ApplicationDomain::Event; 233using Sink::ApplicationDomain::Event;
234using Sink::ApplicationDomain::Todo;
204 235
205void CalDavResourceFactory::registerFacades(const QByteArray &resourceName, Sink::FacadeFactory &factory) 236void CalDavResourceFactory::registerFacades(const QByteArray &resourceName, Sink::FacadeFactory &factory)
206{ 237{
207 factory.registerFacade<Event, Sink::DefaultFacade<Event>>(resourceName); 238 factory.registerFacade<Event, Sink::DefaultFacade<Event>>(resourceName);
239 factory.registerFacade<Todo, Sink::DefaultFacade<Todo>>(resourceName);
208 factory.registerFacade<Calendar, Sink::DefaultFacade<Calendar>>(resourceName); 240 factory.registerFacade<Calendar, Sink::DefaultFacade<Calendar>>(resourceName);
209} 241}
210 242
@@ -213,6 +245,7 @@ void CalDavResourceFactory::registerAdaptorFactories(
213 const QByteArray &resourceName, Sink::AdaptorFactoryRegistry &registry) 245 const QByteArray &resourceName, Sink::AdaptorFactoryRegistry &registry)
214{ 246{
215 registry.registerFactory<Event, DefaultAdaptorFactory<Event>>(resourceName); 247 registry.registerFactory<Event, DefaultAdaptorFactory<Event>>(resourceName);
248 registry.registerFactory<Todo, DefaultAdaptorFactory<Todo>>(resourceName);
216 registry.registerFactory<Calendar, DefaultAdaptorFactory<Calendar>>(resourceName); 249 registry.registerFactory<Calendar, DefaultAdaptorFactory<Calendar>>(resourceName);
217} 250}
218 251
diff --git a/examples/caldavresource/tests/caldavtest.cpp b/examples/caldavresource/tests/caldavtest.cpp
index f9920d9..9609fa0 100644
--- a/examples/caldavresource/tests/caldavtest.cpp
+++ b/examples/caldavresource/tests/caldavtest.cpp
@@ -22,13 +22,15 @@
22using Sink::ApplicationDomain::Calendar; 22using Sink::ApplicationDomain::Calendar;
23using Sink::ApplicationDomain::DummyResource; 23using Sink::ApplicationDomain::DummyResource;
24using Sink::ApplicationDomain::Event; 24using Sink::ApplicationDomain::Event;
25using Sink::ApplicationDomain::Todo;
25using Sink::ApplicationDomain::SinkResource; 26using Sink::ApplicationDomain::SinkResource;
26 27
27class CalDavTest : public QObject 28class CalDavTest : public QObject
28{ 29{
29 Q_OBJECT 30 Q_OBJECT
30 31
31 // This test assumes a calendar MyCalendar with one event in it. 32 // This test assumes a calendar MyCalendar with one event and one todo in
33 // it.
32 34
33 const QString baseUrl = "http://localhost/dav/calendars/users/doe"; 35 const QString baseUrl = "http://localhost/dav/calendars/users/doe";
34 const QString username = "doe"; 36 const QString username = "doe";
@@ -47,6 +49,7 @@ class CalDavTest : public QObject
47 QByteArray mResourceInstanceIdentifier; 49 QByteArray mResourceInstanceIdentifier;
48 50
49 QString addedEventUid; 51 QString addedEventUid;
52 QString addedTodoUid;
50 53
51private slots: 54private slots:
52 55
@@ -74,6 +77,7 @@ private slots:
74 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier))); 77 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier)));
75 // Check in the logs that it doesn't synchronize events again because same CTag 78 // Check in the logs that it doesn't synchronize events again because same CTag
76 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier))); 79 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier)));
80 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
77 } 81 }
78 82
79 void testSyncCalEmpty() 83 void testSyncCalEmpty()
@@ -83,7 +87,11 @@ private slots:
83 87
84 auto eventJob = Sink::Store::fetchAll<Event>(Sink::Query().request<Event::Uid>()) 88 auto eventJob = Sink::Store::fetchAll<Event>(Sink::Query().request<Event::Uid>())
85 .then([](const QList<Event::Ptr> &events) { QCOMPARE(events.size(), 1); }); 89 .then([](const QList<Event::Ptr> &events) { QCOMPARE(events.size(), 1); });
90 auto todoJob = Sink::Store::fetchAll<Todo>(Sink::Query().request<Todo::Uid>())
91 .then([](const QList<Todo::Ptr> &todos) { QCOMPARE(todos.size(), 1); });
92
86 VERIFYEXEC(eventJob); 93 VERIFYEXEC(eventJob);
94 VERIFYEXEC(todoJob);
87 95
88 auto calendarJob = Sink::Store::fetchAll<Calendar>(Sink::Query().request<Calendar::Name>()) 96 auto calendarJob = Sink::Store::fetchAll<Calendar>(Sink::Query().request<Calendar::Name>())
89 .then([](const QList<Calendar::Ptr> &calendars) { 97 .then([](const QList<Calendar::Ptr> &calendars) {
@@ -136,6 +144,44 @@ private slots:
136 VERIFYEXEC(verifyEventJob); 144 VERIFYEXEC(verifyEventJob);
137 } 145 }
138 146
147 void testAddTodo()
148 {
149 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier)));
150 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
151
152 auto job = Sink::Store::fetchOne<Calendar>({}).exec();
153 job.waitForFinished();
154 QVERIFY2(!job.errorCode(), "Fetching Calendar failed");
155 auto calendar = job.value();
156
157 auto todo = QSharedPointer<KCalCore::Todo>::create();
158 todo->setSummary("Hello");
159 todo->setDtStart(QDateTime::currentDateTime());
160 todo->setCreated(QDateTime::currentDateTime());
161 addedTodoUid = QUuid::createUuid().toString();
162 todo->setUid(addedTodoUid);
163
164 auto ical = KCalCore::ICalFormat().toICalString(todo);
165 Todo sinkTodo(mResourceInstanceIdentifier);
166 sinkTodo.setIcal(ical.toUtf8());
167 sinkTodo.setCalendar(calendar);
168
169 SinkLog() << "Adding todo";
170 VERIFYEXEC(Sink::Store::create(sinkTodo));
171 VERIFYEXEC(Sink::ResourceControl::flushReplayQueue(mResourceInstanceIdentifier));
172
173 auto verifyTodoCountJob =
174 Sink::Store::fetchAll<Todo>(Sink::Query().request<Todo::Uid>()).then([](const QList<Todo::Ptr> &todos) {
175 QCOMPARE(todos.size(), 2);
176 });
177 VERIFYEXEC(verifyTodoCountJob);
178
179 auto verifyTodoJob =
180 Sink::Store::fetchOne<Todo>(Sink::Query().filter("uid", Sink::Query::Comparator(addedTodoUid)))
181 .then([](const Todo &todo) { QCOMPARE(todo.getSummary(), {"Hello"}); });
182 VERIFYEXEC(verifyTodoJob);
183 }
184
139 void testModifyEvent() 185 void testModifyEvent()
140 { 186 {
141 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier))); 187 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier)));
@@ -173,6 +219,43 @@ private slots:
173 VERIFYEXEC(verifyEventJob); 219 VERIFYEXEC(verifyEventJob);
174 } 220 }
175 221
222 void testModifyTodo()
223 {
224 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier)));
225 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
226
227 auto job = Sink::Store::fetchOne<Todo>(
228 Sink::Query().filter("uid", Sink::Query::Comparator(addedTodoUid)))
229 .exec();
230 job.waitForFinished();
231 QVERIFY2(!job.errorCode(), "Fetching Todo failed");
232 auto todo = job.value();
233
234 auto incidence = KCalCore::ICalFormat().readIncidence(todo.getIcal());
235 auto caltodo = incidence.dynamicCast<KCalCore::Todo>();
236 QVERIFY2(caltodo, "Cannot convert to KCalCore todo");
237
238 caltodo->setSummary("Hello World!");
239 auto dummy = QSharedPointer<KCalCore::Todo>(caltodo);
240 auto newical = KCalCore::ICalFormat().toICalString(dummy);
241
242 todo.setIcal(newical.toUtf8());
243
244 VERIFYEXEC(Sink::Store::modify(todo));
245
246 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier)));
247 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
248
249 auto verifyTodoCountJob = Sink::Store::fetchAll<Todo>({}).then(
250 [](const QList<Todo::Ptr> &todos) { QCOMPARE(todos.size(), 2); });
251 VERIFYEXEC(verifyTodoCountJob);
252
253 auto verifyTodoJob =
254 Sink::Store::fetchOne<Todo>(Sink::Query().filter("uid", Sink::Query::Comparator(addedTodoUid)))
255 .then([](const Todo &todo) { QCOMPARE(todo.getSummary(), {"Hello World!"}); });
256 VERIFYEXEC(verifyTodoJob);
257 }
258
176 void testSneakyModifyEvent() 259 void testSneakyModifyEvent()
177 { 260 {
178 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier))); 261 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier)));
@@ -180,7 +263,6 @@ private slots:
180 263
181 // Change the item without sink's knowledge 264 // Change the item without sink's knowledge
182 { 265 {
183 qWarning() << 1;
184 auto collection = ([this]() -> KDAV2::DavCollection { 266 auto collection = ([this]() -> KDAV2::DavCollection {
185 QUrl url(baseUrl); 267 QUrl url(baseUrl);
186 url.setUserName(username); 268 url.setUserName(username);
@@ -212,22 +294,17 @@ private slots:
212 return itemFetchJob.item(); 294 return itemFetchJob.item();
213 })(); 295 })();
214 296
215 qWarning() << 3;
216 auto incidence = KCalCore::ICalFormat().readIncidence(davitem.data()); 297 auto incidence = KCalCore::ICalFormat().readIncidence(davitem.data());
217 auto calevent = incidence.dynamicCast<KCalCore::Event>(); 298 auto calevent = incidence.dynamicCast<KCalCore::Event>();
218 QVERIFY2(calevent, "Cannot convert to KCalCore event"); 299 QVERIFY2(calevent, "Cannot convert to KCalCore event");
219 300
220 qWarning() << 4;
221 calevent->setSummary("Manual Hello World!"); 301 calevent->setSummary("Manual Hello World!");
222 auto newical = KCalCore::ICalFormat().toICalString(calevent); 302 auto newical = KCalCore::ICalFormat().toICalString(calevent);
223 303
224 qWarning() << 5;
225 davitem.setData(newical.toUtf8()); 304 davitem.setData(newical.toUtf8());
226 KDAV2::DavItemModifyJob itemModifyJob(davitem); 305 KDAV2::DavItemModifyJob itemModifyJob(davitem);
227 itemModifyJob.exec(); 306 itemModifyJob.exec();
228 QVERIFY2(itemModifyJob.error() == 0, "Cannot modify item"); 307 QVERIFY2(itemModifyJob.error() == 0, "Cannot modify item");
229
230 qWarning() << 6;
231 } 308 }
232 309
233 // Try to change the item with sink 310 // Try to change the item with sink
@@ -274,6 +351,26 @@ private slots:
274 [](const QList<Event::Ptr> &events) { QCOMPARE(events.size(), 1); }); 351 [](const QList<Event::Ptr> &events) { QCOMPARE(events.size(), 1); });
275 VERIFYEXEC(verifyEventCountJob); 352 VERIFYEXEC(verifyEventCountJob);
276 } 353 }
354
355 void testRemoveTodo()
356 {
357 VERIFYEXEC(Sink::Store::synchronize(Sink::Query().resourceFilter(mResourceInstanceIdentifier)));
358 VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
359
360 auto job = Sink::Store::fetchOne<Todo>(
361 Sink::Query().filter("uid", Sink::Query::Comparator(addedTodoUid)))
362 .exec();
363 job.waitForFinished();
364 QVERIFY2(!job.errorCode(), "Fetching Todo failed");
365 auto todo = job.value();
366
367 VERIFYEXEC(Sink::Store::remove(todo));
368 VERIFYEXEC(Sink::ResourceControl::flushReplayQueue(mResourceInstanceIdentifier));
369
370 auto verifyTodoCountJob = Sink::Store::fetchAll<Todo>({}).then(
371 [](const QList<Todo::Ptr> &todos) { QCOMPARE(todos.size(), 1); });
372 VERIFYEXEC(verifyTodoCountJob);
373 }
277}; 374};
278 375
279QTEST_MAIN(CalDavTest) 376QTEST_MAIN(CalDavTest)