M module-apps/application-calendar/ApplicationCalendar.cpp => module-apps/application-calendar/ApplicationCalendar.cpp +3 -4
@@ 38,10 38,9 @@ namespace app
{Repeat::never, "app_calendar_repeat_never"},
{Repeat::daily, "app_calendar_repeat_daily"},
{Repeat::weekly, "app_calendar_repeat_weekly"},
- {Repeat::two_weeks, "app_calendar_repeat_two_weeks"},
- {Repeat::month, "app_calendar_repeat_month"},
- {Repeat::year, "app_calendar_repeat_year"},
- {Repeat::custom, "app_calendar_repeat_custom"}};
+ {Repeat::biweekly, "app_calendar_repeat_two_weeks"},
+ {Repeat::monthly, "app_calendar_repeat_month"},
+ {Repeat::yearly, "app_calendar_repeat_year"}};
ApplicationCalendar::ApplicationCalendar(std::string name,
std::string parent,
M module-apps/application-calendar/data/dateCommon.hpp => module-apps/application-calendar/data/dateCommon.hpp +22 -4
@@ 6,6 6,7 @@
#include <module-utils/date/include/date/date.h>
#include <time/time_conversion.hpp>
+#include <random>
using namespace std::chrono;
using namespace std::chrono_literals;
@@ 36,13 37,14 @@ enum class Repeat
never,
daily,
weekly,
- two_weeks,
- month,
- year,
- custom
+ biweekly,
+ monthly,
+ yearly
};
inline constexpr TimePoint TIME_POINT_INVALID = date::sys_days{date::January / 1 / 1970};
+inline constexpr uint32_t yearDigitsNumb = 4, monthDigitsNumb = 2, dayDigitsNumb = 2, HourDigitsNumb = 2,
+ MinDigitsNumb = 2, SecDigitsNumb = 2;
inline std::tm CreateTmStruct(int year, int month, int day, int hour, int minutes, int seconds)
{
@@ 254,5 256,21 @@ inline unsigned int WeekdayIndexFromTimePoint(const TimePoint &tp)
return ymw.weekday().iso_encoding() - 1;
}
+inline std::string createUID()
+{
+ constexpr uint32_t bufferLimit = 16;
+ char Buffer[bufferLimit];
+ utils::time::Timestamp timestamp;
+ std::string UID{timestamp.str("%Y%m%dT%H%M%S")};
+ UID += '-';
+ std::random_device rd;
+ std::mt19937 gen(rd());
+ std::uniform_int_distribution<> distrib(1, 100);
+ sprintf(Buffer, "%d", distrib(gen));
+ UID += Buffer;
+
+ return UID;
+}
+
#endif
// DATECOMMON_H
M module-apps/application-calendar/widgets/RepeatAndReminderItem.cpp => module-apps/application-calendar/widgets/RepeatAndReminderItem.cpp +1 -1
@@ 103,7 103,7 @@ namespace gui
repeatTitle->setText(utils::localize.get("app_calendar_event_detail_repeat"));
reminderTitle->setText(utils::localize.get("app_calendar_event_detail_reminder"));
onLoadCallback = [&](std::shared_ptr<EventsRecord> event) {
- if (event->repeat >= app::ApplicationCalendar::repeatOptions.size()) {
+ if (event->repeat > app::ApplicationCalendar::repeatOptions.size()) {
repeat->setText("app_calendar_custom_repeat_title");
}
else {
M module-db/CMakeLists.txt => module-db/CMakeLists.txt +2 -0
@@ 103,10 103,12 @@ set(SOURCES
queries/phonebook/QueryContactUpdate.cpp
queries/phonebook/QueryContactRemove.cpp
queries/phonebook/QueryNumberGetByID.cpp
+ queries/calendar/QueryEventsRemoveICS.cpp
queries/calendar/QueryEventsRemove.cpp
queries/calendar/QueryEventsGet.cpp
queries/calendar/QueryEventsGetAll.cpp
queries/calendar/QueryEventsAdd.cpp
+ queries/calendar/QueryEventsEditICS.cpp
queries/calendar/QueryEventsEdit.cpp
queries/calendar/QueryEventsGetFiltered.cpp
queries/calendar/QueryEventsGetAllLimited.cpp
M module-db/Interface/EventsRecord.cpp => module-db/Interface/EventsRecord.cpp +131 -47
@@ 6,8 6,9 @@
#include "module-db/queries/calendar/QueryEventsGetAll.hpp"
#include "module-db/queries/calendar/QueryEventsAdd.hpp"
#include "module-db/queries/calendar/QueryEventsRemove.hpp"
+#include "module-db/queries/calendar/QueryEventsRemoveICS.hpp"
#include "module-db/queries/calendar/QueryEventsEdit.hpp"
-#include <module-db/queries/calendar/QueryEventsEdit.hpp>
+#include <module-db/queries/calendar/QueryEventsEditICS.hpp>
#include <module-db/queries/calendar/QueryEventsGetFiltered.hpp>
#include <module-db/queries/calendar/QueryEventsGetAllLimited.hpp>
#include <module-db/queries/calendar/QueryEventsSelectFirstUpcoming.hpp>
@@ 17,8 18,9 @@
#include <vector>
EventsRecord::EventsRecord(const EventsTableRow &tableRow)
- : Record{tableRow.ID}, title{tableRow.title}, date_from{tableRow.date_from}, date_till{tableRow.date_till},
- reminder{tableRow.reminder}, repeat{tableRow.repeat}, reminder_fired{tableRow.reminder_fired}
+ : Record{tableRow.ID}, UID{tableRow.UID}, title{tableRow.title}, date_from{tableRow.date_from},
+ date_till{tableRow.date_till}, reminder{tableRow.reminder}, repeat{tableRow.repeat}, reminder_fired{
+ tableRow.reminder_fired}
{}
EventsRecordInterface::EventsRecordInterface(EventsDB *eventsDb) : eventsDb(eventsDb)
@@ 27,6 29,7 @@ EventsRecordInterface::EventsRecordInterface(EventsDB *eventsDb) : eventsDb(even
bool EventsRecordInterface::Add(const EventsRecord &rec)
{
auto entry = EventsTableRow{{.ID = rec.ID},
+ .UID = rec.UID,
.title = rec.title,
.date_from = rec.date_from,
.date_till = rec.date_till,
@@ 34,29 37,33 @@ bool EventsRecordInterface::Add(const EventsRecord &rec)
.repeat = rec.repeat,
.reminder_fired = rec.reminder_fired};
- switch (RepeatOption(rec.repeat)) {
- case RepeatOption::Never: {
+ Repeat repeatOption = Repeat(rec.repeat);
+ if (repeatOption > Repeat::yearly) {
+ return (eventsDb->events.addCustom(entry));
+ }
+
+ switch (repeatOption) {
+ case Repeat::never: {
return eventsDb->events.add(entry);
}
- case RepeatOption::Daily: {
+ case Repeat::daily: {
return eventsDb->events.addDaily(entry);
}
- case RepeatOption::Weekly: {
+ case Repeat::weekly: {
return eventsDb->events.addWeekly(entry);
}
- case RepeatOption::TwoWeeks: {
+ case Repeat::biweekly: {
return eventsDb->events.addTwoWeeks(entry);
}
- case RepeatOption::Month: {
+ case Repeat::monthly: {
return eventsDb->events.addMonth(entry);
}
- case RepeatOption::Year: {
+ case Repeat::yearly: {
return eventsDb->events.addYear(entry);
}
- default: {
- return eventsDb->events.addCustom(entry);
- }
}
+
+ return false;
}
std::unique_ptr<std::vector<EventsRecord>> EventsRecordInterface::Select(TimePoint filter_from,
@@ 123,11 130,12 @@ bool EventsRecordInterface::Update(const EventsRecord &rec)
{
auto record = eventsDb->events.getById(rec.ID);
if (!record.isValid()) {
- LOG_DEBUG("IS NOT VALID");
+ LOG_DEBUG("Event record is not valid");
return false;
}
auto entry = EventsTableRow{{.ID = rec.ID},
+ .UID = rec.UID,
.title = rec.title,
.date_from = rec.date_from,
.date_till = rec.date_till,
@@ 137,29 145,81 @@ bool EventsRecordInterface::Update(const EventsRecord &rec)
bool result = eventsDb->events.update(entry);
- switch (RepeatOption(rec.repeat)) {
- case RepeatOption::Never: {
- return (eventsDb->events.add(entry) && result);
+ Repeat repeatOption = Repeat(rec.repeat);
+ if (repeatOption > Repeat::yearly) {
+ return (eventsDb->events.addCustom(entry) && result);
+ }
+
+ switch (repeatOption) {
+ case Repeat::never: {
+ return result;
}
- case RepeatOption::Daily: {
+ case Repeat::daily: {
return (eventsDb->events.addDaily(entry) && result);
}
- case RepeatOption::Weekly: {
+ case Repeat::weekly: {
return (eventsDb->events.addWeekly(entry) && result);
}
- case RepeatOption::TwoWeeks: {
+ case Repeat::biweekly: {
return (eventsDb->events.addTwoWeeks(entry) && result);
}
- case RepeatOption::Month: {
+ case Repeat::monthly: {
return (eventsDb->events.addMonth(entry) && result);
}
- case RepeatOption::Year: {
+ case Repeat::yearly: {
return (eventsDb->events.addYear(entry) && result);
}
- default: {
- return eventsDb->events.addCustom(entry);
}
+
+ return false;
+}
+
+bool EventsRecordInterface::UpdateByUID(const EventsRecord &rec)
+{
+ auto record = eventsDb->events.getByUID(rec.UID);
+ if (!record.isValid()) {
+ LOG_DEBUG("Event record is not valid");
+ return false;
+ }
+
+ auto entry = EventsTableRow{{.ID = rec.ID},
+ .UID = rec.UID,
+ .title = rec.title,
+ .date_from = rec.date_from,
+ .date_till = rec.date_till,
+ .reminder = rec.reminder,
+ .repeat = rec.repeat,
+ .reminder_fired = rec.reminder_fired};
+
+ bool result = eventsDb->events.updateByUID(entry);
+
+ Repeat repeatOption = Repeat(rec.repeat);
+ if (repeatOption > Repeat::yearly) {
+ return (eventsDb->events.addCustom(entry) && result);
+ }
+
+ switch (Repeat(rec.repeat)) {
+ case Repeat::never: {
+ return result;
+ }
+ case Repeat::daily: {
+ return (eventsDb->events.addDaily(entry) && result);
}
+ case Repeat::weekly: {
+ return (eventsDb->events.addWeekly(entry) && result);
+ }
+ case Repeat::biweekly: {
+ return (eventsDb->events.addTwoWeeks(entry) && result);
+ }
+ case Repeat::monthly: {
+ return (eventsDb->events.addMonth(entry) && result);
+ }
+ case Repeat::yearly: {
+ return (eventsDb->events.addYear(entry) && result);
+ }
+ }
+
+ return false;
}
bool EventsRecordInterface::RemoveByID(uint32_t id)
@@ 167,6 227,11 @@ bool EventsRecordInterface::RemoveByID(uint32_t id)
return eventsDb->events.removeById(id);
}
+bool EventsRecordInterface::RemoveByUID(const std::string &UID)
+{
+ return eventsDb->events.removeByUID(UID);
+}
+
bool EventsRecordInterface::RemoveByField(EventsRecordField field, const char *str)
{
assert(0 && "Not implemented");
@@ 223,9 288,15 @@ std::unique_ptr<db::QueryResult> EventsRecordInterface::runQuery(std::shared_ptr
if (typeid(*query) == typeid(db::query::events::Remove)) {
return runQueryImplRemove(query);
}
+ if (typeid(*query) == typeid(db::query::events::RemoveICS)) {
+ return runQueryImplRemoveICS(query);
+ }
if (typeid(*query) == typeid(db::query::events::Edit)) {
return runQueryImplEdit(query);
}
+ if (typeid(*query) == typeid(db::query::events::EditICS)) {
+ return runQueryImplEditICS(query);
+ }
if (typeid(*query) == typeid(db::query::events::SelectFirstUpcoming)) {
return runQueryImplSelectFirstUpcoming(query);
}
@@ 235,8 306,7 @@ std::unique_ptr<db::QueryResult> EventsRecordInterface::runQuery(std::shared_ptr
std::unique_ptr<db::query::events::GetResult> EventsRecordInterface::runQueryImplGetResult(
std::shared_ptr<db::Query> query)
{
- auto getQuery = dynamic_cast<db::query::events::Get *>(query.get());
- assert(getQuery != nullptr);
+ auto getQuery = static_cast<db::query::events::Get *>(query.get());
auto records = GetByID(getQuery->id);
auto response = std::make_unique<db::query::events::GetResult>(records);
response->setRequestQuery(query);
@@ 257,10 327,9 @@ std::unique_ptr<db::query::events::GetAllLimitedResult> EventsRecordInterface::r
std::shared_ptr<db::Query> query)
{
- auto getAllLimitedQuery = dynamic_cast<db::query::events::GetAllLimited *>(query.get());
- assert(getAllLimitedQuery != nullptr);
- auto records = GetLimitOffsetByDate(getAllLimitedQuery->offset, getAllLimitedQuery->limit);
- auto count = GetCount();
+ auto getAllLimitedQuery = static_cast<db::query::events::GetAllLimited *>(query.get());
+ auto records = GetLimitOffsetByDate(getAllLimitedQuery->offset, getAllLimitedQuery->limit);
+ auto count = GetCount();
auto response =
std::make_unique<db::query::events::GetAllLimitedResult>(std::move(records), std::make_unique<uint32_t>(count));
response->setRequestQuery(query);
@@ 270,22 339,20 @@ std::unique_ptr<db::query::events::GetAllLimitedResult> EventsRecordInterface::r
std::unique_ptr<db::query::events::GetFilteredResult> EventsRecordInterface::runQueryImplGetFilteredResult(
std::shared_ptr<db::Query> query)
{
- auto getFilteredQuery = dynamic_cast<db::query::events::GetFiltered *>(query.get());
- assert(getFilteredQuery != nullptr);
- auto records = Select(getFilteredQuery->filter_from,
+ auto getFilteredQuery = static_cast<db::query::events::GetFiltered *>(query.get());
+ auto records = Select(getFilteredQuery->filter_from,
getFilteredQuery->filter_till,
getFilteredQuery->offset,
getFilteredQuery->limit);
- auto numberOfEvents = GetCountFiltered(getFilteredQuery->filter_from, getFilteredQuery->filter_till);
- auto response = std::make_unique<db::query::events::GetFilteredResult>(std::move(records), numberOfEvents);
+ auto numberOfEvents = GetCountFiltered(getFilteredQuery->filter_from, getFilteredQuery->filter_till);
+ auto response = std::make_unique<db::query::events::GetFilteredResult>(std::move(records), numberOfEvents);
response->setRequestQuery(query);
return response;
}
std::unique_ptr<db::query::events::AddResult> EventsRecordInterface::runQueryImplAdd(std::shared_ptr<db::Query> query)
{
- auto addQuery = dynamic_cast<db::query::events::Add *>(query.get());
- assert(addQuery != nullptr);
+ auto addQuery = static_cast<db::query::events::Add *>(query.get());
bool ret = Add(addQuery->getRecord());
auto response = std::make_unique<db::query::events::AddResult>(ret);
response->setRequestQuery(query);
@@ 295,20 362,38 @@ std::unique_ptr<db::query::events::AddResult> EventsRecordInterface::runQueryImp
std::unique_ptr<db::query::events::RemoveResult> EventsRecordInterface::runQueryImplRemove(
std::shared_ptr<db::Query> query)
{
- auto removeQuery = dynamic_cast<db::query::events::Remove *>(query.get());
- assert(removeQuery != nullptr);
- bool ret = RemoveByID(removeQuery->id);
- auto response = std::make_unique<db::query::events::RemoveResult>(ret);
+ auto removeQuery = static_cast<db::query::events::Remove *>(query.get());
+ bool ret = RemoveByID(removeQuery->id);
+ auto response = std::make_unique<db::query::events::RemoveResult>(ret);
+ response->setRequestQuery(query);
+ return response;
+}
+
+std::unique_ptr<db::query::events::RemoveICSResult> EventsRecordInterface::runQueryImplRemoveICS(
+ std::shared_ptr<db::Query> query)
+{
+ auto removeQuery = static_cast<db::query::events::RemoveICS *>(query.get());
+ bool ret = RemoveByUID(removeQuery->UID);
+ auto response = std::make_unique<db::query::events::RemoveICSResult>(ret);
response->setRequestQuery(query);
return response;
}
std::unique_ptr<db::query::events::EditResult> EventsRecordInterface::runQueryImplEdit(std::shared_ptr<db::Query> query)
{
- auto editQuery = dynamic_cast<db::query::events::Edit *>(query.get());
- assert(editQuery != nullptr);
- bool ret = Update(editQuery->getRecord());
- auto response = std::make_unique<db::query::events::EditResult>(ret);
+ auto editQuery = static_cast<db::query::events::Edit *>(query.get());
+ bool ret = Update(editQuery->getRecord());
+ auto response = std::make_unique<db::query::events::EditResult>(ret);
+ response->setRequestQuery(query);
+ return response;
+}
+
+std::unique_ptr<db::query::events::EditICSResult> EventsRecordInterface::runQueryImplEditICS(
+ std::shared_ptr<db::Query> query)
+{
+ auto editQuery = static_cast<db::query::events::EditICS *>(query.get());
+ bool ret = UpdateByUID(editQuery->getRecord());
+ auto response = std::make_unique<db::query::events::EditICSResult>(ret);
response->setRequestQuery(query);
return response;
}
@@ 316,8 401,7 @@ std::unique_ptr<db::query::events::EditResult> EventsRecordInterface::runQueryIm
std::unique_ptr<db::query::events::SelectFirstUpcomingResult> EventsRecordInterface::runQueryImplSelectFirstUpcoming(
std::shared_ptr<db::Query> query)
{
- auto getFirstUpcomingQuery = dynamic_cast<db::query::events::SelectFirstUpcoming *>(query.get());
- assert(getFirstUpcomingQuery != nullptr);
+ auto getFirstUpcomingQuery = static_cast<db::query::events::SelectFirstUpcoming *>(query.get());
auto records = SelectFirstUpcoming(getFirstUpcomingQuery->filter_from, getFirstUpcomingQuery->filter_till);
auto response = std::make_unique<db::query::events::SelectFirstUpcomingResult>(std::move(records));
M module-db/Interface/EventsRecord.hpp => module-db/Interface/EventsRecord.hpp +13 -13
@@ 3,12 3,13 @@
#pragma once
-#include "Common/Common.hpp"
-#include "Databases/EventsDB.hpp"
+#include "module-db/Common/Common.hpp"
+#include "module-db/Databases/EventsDB.hpp"
#include "Record.hpp"
#include <utf8/UTF8.hpp>
#include <cstdint>
#include <vector>
+#include <variant>
#include <module-apps/application-calendar/data/dateCommon.hpp>
// fw declarations
@@ 26,29 27,24 @@ namespace db::query::events
class AddResult;
class Remove;
class RemoveResult;
+ class RemoveICS;
+ class RemoveICSResult;
class Edit;
class EditResult;
+ class EditICS;
+ class EditICSResult;
class SelectFirstUpcoming;
class SelectFirstUpcomingResult;
} // namespace db::query::events
-enum class RepeatOption
-{
- Never = 0,
- Daily = 1,
- Weekly = 2,
- TwoWeeks = 3,
- Month = 4,
- Year = 5
-};
-
struct EventsRecord : public Record
{
+ std::string UID;
std::string title;
TimePoint date_from;
TimePoint date_till;
uint32_t reminder = 0;
- uint32_t repeat = 0;
+ uint32_t repeat = 0;
TimePoint reminder_fired;
EventsRecord() = default;
@@ 71,8 67,10 @@ class EventsRecordInterface : public RecordInterface<EventsRecord, EventsRecordF
bool Add(const EventsRecord &rec) override final;
bool RemoveByID(uint32_t id) override final;
+ bool RemoveByUID(const std::string &UID);
bool RemoveByField(EventsRecordField field, const char *str) override final;
bool Update(const EventsRecord &rec) override final;
+ bool UpdateByUID(const EventsRecord &rec);
EventsRecord GetByID(uint32_t id) override final;
uint32_t GetCount() override final;
uint32_t GetCountFiltered(TimePoint from, TimePoint till);
@@ 101,7 99,9 @@ class EventsRecordInterface : public RecordInterface<EventsRecord, EventsRecordF
std::shared_ptr<db::Query> query);
std::unique_ptr<db::query::events::AddResult> runQueryImplAdd(std::shared_ptr<db::Query> query);
std::unique_ptr<db::query::events::RemoveResult> runQueryImplRemove(std::shared_ptr<db::Query> query);
+ std::unique_ptr<db::query::events::RemoveICSResult> runQueryImplRemoveICS(std::shared_ptr<db::Query> query);
std::unique_ptr<db::query::events::EditResult> runQueryImplEdit(std::shared_ptr<db::Query> query);
+ std::unique_ptr<db::query::events::EditICSResult> runQueryImplEditICS(std::shared_ptr<db::Query> query);
std::unique_ptr<db::query::events::SelectFirstUpcomingResult> runQueryImplSelectFirstUpcoming(
std::shared_ptr<db::Query> query);
};
M module-db/Tables/EventsTable.cpp => module-db/Tables/EventsTable.cpp +390 -303
@@ 16,7 16,7 @@ EventsTable::EventsTable(Database *db) : Table(db)
bool EventsTable::create()
{
- if (!db->execute(createTableQuery.c_str())) {
+ if (!db->execute(createTableQuery)) {
return false;
}
@@ 26,287 26,323 @@ bool EventsTable::create()
bool EventsTable::add(EventsTableRow entry)
{
// Prevent duplicates using ANDs:
- return db->execute("INSERT or IGNORE INTO events "
- "(title, date_from, date_till, reminder, repeat, reminder_fired) "
- "SELECT '%q', '%q','%q', %lu, %lu, '%q' "
- "WHERE NOT EXISTS "
- "(SELECT 1 FROM events e "
- "WHERE e.title='%q' "
- "AND e.date_from='%q' "
- "AND e.date_till='%q' "
- "AND e.reminder=%lu "
- "AND e.repeat=%lu );",
- entry.title.c_str(),
- TimePointToString(entry.date_from).c_str(),
- TimePointToString(entry.date_till).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from).c_str(),
- TimePointToString(entry.date_till).c_str(),
- entry.reminder,
- entry.repeat);
+ if (entry.UID.empty()) {
+ entry.UID = createUID();
+ }
+ return db->execute(
+ "INSERT or IGNORE INTO events (uid, title, date_from, date_till, reminder, repeat, reminder_fired) "
+ "SELECT '%q','%q', '%q','%q', %lu, %lu, '%q' "
+ "WHERE NOT EXISTS "
+ "(SELECT 1 FROM events e "
+ "WHERE e.title='%q' "
+ "AND e.date_from='%q' "
+ "AND e.date_till='%q' "
+ "AND e.reminder=%lu "
+ "AND e.repeat=%lu );",
+ entry.UID.c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from).c_str(),
+ TimePointToString(entry.date_till).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from).c_str(),
+ TimePointToString(entry.date_till).c_str(),
+ entry.reminder,
+ entry.repeat);
}
bool EventsTable::addDaily(EventsTableRow entry)
{
- return db->execute("INSERT or IGNORE INTO events "
- "(title, date_from, date_till, reminder, repeat, reminder_fired) VALUES"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q');",
- entry.title.c_str(),
- TimePointToString(entry.date_from).c_str(),
- TimePointToString(entry.date_till).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from + date::days{1}).c_str(),
- TimePointToString(entry.date_till + date::days{1}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from + date::days{2}).c_str(),
- TimePointToString(entry.date_till + date::days{2}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from + date::days{3}).c_str(),
- TimePointToString(entry.date_till + date::days{3}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from + date::days{4}).c_str(),
- TimePointToString(entry.date_till + date::days{4}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from + date::days{5}).c_str(),
- TimePointToString(entry.date_till + date::days{5}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from + date::days{6}).c_str(),
- TimePointToString(entry.date_till + date::days{6}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str());
+ return db->execute(
+ "INSERT or IGNORE INTO events (uid, title, date_from, date_till, reminder, repeat, reminder_fired) VALUES"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q');",
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from).c_str(),
+ TimePointToString(entry.date_till).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from + date::days{1}).c_str(),
+ TimePointToString(entry.date_till + date::days{1}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from + date::days{2}).c_str(),
+ TimePointToString(entry.date_till + date::days{2}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from + date::days{3}).c_str(),
+ TimePointToString(entry.date_till + date::days{3}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from + date::days{4}).c_str(),
+ TimePointToString(entry.date_till + date::days{4}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from + date::days{5}).c_str(),
+ TimePointToString(entry.date_till + date::days{5}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from + date::days{6}).c_str(),
+ TimePointToString(entry.date_till + date::days{6}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str());
}
bool EventsTable::addWeekly(EventsTableRow entry)
{
- return db->execute("INSERT or IGNORE INTO events "
- "(title, date_from, date_till, reminder, repeat, reminder_fired) VALUES"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q');",
- entry.title.c_str(),
- TimePointToString(entry.date_from).c_str(),
- TimePointToString(entry.date_till).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from + date::days{7}).c_str(),
- TimePointToString(entry.date_till + date::days{7}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from + date::days{14}).c_str(),
- TimePointToString(entry.date_till + date::days{14}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from + date::days{21}).c_str(),
- TimePointToString(entry.date_till + date::days{21}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str());
+ return db->execute(
+ "INSERT or IGNORE INTO events (uid, title, date_from, date_till, reminder, repeat, reminder_fired) VALUES"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q');",
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from).c_str(),
+ TimePointToString(entry.date_till).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from + date::days{7}).c_str(),
+ TimePointToString(entry.date_till + date::days{7}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from + date::days{14}).c_str(),
+ TimePointToString(entry.date_till + date::days{14}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from + date::days{21}).c_str(),
+ TimePointToString(entry.date_till + date::days{21}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str());
}
bool EventsTable::addTwoWeeks(EventsTableRow entry)
{
- return db->execute("INSERT or IGNORE INTO events "
- "(title, date_from, date_till, reminder, repeat, reminder_fired) VALUES"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q');",
- entry.title.c_str(),
- TimePointToString(entry.date_from).c_str(),
- TimePointToString(entry.date_till).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from + date::days{14}).c_str(),
- TimePointToString(entry.date_till + date::days{14}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from + date::days{28}).c_str(),
- TimePointToString(entry.date_till + date::days{28}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from + date::days{42}).c_str(),
- TimePointToString(entry.date_till + date::days{42}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str());
+ return db->execute(
+ "INSERT or IGNORE INTO events (uid, title, date_from, date_till, reminder, repeat, reminder_fired) VALUES"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q');",
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from).c_str(),
+ TimePointToString(entry.date_till).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from + date::days{14}).c_str(),
+ TimePointToString(entry.date_till + date::days{14}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from + date::days{28}).c_str(),
+ TimePointToString(entry.date_till + date::days{28}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from + date::days{42}).c_str(),
+ TimePointToString(entry.date_till + date::days{42}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str());
}
bool EventsTable::addMonth(EventsTableRow entry)
{
- return db->execute("INSERT or IGNORE INTO events "
- "(title, date_from, date_till, reminder, repeat, reminder_fired) VALUES"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q');",
- entry.title.c_str(),
- TimePointToString(entry.date_from).c_str(),
- TimePointToString(entry.date_till).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from, date::months{1}).c_str(),
- TimePointToString(entry.date_till, date::months{1}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from, date::months{2}).c_str(),
- TimePointToString(entry.date_till, date::months{2}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from, date::months{3}).c_str(),
- TimePointToString(entry.date_till, date::months{3}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from, date::months{4}).c_str(),
- TimePointToString(entry.date_till, date::months{4}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from, date::months{5}).c_str(),
- TimePointToString(entry.date_till, date::months{5}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from, date::months{6}).c_str(),
- TimePointToString(entry.date_till, date::months{6}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from, date::months{7}).c_str(),
- TimePointToString(entry.date_till, date::months{7}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from, date::months{8}).c_str(),
- TimePointToString(entry.date_till, date::months{8}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from, date::months{9}).c_str(),
- TimePointToString(entry.date_till, date::months{9}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from, date::months{10}).c_str(),
- TimePointToString(entry.date_till, date::months{10}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from, date::months{11}).c_str(),
- TimePointToString(entry.date_till, date::months{11}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from, date::months{12}).c_str(),
- TimePointToString(entry.date_till, date::months{12}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str());
+ return db->execute(
+ "INSERT or IGNORE INTO events (uid, title, date_from, date_till, reminder, repeat, reminder_fired) VALUES"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q');",
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from).c_str(),
+ TimePointToString(entry.date_till).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from, date::months{1}).c_str(),
+ TimePointToString(entry.date_till, date::months{1}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from, date::months{2}).c_str(),
+ TimePointToString(entry.date_till, date::months{2}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from, date::months{3}).c_str(),
+ TimePointToString(entry.date_till, date::months{3}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from, date::months{4}).c_str(),
+ TimePointToString(entry.date_till, date::months{4}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from, date::months{5}).c_str(),
+ TimePointToString(entry.date_till, date::months{5}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from, date::months{6}).c_str(),
+ TimePointToString(entry.date_till, date::months{6}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from, date::months{7}).c_str(),
+ TimePointToString(entry.date_till, date::months{7}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from, date::months{8}).c_str(),
+ TimePointToString(entry.date_till, date::months{8}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from, date::months{9}).c_str(),
+ TimePointToString(entry.date_till, date::months{9}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from, date::months{10}).c_str(),
+ TimePointToString(entry.date_till, date::months{10}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from, date::months{11}).c_str(),
+ TimePointToString(entry.date_till, date::months{11}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from, date::months{12}).c_str(),
+ TimePointToString(entry.date_till, date::months{12}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str());
}
bool EventsTable::addYear(EventsTableRow entry)
{
- return db->execute("INSERT or IGNORE INTO events "
- "(title, date_from, date_till, reminder, repeat, reminder_fired) VALUES"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q'),"
- "('%q', '%q', '%q', %u, %u, '%q');",
- entry.title.c_str(),
- TimePointToString(entry.date_from).c_str(),
- TimePointToString(entry.date_till).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from + date::years{1}).c_str(),
- TimePointToString(entry.date_till + date::years{1}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from + date::years{2}).c_str(),
- TimePointToString(entry.date_till + date::years{2}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from + date::years{3}).c_str(),
- TimePointToString(entry.date_till + date::years{3}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str(),
- entry.title.c_str(),
- TimePointToString(entry.date_from + date::years{4}).c_str(),
- TimePointToString(entry.date_till + date::years{4}).c_str(),
- entry.reminder,
- entry.repeat,
- TimePointToString(entry.reminder_fired).c_str());
+ return db->execute(
+ "INSERT or IGNORE INTO events (uid, title, date_from, date_till, reminder, repeat, reminder_fired) VALUES"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q'),"
+ "('%q','%q', '%q','%q', %u, %u,'%q');",
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from).c_str(),
+ TimePointToString(entry.date_till).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from + date::years{1}).c_str(),
+ TimePointToString(entry.date_till + date::years{1}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from + date::years{2}).c_str(),
+ TimePointToString(entry.date_till + date::years{2}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from + date::years{3}).c_str(),
+ TimePointToString(entry.date_till + date::years{3}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str(),
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from + date::years{4}).c_str(),
+ TimePointToString(entry.date_till + date::years{4}).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str());
}
std::vector<bool> parseOptions(const uint32_t &dataDB)
@@ 336,13 372,18 @@ bool EventsTable::addCustom(EventsTableRow entry)
weekDayOptions = parseOptions(entry.repeat);
uint32_t incrementation = 0;
- result = result && db->execute("INSERT or IGNORE INTO events (title, date_from, date_till, reminder, repeat) VALUES"
- "('%q', '%q','%q', %u, %u);",
- entry.title.c_str(),
- TimePointToString(entry.date_from).c_str(),
- TimePointToString(entry.date_till).c_str(),
- entry.reminder,
- entry.repeat);
+ result =
+ result &&
+ db->execute(
+ "INSERT or IGNORE INTO events (uid, title, date_from, date_till, reminder, repeat, reminder_fired) VALUES"
+ "('%q','%q', '%q','%q', %u, %u, '%q');",
+ createUID().c_str(),
+ entry.title.c_str(),
+ TimePointToString(entry.date_from).c_str(),
+ TimePointToString(entry.date_till).c_str(),
+ entry.reminder,
+ entry.repeat,
+ TimePointToString(entry.reminder_fired).c_str());
auto dateFrom = getFirstWeekDay(entry.date_from);
auto dateTill = getFirstWeekDay(entry.date_till);
@@ 350,9 391,10 @@ bool EventsTable::addCustom(EventsTableRow entry)
for (uint32_t i = 1; i <= numberOfWeeks; i++) {
for (auto option : weekDayOptions) {
if (option) {
- result = result && db->execute("INSERT or IGNORE INTO events "
- "(title, date_from, date_till, reminder, repeat, reminder_fired) VALUES"
- "('%q', '%q','%q', %u, %u);",
+ result = result && db->execute("INSERT or IGNORE INTO events (uid, title, date_from, date_till, "
+ "reminder, repeat, reminder_fired) VALUES"
+ "('%q','%q', '%q','%q', %u, %u, '%q');",
+ createUID().c_str(),
entry.title.c_str(),
TimePointToString(dateFrom + date::days{incrementation}).c_str(),
TimePointToString(dateTill + date::days{incrementation}).c_str(),
@@ 372,6 414,11 @@ bool EventsTable::removeById(uint32_t id)
return db->execute("DELETE FROM events where _id = %u;", id);
}
+bool EventsTable::removeByUID(const std::string &UID)
+{
+ return db->execute("DELETE FROM events where uid = '%q';", UID.c_str());
+}
+
bool EventsTable::removeByField(EventsTableFields field, const char *str)
{
std::string fieldName;
@@ 403,11 450,24 @@ bool EventsTable::update(EventsTableRow entry)
entry.ID);
}
+bool EventsTable::updateByUID(EventsTableRow entry)
+{
+ return db->execute("UPDATE events SET title= '%q', date_from = '%q', date_till = '%q', reminder "
+ "= %u, repeat = %u, reminder_fired = '%q' WHERE uid = '%q';",
+ entry.title.c_str(),
+ TimePointToString(entry.date_from).c_str(),
+ TimePointToString(entry.date_till).c_str(),
+ entry.reminder,
+ static_cast<uint32_t>(entry.repeat),
+ TimePointToString(entry.reminder_fired).c_str(),
+ entry.UID.c_str());
+}
+
EventsTableRow EventsTable::getById(uint32_t id)
{
auto retQuery = db->query("SELECT * FROM events WHERE _id= %u;", id);
- if ((retQuery == nullptr) || (retQuery->getRowCount() == 0)) {
+ if (retQuery == nullptr || retQuery->getRowCount() == 0) {
return EventsTableRow();
}
@@ 415,13 475,35 @@ EventsTableRow EventsTable::getById(uint32_t id)
return EventsTableRow{
(*retQuery)[0].getUInt32(), // ID
- (*retQuery)[1].getString(), // title
- TimePointFromString((*retQuery)[2].getString().c_str()), // date_from
- TimePointFromString((*retQuery)[3].getString().c_str()), // date_till
- (*retQuery)[4].getUInt32(), // reminder
- (*retQuery)[5].getUInt32(), // repeat
- TimePointFromString((*retQuery)[6].getString().c_str()) // date_till
+ (*retQuery)[1].getString(), // UID
+ (*retQuery)[2].getString(), // title
+ TimePointFromString((*retQuery)[3].getString().c_str()), // date_from
+ TimePointFromString((*retQuery)[4].getString().c_str()), // date_till
+ (*retQuery)[5].getUInt32(), // reminder
+ (*retQuery)[6].getUInt32(), // repeat
+ TimePointFromString((*retQuery)[7].getString().c_str()) // reminder_fired
+ };
+}
+EventsTableRow EventsTable::getByUID(const std::string &UID)
+{
+ auto retQuery = db->query("SELECT * FROM events WHERE uid= '%q';", UID.c_str());
+
+ if (retQuery == nullptr || retQuery->getRowCount() == 0) {
+ return EventsTableRow();
+ }
+
+ assert(retQuery->getRowCount() == 1);
+
+ return EventsTableRow{
+ (*retQuery)[0].getUInt32(), // ID
+ (*retQuery)[1].getString(), // UID
+ (*retQuery)[2].getString(), // title
+ TimePointFromString((*retQuery)[3].getString().c_str()), // date_from
+ TimePointFromString((*retQuery)[4].getString().c_str()), // date_till
+ (*retQuery)[5].getUInt32(), // reminder
+ (*retQuery)[6].getUInt32(), // repeat
+ TimePointFromString((*retQuery)[7].getString().c_str()) // reminder_fired
};
}
@@ 437,7 519,7 @@ std::vector<EventsTableRow> EventsTable::selectByDatePeriod(TimePoint date_filte
limit,
offset);
- if ((retQuery == nullptr) || (retQuery->getRowCount() == 0)) {
+ if (retQuery == nullptr || retQuery->getRowCount() == 0) {
return std::vector<EventsTableRow>();
}
@@ 446,12 528,13 @@ std::vector<EventsTableRow> EventsTable::selectByDatePeriod(TimePoint date_filte
do {
ret.push_back(EventsTableRow{
(*retQuery)[0].getUInt32(), // ID
- (*retQuery)[1].getString(), // title
- TimePointFromString((*retQuery)[2].getString().c_str()), // date_from
- TimePointFromString((*retQuery)[3].getString().c_str()), // date_till
- (*retQuery)[4].getUInt32(), // reminder
- (*retQuery)[5].getUInt32(), // repeat
- TimePointFromString((*retQuery)[6].getString().c_str()) // date_till
+ (*retQuery)[1].getString(), // UID
+ (*retQuery)[2].getString(), // title
+ TimePointFromString((*retQuery)[3].getString().c_str()), // date_from
+ TimePointFromString((*retQuery)[4].getString().c_str()), // date_till
+ (*retQuery)[5].getUInt32(), // reminder
+ (*retQuery)[6].getUInt32(), // repeat
+ TimePointFromString((*retQuery)[7].getString().c_str()) // reminder_fired
});
} while (retQuery->nextRow());
@@ 464,7 547,7 @@ std::vector<EventsTableRow> EventsTable::getLimitOffset(uint32_t offset, uint32_
auto retQuery = db->query("SELECT * from events LIMIT %lu OFFSET %lu;", limit, offset);
//"SELECT * FROM event WHERE id = "
- if ((retQuery == nullptr) || (retQuery->getRowCount() == 0)) {
+ if (retQuery == nullptr || retQuery->getRowCount() == 0) {
return std::vector<EventsTableRow>();
}
@@ 473,12 556,14 @@ std::vector<EventsTableRow> EventsTable::getLimitOffset(uint32_t offset, uint32_
do {
ret.push_back(EventsTableRow{
(*retQuery)[0].getUInt32(), // ID
- (*retQuery)[1].getString(), // title
- TimePointFromString((*retQuery)[2].getString().c_str()), // date_from
- TimePointFromString((*retQuery)[3].getString().c_str()), // date_till
- (*retQuery)[4].getUInt32(), // reminder
- (*retQuery)[5].getUInt32(), // repeat
- TimePointFromString((*retQuery)[6].getString().c_str()) // date_till
+ (*retQuery)[1].getString(), // UID
+ (*retQuery)[2].getString(), // title
+ TimePointFromString((*retQuery)[3].getString().c_str()), // date_from
+ TimePointFromString((*retQuery)[4].getString().c_str()), // date_till
+ (*retQuery)[5].getUInt32(), // reminder
+ (*retQuery)[6].getUInt32(), // repeat
+ TimePointFromString((*retQuery)[7].getString().c_str()) // reminder_fired
+
});
} while (retQuery->nextRow());
@@ 490,7 575,7 @@ std::vector<EventsTableRow> EventsTable::getLimitOffsetByDate(uint32_t offset, u
auto retQuery = db->query("SELECT * from events ORDER BY datetime(date_from) LIMIT %u OFFSET %u;", limit, offset);
- if ((retQuery == nullptr) || (retQuery->getRowCount() == 0)) {
+ if (retQuery == nullptr || retQuery->getRowCount() == 0) {
return std::vector<EventsTableRow>();
}
@@ 499,12 584,13 @@ std::vector<EventsTableRow> EventsTable::getLimitOffsetByDate(uint32_t offset, u
do {
ret.push_back(EventsTableRow{
(*retQuery)[0].getUInt32(), // ID
- (*retQuery)[1].getString(), // title
- TimePointFromString((*retQuery)[2].getString().c_str()), // date_from
- TimePointFromString((*retQuery)[3].getString().c_str()), // date_till
- (*retQuery)[4].getUInt32(), // reminder
- (*retQuery)[5].getUInt32(), // repeat
- TimePointFromString((*retQuery)[6].getString().c_str()) // date_till
+ (*retQuery)[1].getString(), // UID
+ (*retQuery)[2].getString(), // title
+ TimePointFromString((*retQuery)[3].getString().c_str()), // date_from
+ TimePointFromString((*retQuery)[4].getString().c_str()), // date_till
+ (*retQuery)[5].getUInt32(), // reminder
+ (*retQuery)[6].getUInt32(), // repeat
+ TimePointFromString((*retQuery)[7].getString().c_str()) // reminder_fired
});
} while (retQuery->nextRow());
@@ 567,7 653,7 @@ std::vector<EventsTableRow> EventsTable::SelectFirstUpcoming(TimePoint filter_fr
TimePointToString(filter_from).c_str(),
TimePointToString(TIME_POINT_INVALID).c_str());
- if ((retQuery == nullptr) || (retQuery->getRowCount() == 0)) {
+ if (retQuery == nullptr || retQuery->getRowCount() == 0) {
return std::vector<EventsTableRow>();
}
@@ 575,13 661,14 @@ std::vector<EventsTableRow> EventsTable::SelectFirstUpcoming(TimePoint filter_fr
do {
ret.push_back(EventsTableRow{
- (*retQuery)[1].getUInt32(), // ID
+ (*retQuery)[0].getUInt32(), // ID
+ (*retQuery)[1].getString(), // UID
(*retQuery)[2].getString(), // title
TimePointFromString((*retQuery)[3].getString().c_str()), // date_from
TimePointFromString((*retQuery)[4].getString().c_str()), // date_till
(*retQuery)[5].getUInt32(), // reminder
(*retQuery)[6].getUInt32(), // repeat
- TimePointFromString((*retQuery)[7].getString().c_str()) // date_till
+ TimePointFromString((*retQuery)[7].getString().c_str()) // reminder_fired
});
} while (retQuery->nextRow());
M module-db/Tables/EventsTable.hpp => module-db/Tables/EventsTable.hpp +18 -13
@@ 5,16 5,17 @@
#include "Table.hpp"
#include "Record.hpp"
-#include <Database/Database.hpp>
-#include <Common/Common.hpp>
+#include <module-db/Database/Database.hpp>
+#include <module-db/Common/Common.hpp>
#include <utf8/UTF8.hpp>
#include <module-apps/application-calendar/data/dateCommon.hpp>
struct EventsTableRow : public Record
{
+ std::string UID;
std::string title;
- TimePoint date_from = TIME_POINT_INVALID;
- TimePoint date_till = TIME_POINT_INVALID;
+ TimePoint date_from = TIME_POINT_INVALID;
+ TimePoint date_till = TIME_POINT_INVALID;
uint32_t reminder = 0;
uint32_t repeat = 0;
TimePoint reminder_fired = TIME_POINT_INVALID;
@@ 41,8 42,11 @@ class EventsTable : public Table<EventsTableRow, EventsTableFields>
bool addYear(EventsTableRow entry);
bool addCustom(EventsTableRow entry);
bool removeById(uint32_t id) override final;
+ bool removeByUID(const std::string &UID);
bool removeByField(EventsTableFields field, const char *str) override final;
bool update(EventsTableRow entry) override final;
+ bool updateByUID(EventsTableRow entry);
+ EventsTableRow getByUID(const std::string &UID);
EventsTableRow getById(uint32_t id) override final;
std::vector<EventsTableRow> selectByDatePeriod(TimePoint filter_from,
TimePoint filter_till,
@@ 61,13 65,14 @@ class EventsTable : public Table<EventsTableRow, EventsTableFields>
std::vector<EventsTableRow> SelectFirstUpcoming(TimePoint filter_from, TimePoint filter_till);
private:
- const std::string createTableQuery = "CREATE TABLE IF NOT EXISTS events("
- "_id INTEGER PRIMARY KEY AUTOINCREMENT,"
- "title TEXT,"
- "date_from DATETIME,"
- "date_till DATETIME,"
- "reminder INTEGER,"
- "repeat INTEGER,"
- "reminder_fired DATETIME,"
- "UNIQUE (title, date_from, date_till));";
+ const char *createTableQuery = "CREATE TABLE IF NOT EXISTS events("
+ "_id INTEGER PRIMARY KEY AUTOINCREMENT,"
+ "uid TEXT,"
+ "title TEXT,"
+ "date_from DATETIME,"
+ "date_till DATETIME,"
+ "reminder INTEGER,"
+ "repeat INTEGER,"
+ "reminder_fired DATETIME,"
+ "UNIQUE (title, date_from, date_till));";
};
M module-db/queries/calendar/QueryEventsAdd.hpp => module-db/queries/calendar/QueryEventsAdd.hpp +1 -1
@@ 23,7 23,7 @@ namespace db::query::events
class AddResult : public QueryResult
{
public:
- AddResult(bool ret);
+ explicit AddResult(bool ret);
[[nodiscard]] auto getResult() const -> bool;
[[nodiscard]] auto debugInfo() const -> std::string override;
M module-db/queries/calendar/QueryEventsEdit.hpp => module-db/queries/calendar/QueryEventsEdit.hpp +1 -1
@@ 23,7 23,7 @@ namespace db::query::events
class EditResult : public QueryResult
{
public:
- EditResult(bool ret);
+ explicit EditResult(bool ret);
[[nodiscard]] auto getResult() const -> bool;
[[nodiscard]] auto debugInfo() const -> std::string override;
A module-db/queries/calendar/QueryEventsEditICS.cpp => module-db/queries/calendar/QueryEventsEditICS.cpp +33 -0
@@ 0,0 1,33 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "QueryEventsEditICS.hpp"
+
+namespace db::query::events
+{
+ EditICS::EditICS(EventsRecord record) : Query(Query::Type::Update), record(record)
+ {}
+
+ auto EditICS::getRecord() const -> EventsRecord
+ {
+ return record;
+ }
+
+ auto EditICS::debugInfo() const -> std::string
+ {
+ return "Edit";
+ }
+
+ EditICSResult::EditICSResult(bool ret) : ret(ret)
+ {}
+
+ auto EditICSResult::getResult() const -> bool
+ {
+ return ret;
+ }
+
+ auto EditICSResult::debugInfo() const -> std::string
+ {
+ return "EditResult";
+ }
+} // namespace db::query::events
A module-db/queries/calendar/QueryEventsEditICS.hpp => module-db/queries/calendar/QueryEventsEditICS.hpp +34 -0
@@ 0,0 1,34 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include "module-db/Interface/EventsRecord.hpp"
+#include <Common/Query.hpp>
+#include <string>
+
+namespace db::query::events
+{
+ class EditICS : public Query
+ {
+ EventsRecord record;
+
+ public:
+ EditICS(EventsRecord record);
+
+ [[nodiscard]] auto getRecord() const -> EventsRecord;
+ [[nodiscard]] auto debugInfo() const -> std::string override;
+ };
+
+ class EditICSResult : public QueryResult
+ {
+ public:
+ explicit EditICSResult(bool ret);
+ [[nodiscard]] auto getResult() const -> bool;
+
+ [[nodiscard]] auto debugInfo() const -> std::string override;
+
+ bool ret;
+ };
+
+} // namespace db::query::events
M module-db/queries/calendar/QueryEventsRemove.cpp => module-db/queries/calendar/QueryEventsRemove.cpp +1 -1
@@ 13,7 13,7 @@ namespace db::query::events
return "Remove";
}
- RemoveResult::RemoveResult(const bool &ret) : ret(ret)
+ RemoveResult::RemoveResult(bool ret) : ret(ret)
{}
auto RemoveResult::getResult() const -> bool
M module-db/queries/calendar/QueryEventsRemove.hpp => module-db/queries/calendar/QueryEventsRemove.hpp +2 -2
@@ 21,10 21,10 @@ namespace db::query::events
class RemoveResult : public QueryResult
{
- const bool ret = true;
+ bool ret;
public:
- RemoveResult(const bool &ret);
+ explicit RemoveResult(bool ret);
[[nodiscard]] auto getResult() const -> bool;
[[nodiscard]] auto debugInfo() const -> std::string override;
A module-db/queries/calendar/QueryEventsRemoveICS.cpp => module-db/queries/calendar/QueryEventsRemoveICS.cpp +28 -0
@@ 0,0 1,28 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "QueryEventsRemoveICS.hpp"
+
+namespace db::query::events
+{
+ RemoveICS::RemoveICS(const std::string &UID) : Query(Query::Type::Delete), UID(UID)
+ {}
+
+ auto RemoveICS::debugInfo() const -> std::string
+ {
+ return "Remove";
+ }
+
+ RemoveICSResult::RemoveICSResult(bool ret) : ret(ret)
+ {}
+
+ auto RemoveICSResult::getResult() const -> bool
+ {
+ return ret;
+ }
+
+ auto RemoveICSResult::debugInfo() const -> std::string
+ {
+ return "RemoveResult";
+ }
+} // namespace db::query::events
A module-db/queries/calendar/QueryEventsRemoveICS.hpp => module-db/queries/calendar/QueryEventsRemoveICS.hpp +33 -0
@@ 0,0 1,33 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include "module-db/Interface/EventsRecord.hpp"
+#include <Common/Query.hpp>
+#include <string>
+
+namespace db::query::events
+{
+
+ class RemoveICS : public Query
+ {
+ public:
+ RemoveICS(const std::string &UID);
+ [[nodiscard]] auto debugInfo() const -> std::string override;
+
+ std::string UID;
+ };
+
+ class RemoveICSResult : public QueryResult
+ {
+ bool ret;
+
+ public:
+ explicit RemoveICSResult(bool ret);
+ [[nodiscard]] auto getResult() const -> bool;
+
+ [[nodiscard]] auto debugInfo() const -> std::string override;
+ };
+
+} // namespace db::query::events
M module-db/tests/EventsRecord_tests.cpp => module-db/tests/EventsRecord_tests.cpp +16 -6
@@ 44,11 44,13 @@ TEST_CASE("Events Record tests")
SECTION("Constructor from EventsTableRow")
{
EventsTableRow tableRow{{.ID = 10},
+ "test",
"Event3",
TimePointFromString("2019-10-20 14:24:00"),
TimePointFromString("2019-10-20 15:36:00"),
1,
- 2};
+ 2,
+ TIME_POINT_INVALID};
EventsRecord testRec(tableRow);
REQUIRE(testRec.title == "Event3");
REQUIRE(testRec.date_from == TimePointFromString("2019-10-20 14:24:00"));
@@ 65,11 67,14 @@ TEST_CASE("Events Record tests")
REQUIRE(numberOfEvents == 0);
EventsTableRow tableRow{{.ID = 10},
+ "test",
"Event1",
TimePointFromString("2019-10-20 14:24:00"),
TimePointFromString("2019-10-20 15:36:00"),
1,
- 2};
+ 2,
+ TIME_POINT_INVALID};
+
auto rec = EventsRecord(tableRow);
REQUIRE(rec.title == "Event1");
REQUIRE(rec.date_from == TimePointFromString("2019-10-20 14:24:00"));
@@ 108,11 113,14 @@ TEST_CASE("Events Record tests")
}
EventsTableRow tableRow2{{.ID = 10},
+ "test",
"Event2",
TimePointFromString("2025-10-20 14:24:00"),
TimePointFromString("2025-10-20 15:36:00"),
1,
- 2};
+ 2,
+ TIME_POINT_INVALID};
+
auto rec2 = EventsRecord(tableRow2);
REQUIRE(rec2.title == "Event2");
REQUIRE(rec2.date_from == TimePointFromString("2025-10-20 14:24:00"));
@@ 194,11 202,13 @@ TEST_CASE("Events Record tests")
}
EventsTableRow tableRow3{{.ID = 3},
+ "test",
"Event3",
TimePointFromString("2021-10-20 14:24:00"),
TimePointFromString("2021-10-20 15:36:00"),
1,
- 2};
+ 2,
+ TIME_POINT_INVALID};
auto rec3 = EventsRecord(tableRow3);
REQUIRE(rec3.title == "Event3");
REQUIRE(rec3.date_from == TimePointFromString("2021-10-20 14:24:00"));
@@ 247,7 257,7 @@ TEST_CASE("Events Record tests")
};
auto AddQuery = [&](uint32_t id, std::string title, TimePoint date_from, TimePoint date_till) {
- EventsTableRow tableRow2{{.ID = id}, title, date_from, date_till, 1, 2};
+ EventsTableRow tableRow2{{.ID = id}, "test", title, date_from, date_till, 1, 2, TIME_POINT_INVALID};
auto record = EventsRecord(tableRow2);
auto query = std::make_shared<db::query::events::Add>(record);
auto ret = eventsRecordInterface.runQuery(query);
@@ 270,7 280,7 @@ TEST_CASE("Events Record tests")
TimePoint date_till,
uint32_t reminder,
uint32_t repeat) {
- EventsTableRow tableRow2{{.ID = id}, title, date_from, date_till, reminder, repeat};
+ EventsTableRow tableRow2{{.ID = id}, "test", title, date_from, date_till, reminder, repeat, TIME_POINT_INVALID};
auto record = EventsRecord(tableRow2);
auto query = std::make_shared<db::query::events::Edit>(record);
auto ret = eventsRecordInterface.runQuery(query);
M module-db/tests/EventsTable_tests.cpp => module-db/tests/EventsTable_tests.cpp +109 -71
@@ 30,6 30,7 @@ TEST_CASE("Events Table tests")
{
EventsTableRow testRow;
REQUIRE(testRow.ID == DB_ID_NONE);
+ REQUIRE(testRow.UID == "");
REQUIRE(testRow.title == "");
REQUIRE(testRow.date_from == TIME_POINT_INVALID);
REQUIRE(testRow.date_till == TIME_POINT_INVALID);
@@ 40,17 41,22 @@ TEST_CASE("Events Table tests")
}
REQUIRE(eventsTbl.add({{.ID = 0},
- .title = "Event3",
- .date_from = TimePointFromString("2019-10-20 14:24:00"),
- .date_till = TimePointFromString("2019-10-20 15:36:00"),
- .reminder = 1,
- .repeat = 2}));
+ .UID = "test",
+ .title = "Event3",
+ .date_from = TimePointFromString("2019-10-20 14:24:00"),
+ .date_till = TimePointFromString("2019-10-20 15:36:00"),
+ .reminder = 1,
+ .repeat = 2,
+ .reminder_fired = TimePointFromString("2019-10-20 15:36:00")}));
+
REQUIRE(eventsTbl.add({{.ID = 0},
- .title = "Event4",
- .date_from = TimePointFromString("2021-10-20 12:24:00"),
- .date_till = TimePointFromString("2021-10-20 15:36:00"),
- .reminder = 0,
- .repeat = 3}));
+ .UID = "test",
+ .title = "Event4",
+ .date_from = TimePointFromString("2021-10-20 12:24:00"),
+ .date_till = TimePointFromString("2021-10-20 15:36:00"),
+ .reminder = 0,
+ .repeat = 3,
+ .reminder_fired = TimePointFromString("2019-10-20 15:36:00")}));
REQUIRE(eventsTbl.count() == 2);
@@ 85,11 91,13 @@ TEST_CASE("Events Table tests")
SECTION("Update entry by ID")
{
auto entry = EventsTableRow({{.ID = 2},
+ "test",
"TestUpdateEvent",
TimePointFromString("2019-10-20 15:00:00"),
TimePointFromString("2019-10-20 18:54:00"),
0,
- 2});
+ 2,
+ TIME_POINT_INVALID});
REQUIRE(eventsTbl.update(entry));
auto record = eventsTbl.getById(2);
REQUIRE(record.ID == 2);
@@ 104,41 112,53 @@ TEST_CASE("Events Table tests")
SECTION("Select entry by date")
{
REQUIRE(eventsTbl.add({{.ID = 0},
- .title = "Event5",
- .date_from = TimePointFromString("2019-10-20 14:24:00"),
- .date_till = TimePointFromString("2019-10-20 15:36:00"),
- .reminder = 1,
- .repeat = 2}));
+ .UID = "test",
+ .title = "Event5",
+ .date_from = TimePointFromString("2019-10-20 14:24:00"),
+ .date_till = TimePointFromString("2019-10-20 15:36:00"),
+ .reminder = 1,
+ .repeat = 2,
+ .reminder_fired = TimePointFromString("2019-10-20 15:36:00")}));
REQUIRE(eventsTbl.add({{.ID = 1},
- .title = "Event6",
- .date_from = TimePointFromString("2021-04-19 12:24:00"),
- .date_till = TimePointFromString("2021-04-20 15:36:00"),
- .reminder = 0,
- .repeat = 3}));
+ .UID = "test",
+ .title = "Event6",
+ .date_from = TimePointFromString("2021-04-19 12:24:00"),
+ .date_till = TimePointFromString("2021-04-20 15:36:00"),
+ .reminder = 0,
+ .repeat = 3,
+ .reminder_fired = TimePointFromString("2019-10-20 15:36:00")}));
REQUIRE(eventsTbl.add({{.ID = 2},
- .title = "Event7",
- .date_from = TimePointFromString("2019-10-20 15:24:00"),
- .date_till = TimePointFromString("2019-10-20 15:36:00"),
- .reminder = 1,
- .repeat = 2}));
+ .UID = "test",
+ .title = "Event7",
+ .date_from = TimePointFromString("2019-10-20 15:24:00"),
+ .date_till = TimePointFromString("2019-10-20 15:36:00"),
+ .reminder = 1,
+ .repeat = 2,
+ .reminder_fired = TimePointFromString("2019-10-20 15:36:00")}));
REQUIRE(eventsTbl.add({{.ID = 3},
- .title = "Event8",
- .date_from = TimePointFromString("2021-04-19 12:24:00"),
- .date_till = TimePointFromString("2019-10-20 15:36:00"),
- .reminder = 0,
- .repeat = 3}));
+ .UID = "test",
+ .title = "Event8",
+ .date_from = TimePointFromString("2021-04-19 12:24:00"),
+ .date_till = TimePointFromString("2019-10-20 15:36:00"),
+ .reminder = 0,
+ .repeat = 3,
+ .reminder_fired = TimePointFromString("2019-10-20 15:36:00")}));
REQUIRE(eventsTbl.add({{.ID = 4},
- .title = "Event9",
- .date_from = TimePointFromString("2025-10-20 15:24:00"),
- .date_till = TimePointFromString("2025-10-20 15:36:00"),
- .reminder = 1,
- .repeat = 2}));
+ .UID = "test",
+ .title = "Event9",
+ .date_from = TimePointFromString("2025-10-20 15:24:00"),
+ .date_till = TimePointFromString("2025-10-20 15:36:00"),
+ .reminder = 1,
+ .repeat = 2,
+ .reminder_fired = TimePointFromString("2019-10-20 15:36:00")}));
REQUIRE(eventsTbl.add({{.ID = 5},
- .title = "Event10",
- .date_from = TimePointFromString("2021-12-19 12:24:00"),
- .date_till = TimePointFromString("2021-12-20 15:36:00"),
- .reminder = 0,
- .repeat = 3}));
+ .UID = "test",
+ .title = "Event10",
+ .date_from = TimePointFromString("2021-12-19 12:24:00"),
+ .date_till = TimePointFromString("2021-12-20 15:36:00"),
+ .reminder = 0,
+ .repeat = 3,
+ .reminder_fired = TimePointFromString("2019-10-20 15:36:00")}));
auto entries = eventsTbl.selectByDatePeriod(
TimePointFromString("2000-01-01 00:00:00"), TimePointFromString("2012-12-31 23:59:00"), 0, UINT32_MAX);
@@ 168,41 188,53 @@ TEST_CASE("Events Table tests")
const std::array<uint32_t, 6> paramID{3, 4, 5, 6, 7, 8};
const std::array<std::string, 6> paramName{"Event1", "Event2", "Event3", "Event4", "Event5", "Event6"};
REQUIRE(eventsTbl.add({{.ID = 1},
- .title = "Event1",
- .date_from = paramDate[0],
- .date_till = TimePointFromString("2030-10-20 15:24"),
- .reminder = 0,
- .repeat = 0}));
+ .UID = "test",
+ .title = "Event1",
+ .date_from = paramDate[0],
+ .date_till = TimePointFromString("2030-10-20 15:24"),
+ .reminder = 0,
+ .repeat = 0,
+ .reminder_fired = TimePointFromString("2019-10-20 15:36:00")}));
REQUIRE(eventsTbl.add({{.ID = 2},
- .title = "Event2",
- .date_from = paramDate[5],
- .date_till = TimePointFromString("2030-10-20 15:24"),
- .reminder = 0,
- .repeat = 0}));
+ .UID = "test",
+ .title = "Event2",
+ .date_from = paramDate[5],
+ .date_till = TimePointFromString("2030-10-20 15:24"),
+ .reminder = 0,
+ .repeat = 0,
+ .reminder_fired = TimePointFromString("2019-10-20 15:36:00")}));
REQUIRE(eventsTbl.add({{.ID = 3},
- .title = "Event3",
- .date_from = paramDate[2],
- .date_till = TimePointFromString("2030-10-20 15:24"),
- .reminder = 0,
- .repeat = 0}));
+ .UID = "test",
+ .title = "Event3",
+ .date_from = paramDate[2],
+ .date_till = TimePointFromString("2030-10-20 15:24"),
+ .reminder = 0,
+ .repeat = 0,
+ .reminder_fired = TimePointFromString("2019-10-20 15:36:00")}));
REQUIRE(eventsTbl.add({{.ID = 4},
- .title = "Event4",
- .date_from = paramDate[3],
- .date_till = TimePointFromString("2030-10-20 15:24"),
- .reminder = 0,
- .repeat = 0}));
+ .UID = "test",
+ .title = "Event4",
+ .date_from = paramDate[3],
+ .date_till = TimePointFromString("2030-10-20 15:24"),
+ .reminder = 0,
+ .repeat = 0,
+ .reminder_fired = TimePointFromString("2019-10-20 15:36:00")}));
REQUIRE(eventsTbl.add({{.ID = 5},
- .title = "Event5",
- .date_from = paramDate[4],
- .date_till = TimePointFromString("2030-10-20 15:24"),
- .reminder = 0,
- .repeat = 0}));
+ .UID = "test",
+ .title = "Event5",
+ .date_from = paramDate[4],
+ .date_till = TimePointFromString("2030-10-20 15:24"),
+ .reminder = 0,
+ .repeat = 0,
+ .reminder_fired = TimePointFromString("2019-10-20 15:36:00")}));
REQUIRE(eventsTbl.add({{.ID = 6},
- .title = "Event6",
- .date_from = paramDate[1],
- .date_till = TimePointFromString("2030-10-20 15:24"),
- .reminder = 0,
- .repeat = 0}));
+ .UID = "test",
+ .title = "Event6",
+ .date_from = paramDate[1],
+ .date_till = TimePointFromString("2030-10-20 15:24"),
+ .reminder = 0,
+ .repeat = 0,
+ .reminder_fired = TimePointFromString("2019-10-20 15:36:00")}));
auto entries = eventsTbl.getLimitOffsetByDate(0, 6);
REQUIRE(entries.size() == 6);
@@ 240,6 272,7 @@ TEST_CASE("Events Table tests")
TimePoint firedDate = TimePointFromString("2018-10-20 14:24:00");
REQUIRE(eventsTbl.add({{.ID = 1},
+ .UID = "test",
.title = "Event1",
.date_from = paramDate[0],
.date_till = tillDate,
@@ 247,6 280,7 @@ TEST_CASE("Events Table tests")
.repeat = 0,
.reminder_fired = TIME_POINT_INVALID}));
REQUIRE(eventsTbl.add({{.ID = 2},
+ .UID = "test",
.title = "Event2",
.date_from = paramDate[1],
.date_till = tillDate,
@@ 254,6 288,7 @@ TEST_CASE("Events Table tests")
.repeat = 0,
.reminder_fired = TIME_POINT_INVALID}));
REQUIRE(eventsTbl.add({{.ID = 3},
+ .UID = "test",
.title = "Event3",
.date_from = paramDate[2],
.date_till = tillDate,
@@ 261,6 296,7 @@ TEST_CASE("Events Table tests")
.repeat = 0,
.reminder_fired = firedDate}));
REQUIRE(eventsTbl.add({{.ID = 4},
+ .UID = "test",
.title = "Event4",
.date_from = paramDate[3],
.date_till = tillDate,
@@ 268,6 304,7 @@ TEST_CASE("Events Table tests")
.repeat = 0,
.reminder_fired = firedDate}));
REQUIRE(eventsTbl.add({{.ID = 5},
+ .UID = "test",
.title = "Event5",
.date_from = paramDate[4],
.date_till = tillDate,
@@ 275,6 312,7 @@ TEST_CASE("Events Table tests")
.repeat = 0,
.reminder_fired = TIME_POINT_INVALID}));
REQUIRE(eventsTbl.add({{.ID = 6},
+ .UID = "test",
.title = "Event6",
.date_from = paramDate[5],
.date_till = tillDate,
M module-services/service-desktop/CMakeLists.txt => module-services/service-desktop/CMakeLists.txt +2 -0
@@ 19,6 19,8 @@ set(SOURCES
endpoints/update/UpdateEndpoint.cpp
endpoints/update/UpdateMuditaOS.cpp
endpoints/filesystem/FilesystemEndpoint.cpp
+ endpoints/calendarEvents/CalendarEventsHelper.cpp
+ endpoints/calendarEvents/CalendarEventsEndpoint.cpp
parser/ParserUtils.cpp
parser/ParserFSM.cpp
A module-services/service-desktop/endpoints/CMakeLists.txt => module-services/service-desktop/endpoints/CMakeLists.txt +0 -0
M module-services/service-desktop/endpoints/EndpointFactory.hpp => module-services/service-desktop/endpoints/EndpointFactory.hpp +3 -0
@@ 6,6 6,7 @@
#include "Endpoint.hpp"
#include "Service/Service.hpp"
+#include "calendarEvents/CalendarEventsEndpoint.hpp"
#include "backup/BackupEndpoint.hpp"
#include "deviceInfo/DeviceInfoEndpoint.hpp"
#include "update/UpdateEndpoint.hpp"
@@ 47,6 48,8 @@ class EndpointFactory
return std::make_unique<CalllogEndpoint>(ownerServicePtr);
case EndpointType::developerMode:
return std::make_unique<DeveloperModeEndpoint>(ownerServicePtr);
+ case EndpointType::calendarEvents:
+ return std::make_unique<CalendarEventsEndpoint>(ownerServicePtr);
default:
return nullptr;
}
A module-services/service-desktop/endpoints/calendarEvents/CalendarEventsEndpoint.cpp => module-services/service-desktop/endpoints/calendarEvents/CalendarEventsEndpoint.cpp +27 -0
@@ 0,0 1,27 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "CalendarEventsEndpoint.hpp"
+#include "queries/phonebook/QueryContactGet.hpp"
+#include <memory>
+#include <string>
+
+using namespace parserFSM;
+
+auto CalendarEventsEndpoint::handle(Context &context) -> void
+{
+ switch (context.getMethod()) {
+ case http::Method::get:
+ helper->requestDataFromDB(context);
+ break;
+ case http::Method::post: // update entry
+ helper->updateDBEntry(context);
+ break;
+ case http::Method::put:
+ helper->createDBEntry(context);
+ break;
+ case http::Method::del:
+ helper->deleteDBEntry(context);
+ break;
+ }
+}
A module-services/service-desktop/endpoints/calendarEvents/CalendarEventsEndpoint.hpp => module-services/service-desktop/endpoints/calendarEvents/CalendarEventsEndpoint.hpp +24 -0
@@ 0,0 1,24 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <endpoints/Endpoint.hpp>
+#include "Service/Service.hpp"
+#include "CalendarEventsHelper.hpp"
+
+using namespace parserFSM;
+
+class CalendarEventsEndpoint : public Endpoint
+{
+ private:
+ std::string debugName = "CalendarEventsEndpoint";
+ std::unique_ptr<CalendarEventsHelper> helper;
+
+ public:
+ CalendarEventsEndpoint(sys::Service *_ownerServicePtr) : Endpoint(_ownerServicePtr)
+ {
+ helper = std::make_unique<CalendarEventsHelper>(ownerServicePtr);
+ }
+ void handle(Context &context) override;
+};
A module-services/service-desktop/endpoints/calendarEvents/CalendarEventsHelper.cpp => module-services/service-desktop/endpoints/calendarEvents/CalendarEventsHelper.cpp +334 -0
@@ 0,0 1,334 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "EventsRecord.hpp"
+#include "CalendarEventsHelper.hpp"
+#include "Common/Query.hpp"
+#include <parser/ParserUtils.hpp>
+#include "Service/Common.hpp"
+#include <service-db/DBServiceAPI.hpp>
+#include "log/log.hpp"
+#include "json/json11.hpp"
+#include <queries/calendar/QueryEventsGetAll.hpp>
+#include <queries/calendar/QueryEventsGet.hpp>
+#include <queries/calendar/QueryEventsAdd.hpp>
+#include <queries/calendar/QueryEventsEdit.hpp>
+#include <queries/calendar/QueryEventsEditICS.hpp>
+#include <queries/calendar/QueryEventsRemove.hpp>
+#include <queries/calendar/QueryEventsRemoveICS.hpp>
+#include <queries/calendar/QueryEventsGetAllLimited.hpp>
+#include <variant>
+
+namespace parserFSM
+{
+ namespace ical
+ {
+ namespace duration
+ {
+ const inline auto five_minutes_before = Duration(0, 0, 0, 5);
+ const inline auto fifteen_minutes_before = Duration(0, 0, 0, 15);
+ const inline auto thirty_minutes_before = Duration(0, 0, 0, 30);
+ const inline auto one_hour_before = Duration(0, 0, 1, 0);
+ const inline auto two_hours_before = Duration(0, 0, 2, 0);
+ const inline auto one_day_before = Duration(0, 1, 0, 0);
+ const inline auto two_days_before = Duration(0, 2, 0, 0);
+ const inline auto one_week_before = Duration(1, 0, 0, 0);
+ const inline auto event_time = Duration(0, 0, 0, 0);
+ } // namespace duration
+ } // namespace ical
+
+ namespace json::calendar::events
+ {
+ constexpr inline auto UID = "UID";
+ constexpr inline auto data = "data";
+ constexpr inline auto offset = "offset";
+ constexpr inline auto limit = "limit";
+ constexpr inline auto count = "count";
+ } // namespace json::calendar::events
+} // namespace parserFSM
+using namespace parserFSM;
+
+auto CalendarEventsHelper::frequencyFromCustomRepeat(Repeat repeat) const -> Frequency
+{
+ return Frequency(static_cast<uint32_t>(repeat));
+}
+
+auto CalendarEventsHelper::recurrenceRuleFrom(Repeat repeat) const -> RecurrenceRule
+{
+ if (repeat > Repeat::yearly) {
+ uint32_t count = 1, interval = 1;
+ return RecurrenceRule(frequencyFromCustomRepeat(repeat), count, interval);
+ }
+ switch (repeat) {
+ case Repeat::never: {
+ return RecurrenceRule();
+ }
+ case Repeat::daily: {
+ uint32_t count = 7, interval = 1;
+ return RecurrenceRule(Frequency::daily, count, interval);
+ }
+ case Repeat::weekly: {
+ uint32_t count = 4, interval = 1;
+ return RecurrenceRule(Frequency::weekly, count, interval);
+ }
+ case Repeat::biweekly: {
+ uint32_t count = 4, interval = 2;
+ return RecurrenceRule(Frequency::weekly, count, interval);
+ }
+ case Repeat::monthly: {
+ uint32_t count = 12, interval = 1;
+ return RecurrenceRule(Frequency::monthly, count, interval);
+ }
+ case Repeat::yearly: {
+ uint32_t count = 4, interval = 1;
+ return RecurrenceRule(Frequency::yearly, count, interval);
+ }
+ }
+
+ return RecurrenceRule();
+}
+
+auto CalendarEventsHelper::alarmFrom(Reminder reminder) const -> Alarm
+{
+ switch (reminder) {
+ case Reminder::never: {
+ return Alarm();
+ }
+ case Reminder::five_min_before: {
+ auto beforeEvent = ical::duration::five_minutes_before;
+ return Alarm(beforeEvent, Action::display);
+ }
+ case Reminder::fifteen_min_before: {
+ auto beforeEvent = ical::duration::fifteen_minutes_before;
+ return Alarm(beforeEvent, Action::display);
+ }
+ case Reminder::thirty_min_before: {
+ auto beforeEvent = ical::duration::thirty_minutes_before;
+ return Alarm(beforeEvent, Action::display);
+ }
+ case Reminder::one_hour_before: {
+ auto beforeEvent = ical::duration::one_hour_before;
+ return Alarm(beforeEvent, Action::display);
+ }
+ case Reminder::two_hour_before: {
+ auto beforeEvent = ical::duration::two_hours_before;
+ return Alarm(beforeEvent, Action::display);
+ }
+ case Reminder::one_day_before: {
+ auto beforeEvent = ical::duration::one_day_before;
+ return Alarm(beforeEvent, Action::display);
+ }
+ case Reminder::two_days_before: {
+ auto beforeEvent = ical::duration::two_days_before;
+ return Alarm(beforeEvent, Action::display);
+ }
+ case Reminder::one_week_before: {
+ auto beforeEvent = ical::duration::one_week_before;
+ return Alarm(beforeEvent, Action::display);
+ }
+ case Reminder::event_time: {
+ auto beforeEvent = ical::duration::event_time;
+ return Alarm(beforeEvent, Action::display);
+ }
+ }
+ return Alarm();
+}
+
+auto CalendarEventsHelper::icalEventFrom(const EventsRecord &record) const -> ICalEvent
+{
+
+ auto event = Event(record.title, record.date_from, record.date_till, record.UID);
+ auto alarm = alarmFrom(Reminder(record.reminder));
+ auto rrule = recurrenceRuleFrom(Repeat(record.repeat));
+ return ICalEvent{event, alarm, rrule};
+}
+
+auto CalendarEventsHelper::requestDataFromDB(Context &context) -> sys::ReturnCodes
+{
+ auto obj = context.getBody();
+ uint32_t offset = obj[json::calendar::events::offset].int_value();
+ uint32_t limit = obj[json::calendar::events::limit].int_value();
+ auto query = std::make_unique<db::query::events::GetAllLimited>(offset, limit);
+
+ auto listener = std::make_unique<db::EndpointListener>(
+ [&](db::QueryResult *result, Context context) {
+ if (auto EventsResult = dynamic_cast<db::query::events::GetAllLimitedResult *>(result)) {
+ auto records = EventsResult->getResult();
+ assert(records != nullptr);
+ auto parser = std::make_unique<ParserICS>();
+ std::vector<ICalEvent> icalEvents;
+ for (auto rec : *records) {
+ icalEvents.push_back(icalEventFrom(rec));
+ }
+ parser->importEvents(icalEvents);
+ auto jsonObj = json11::Json::object({{json::calendar::events::data, parser->getIcsData()},
+ {json::calendar::events::count, std::to_string(records->size())}});
+
+ context.setResponseBody(jsonObj);
+ MessageHandler::putToSendQueue(context.createSimpleResponse());
+ return true;
+ }
+ return false;
+ },
+ context);
+
+ query->setQueryListener(std::move(listener));
+ auto ret = DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::Events, std::move(query));
+
+ if (ret) {
+ return sys::ReturnCodes::Success;
+ }
+ else {
+ return sys::ReturnCodes::Failure;
+ }
+}
+
+auto CalendarEventsHelper::frequencyToCustomRepeat(Frequency freq) const -> uint32_t
+{
+ return static_cast<uint32_t>(freq);
+}
+
+auto CalendarEventsHelper::repeatFrom(RecurrenceRule &rrule) const -> Repeat
+{
+ auto freq = rrule.getFrequencyValue();
+ switch (freq) {
+ case Frequency::daily: {
+ return Repeat::daily;
+ }
+ case Frequency::weekly: {
+ if (rrule.getIntervalValue() == 1) {
+ return Repeat::weekly;
+ }
+ else if (rrule.getIntervalValue() == 2) {
+ return Repeat::biweekly;
+ }
+ else {
+ LOG_ERROR("Interval invalid");
+ return Repeat::never;
+ }
+ }
+ case Frequency::monthly: {
+ return Repeat::monthly;
+ }
+ case Frequency::yearly: {
+ return Repeat::yearly;
+ }
+ case Frequency::invalid: {
+ LOG_ERROR("Frequency invalid");
+ return Repeat::never;
+ }
+ }
+ return Repeat::never;
+}
+
+auto CalendarEventsHelper::eventsRecordFrom(ICalEvent &icalEvent) const -> EventsRecord
+{
+
+ auto record = EventsRecord();
+ record.UID = icalEvent.event.getUID();
+ record.title = icalEvent.event.getSummary();
+ record.date_from = icalEvent.event.getDTStartTimePoint();
+ record.date_till = icalEvent.event.getDTEndTimePoint();
+ if (icalEvent.rrule.getFrequencyValue() > Frequency::yearly) {
+ record.repeat = frequencyToCustomRepeat(icalEvent.rrule.getFrequencyValue());
+ }
+ record.repeat = static_cast<uint32_t>(repeatFrom(icalEvent.rrule));
+ record.reminder = icalEvent.alarm.getTriggerValue().getDurationInMinutes();
+
+ return record;
+}
+
+auto CalendarEventsHelper::createDBEntry(Context &context) -> sys::ReturnCodes
+{
+ auto parser = std::make_unique<ParserICS>();
+ parser->loadData(context.getBody()[json::calendar::events::data].string_value());
+ auto icalEvents = parser->exportEvents();
+
+ bool ret = true;
+ for (auto event : icalEvents) {
+ auto record = eventsRecordFrom(event);
+ auto query = std::make_unique<db::query::events::Add>(record);
+
+ auto listener = std::make_unique<db::EndpointListener>(
+ [=](db::QueryResult *result, Context context) {
+ if (auto EventResult = dynamic_cast<db::query::events::AddResult *>(result)) {
+ context.setResponseStatus(EventResult->getResult() ? http::Code::OK
+ : http::Code::InternalServerError);
+ MessageHandler::putToSendQueue(context.createSimpleResponse());
+ return true;
+ }
+ return false;
+ },
+ context);
+
+ query->setQueryListener(std::move(listener));
+ ret = ret && DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::Events, std::move(query));
+ }
+
+ if (ret) {
+ return sys::ReturnCodes::Success;
+ }
+ else {
+ return sys::ReturnCodes::Failure;
+ }
+}
+
+auto CalendarEventsHelper::updateDBEntry(Context &context) -> sys::ReturnCodes
+{
+ auto parser = std::make_unique<ParserICS>();
+ parser->loadData(context.getBody()[json::calendar::events::data].string_value());
+ auto icalEvents = parser->exportEvents();
+
+ bool ret = true;
+ for (auto event : icalEvents) {
+
+ auto record = eventsRecordFrom(event);
+ auto query = std::make_unique<db::query::events::EditICS>(record);
+ auto listener = std::make_unique<db::EndpointListener>(
+ [](db::QueryResult *result, Context context) {
+ if (auto EventResult = dynamic_cast<db::query::events::EditICSResult *>(result)) {
+ context.setResponseStatus(EventResult->getResult() ? http::Code::OK
+ : http::Code::InternalServerError);
+ MessageHandler::putToSendQueue(context.createSimpleResponse());
+ return true;
+ }
+ return false;
+ },
+ context);
+
+ query->setQueryListener(std::move(listener));
+ ret = ret && DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::Events, std::move(query));
+ }
+ if (ret) {
+ return sys::ReturnCodes::Success;
+ }
+ else {
+ return sys::ReturnCodes::Failure;
+ }
+}
+
+auto CalendarEventsHelper::deleteDBEntry(Context &context) -> sys::ReturnCodes
+{
+ auto UID = context.getBody()[json::calendar::events::UID].string_value();
+ auto query = std::make_unique<db::query::events::RemoveICS>(UID);
+ auto listener = std::make_unique<db::EndpointListener>(
+ [=](db::QueryResult *result, Context context) {
+ if (auto EventResult = dynamic_cast<db::query::events::RemoveICSResult *>(result)) {
+ context.setResponseStatus(EventResult->getResult() ? http::Code::OK : http::Code::InternalServerError);
+ MessageHandler::putToSendQueue(context.createSimpleResponse());
+ return true;
+ }
+ return false;
+ },
+ context);
+
+ query->setQueryListener(std::move(listener));
+ auto ret = DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::Events, std::move(query));
+
+ if (ret) {
+ return sys::ReturnCodes::Success;
+ }
+ else {
+ return sys::ReturnCodes::Failure;
+ }
+}
A module-services/service-desktop/endpoints/calendarEvents/CalendarEventsHelper.hpp => module-services/service-desktop/endpoints/calendarEvents/CalendarEventsHelper.hpp +41 -0
@@ 0,0 1,41 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include "Common/Query.hpp"
+#include "EventsRecord.hpp"
+#include "Service/Service.hpp"
+#include "Service/Common.hpp"
+#include <memory>
+#include <service-db/DBServiceAPI.hpp>
+#include <endpoints/Endpoint.hpp>
+#include <endpoints/Context.hpp>
+#include <endpoints/DBHelper.hpp>
+
+#include <module-utils/ical/ParserICS.hpp>
+
+namespace parserFSM
+{
+
+ class CalendarEventsHelper : public DBHelper
+ {
+ [[nodiscard]] auto frequencyFromCustomRepeat(Repeat repeat) const -> Frequency;
+ [[nodiscard]] auto recurrenceRuleFrom(Repeat repeat) const -> RecurrenceRule;
+ [[nodiscard]] auto alarmFrom(Reminder reminder) const -> Alarm;
+ [[nodiscard]] auto icalEventFrom(const EventsRecord &record) const -> ICalEvent;
+
+ [[nodiscard]] auto frequencyToCustomRepeat(Frequency freq) const -> uint32_t;
+ [[nodiscard]] auto repeatFrom(RecurrenceRule &rrule) const -> Repeat;
+ [[nodiscard]] auto eventsRecordFrom(ICalEvent &icalEvent) const -> EventsRecord;
+
+ public:
+ CalendarEventsHelper(sys::Service *_ownerServicePtr) : DBHelper(_ownerServicePtr)
+ {}
+
+ auto createDBEntry(Context &context) -> sys::ReturnCodes override;
+ auto requestDataFromDB(Context &context) -> sys::ReturnCodes override;
+ auto updateDBEntry(Context &context) -> sys::ReturnCodes override;
+ auto deleteDBEntry(Context &context) -> sys::ReturnCodes override;
+ };
+} // namespace parserFSM
M module-services/service-desktop/parser/ParserUtils.hpp => module-services/service-desktop/parser/ParserUtils.hpp +2 -1
@@ 25,7 25,8 @@ namespace parserFSM
contacts,
messages,
calllog,
- developerMode,
+ calendarEvents,
+ developerMode
};
inline constexpr auto lastEndpoint = static_cast<int>(EndpointType::developerMode);
M module-utils/CMakeLists.txt => module-utils/CMakeLists.txt +1 -0
@@ 33,6 33,7 @@ set (SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/NumberHolderMatcher.hpp
${CMAKE_CURRENT_SOURCE_DIR}/country.hpp
${CMAKE_CURRENT_SOURCE_DIR}/state/ServiceState.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/ical/ParserICS.cpp
)
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${BOARD_SOURCES})
A module-utils/ical/ParserICS.cpp => module-utils/ical/ParserICS.cpp +610 -0
@@ 0,0 1,610 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "ParserICS.hpp"
+//#include <exception>
+
+namespace ical
+{
+ constexpr inline auto begin = "BEGIN:VCALENDAR";
+
+ namespace with_linefeed
+ {
+ constexpr inline auto begin = "BEGIN:VCALENDAR\r\n";
+ constexpr inline auto version = "VERSION:2.0\r\n";
+ constexpr inline auto end = "END:VCALENDAR\r\n";
+ } // namespace with_linefeed
+
+ namespace event
+ {
+ namespace with_linefeed
+ {
+ constexpr inline auto begin = "BEGIN:VEVENT\r\n";
+ constexpr inline auto end = "END:VEVENT\r\n";
+ } // namespace with_linefeed
+ constexpr inline auto begin = "BEGIN:VEVENT";
+ constexpr inline auto end = "END:VEVENT";
+
+ constexpr inline auto uid = "UID:";
+ constexpr inline auto summary = "SUMMARY:";
+ constexpr inline auto dtstart = "DTSTART:";
+ constexpr inline auto dtend = "DTEND:";
+ } // namespace event
+
+ namespace alarm
+ {
+ namespace with_linefeed
+ {
+ constexpr inline auto begin = "BEGIN:VALARM\r\n";
+ constexpr inline auto end = "END:VALARM\r\n";
+ } // namespace with_linefeed
+ constexpr inline auto begin = "BEGIN:VALARM";
+ constexpr inline auto end = "END:VALARM";
+
+ constexpr inline auto trigger = "TRIGGER:";
+ constexpr inline auto action = "ACTION:";
+
+ namespace value
+ {
+ // Time, 0, Minutes
+ namespace action
+ {
+ constexpr inline auto display = "DISPLAY";
+ constexpr inline auto procedure = "PROCEDURE";
+ constexpr inline auto audio = "AUDIO";
+ } // namespace action
+ constexpr inline auto trigger_invalid = "T0M";
+ constexpr inline auto before = "-P";
+ constexpr inline auto after = "P";
+ } // namespace value
+ } // namespace alarm
+
+ namespace rrule
+ {
+ constexpr inline auto rrule = "RRULE:";
+ constexpr inline auto freq = "FREQ=";
+ namespace frequency
+ {
+ constexpr inline auto daily = "DAILY";
+ constexpr inline auto weekly = "WEEKLY";
+ constexpr inline auto monthly = "MONTHLY";
+ constexpr inline auto yearly = "YEARLY";
+ } // namespace frequency
+ constexpr inline auto count = "COUNT=";
+ constexpr inline auto interval = "INTERVAL=";
+ } // namespace rrule
+
+ namespace duration
+ {
+ constexpr inline auto minutesInHour = 60;
+ constexpr inline auto minutesInDay = 24 * minutesInHour;
+ constexpr inline auto minutesInWeek = 7 * minutesInDay;
+ } // namespace duration
+} // namespace ical
+
+Duration::Duration(uint32_t week, uint32_t day, uint32_t hour, uint32_t minute)
+{
+ this->week = week;
+ this->day = day;
+ this->hour = hour;
+ this->minute = minute;
+}
+
+Duration::Duration(const std::string &property)
+{
+ uint32_t i = 0;
+ if (property.empty() || (property[0] != 'P' && property[1] != 'P')) {
+ LOG_ERROR("Duration constructor: Invalid format provided: %s", property.c_str());
+ return;
+ }
+ while (property[i] != '\0' && i < property.length()) {
+ if (isdigit(property[i])) {
+ std::string value;
+ while (isdigit(property[i])) {
+ value += property[i];
+ ++i;
+ }
+ try {
+ switch (property[i]) {
+ case 'W':
+ this->week = stoi(value);
+ break;
+ case 'D':
+ this->day = stoi(value);
+ break;
+ case 'H':
+ this->hour = stoi(value);
+ break;
+ case 'M':
+ this->minute = stoi(value);
+ break;
+ }
+ }
+ catch (std::exception &e) {
+ LOG_DEBUG("Duration conversion from string to int failed with exception:%s", e.what());
+ }
+ }
+ ++i;
+ }
+}
+
+auto Duration::getDurationInMinutes() const -> uint32_t
+{
+ auto weeksMinutes = week * ical::duration::minutesInWeek;
+ auto daysMinutes = day * ical::duration::minutesInDay;
+ auto hoursMinutes = hour * ical::duration::minutesInHour;
+
+ return weeksMinutes + daysMinutes + hoursMinutes + minute;
+}
+
+auto Duration::getDurationString() const -> std::string
+{
+ std::string durationString;
+ if (week) {
+ durationString += std::to_string(week) + 'W';
+ }
+ if (day) {
+ durationString += std::to_string(day) + 'D';
+ }
+ if (hour || minute) {
+ durationString += 'T';
+ }
+ if (hour) {
+ durationString += std::to_string(hour) + 'H';
+ }
+ if (minute) {
+ durationString += std::to_string(minute) + 'M';
+ }
+ if (week == 0 && day == 0 && hour == 0 && minute == 0) {
+ durationString += "T0M";
+ }
+ return durationString;
+}
+
+Alarm::Alarm(Duration &beforeEvent, Action action)
+{
+ if (beforeEvent.getDurationString().empty()) {
+ LOG_ERROR("Got empty duration value");
+ return;
+ }
+ this->trigger = beforeEvent;
+ this->action = action;
+}
+
+void Alarm::setAction(const std::string &action)
+{
+ if (action == ical::alarm::value::action::display) {
+ this->action = Action::display;
+ }
+ else if (action == ical::alarm::value::action::procedure) {
+ this->action = Action::procedure;
+ }
+ else if (action == ical::alarm::value::action::audio) {
+ this->action = Action::audio;
+ }
+ else {
+ this->action = Action::invalid;
+ }
+}
+
+void Alarm::setTrigger(const std::string &duration)
+{
+ this->trigger = Duration(duration);
+}
+
+auto Alarm::getTriggerValue() const -> Duration
+{
+ return this->trigger;
+}
+
+auto Alarm::getActionValue() const -> Action
+{
+ return this->action;
+}
+
+auto Alarm::getTriggerString() const -> std::string
+{
+ return ical::alarm::value::before + trigger.getDurationString();
+}
+
+auto Alarm::getActionString() const -> std::string
+{
+ std::string actionStr = ical::alarm::action;
+ switch (this->action) {
+ case Action::audio: {
+ return ical::alarm::value::action::audio;
+ }
+ case Action::display: {
+ return ical::alarm::value::action::display;
+ }
+ case Action::procedure: {
+ return ical::alarm::value::action::procedure;
+ }
+ case Action::invalid: {
+ LOG_ERROR("Alarm with no action");
+ return "";
+ }
+ }
+ return "";
+}
+
+RecurrenceRule::RecurrenceRule(Frequency freq, uint32_t count, uint32_t interval)
+{
+ if (count == 0 || interval == 0) {
+ LOG_ERROR("Invalid count or interval value!");
+ return;
+ }
+
+ this->frequency = freq;
+ this->count = count;
+ this->interval = interval;
+}
+
+void RecurrenceRule::setFrequency(const std::string &property)
+{
+ if (property == ical::rrule::frequency::daily) {
+ this->frequency = Frequency::daily;
+ }
+ else if (property == ical::rrule::frequency::weekly) {
+ this->frequency = Frequency::weekly;
+ }
+ else if (property == ical::rrule::frequency::monthly) {
+ this->frequency = Frequency::monthly;
+ }
+ else if (property == ical::rrule::frequency::yearly) {
+ this->frequency = Frequency::yearly;
+ }
+ else {
+ LOG_ERROR("Invalid frequency!");
+ this->frequency = Frequency::invalid;
+ }
+}
+void RecurrenceRule::setCount(const std::string &property)
+{
+ try {
+ this->count = stoi(property);
+ }
+ catch (...) {
+ LOG_ERROR("Count value not conversionable to int!");
+ }
+}
+
+void RecurrenceRule::setInterval(const std::string &property)
+{
+ try {
+ this->interval = stoi(property);
+ }
+ catch (...) {
+ LOG_ERROR("Interval value not conversionable to int!");
+ }
+}
+
+auto RecurrenceRule::getFrequencyValue() const -> Frequency
+{
+ return this->frequency;
+}
+
+auto RecurrenceRule::getCountValue() const -> uint32_t
+{
+ return this->count;
+}
+
+auto RecurrenceRule::getIntervalValue() const -> uint32_t
+{
+ return this->interval;
+}
+
+auto RecurrenceRule::getFrequencyString() const -> std::string
+{
+ std::string frequencyStr = ical::rrule::freq;
+ switch (this->frequency) {
+ case Frequency::daily: {
+ frequencyStr = ical::rrule::frequency::daily;
+ break;
+ }
+ case Frequency::weekly: {
+ frequencyStr = ical::rrule::frequency::weekly;
+ break;
+ }
+ case Frequency::monthly: {
+ frequencyStr = ical::rrule::frequency::monthly;
+ break;
+ }
+ case Frequency::yearly: {
+ frequencyStr = ical::rrule::frequency::yearly;
+ break;
+ }
+ case Frequency::invalid: {
+ LOG_ERROR("Frequency invalid");
+ return "";
+ }
+ }
+ return frequencyStr;
+}
+
+auto RecurrenceRule::getCountString() const -> std::string
+{
+ if (this->frequency == Frequency::invalid) {
+ LOG_ERROR("Frequency value is invalid!");
+ return "";
+ }
+ return std::to_string(this->count);
+}
+
+auto RecurrenceRule::getIntervalString() const -> std::string
+{
+ if (this->frequency == Frequency::invalid) {
+ LOG_ERROR("Frequency value is invalid!");
+ return "";
+ }
+
+ return std::to_string(this->interval);
+}
+
+auto Event::getDateFromIcalFormat(const std::string &icalDateTime) const -> std::string
+{
+ return icalDateTime.substr(0, icalDateTime.find_first_of('T'));
+}
+
+auto Event::getTimeFromIcalFormat(const std::string &icalDateTime) const -> std::string
+{
+ return icalDateTime.substr(icalDateTime.find_first_of('T') + 1);
+}
+
+auto Event::dateStringFrom(const std::string &icalDate) const -> std::string
+{
+ return icalDate.substr(0, yearDigitsNumb) + "-" + icalDate.substr(yearDigitsNumb, monthDigitsNumb) + "-" +
+ icalDate.substr(yearDigitsNumb + monthDigitsNumb, dayDigitsNumb);
+}
+
+auto Event::timeStringFrom(const std::string &icalTime) const -> std::string
+{
+ return icalTime.substr(0, HourDigitsNumb) + ":" + icalTime.substr(HourDigitsNumb, MinDigitsNumb) + ":" +
+ icalTime.substr(HourDigitsNumb + MinDigitsNumb, SecDigitsNumb);
+}
+
+auto Event::TimePointFromIcalDate(const std::string &icalDateTime) const -> TimePoint
+{
+ std::string icalDate(getDateFromIcalFormat(icalDateTime));
+ std::string icalTime(getTimeFromIcalFormat(icalDateTime));
+
+ std::string date(dateStringFrom(icalDate));
+ std::string time(timeStringFrom(icalTime));
+
+ std::string dateTime(date + " " + time);
+
+ return TimePointFromString(dateTime.c_str());
+}
+
+auto Event::TimePointToIcalDate(const TimePoint &tp) const -> std::string
+{
+ constexpr uint32_t bufferLimit = 16;
+ auto time = TimePointToTimeT(tp);
+ auto utcTime = gmtime(&time);
+ char Buffer[bufferLimit];
+ strftime(Buffer, bufferLimit, "%Y%m%dT%H%M%S", utcTime);
+ std::string IcalDate = Buffer;
+ return IcalDate;
+}
+
+Event::Event(const std::string &summary, const TimePoint from, TimePoint till, const std::string &uid)
+{
+ this->summary = summary;
+ this->dtstart = from;
+ this->dtend = till;
+ this->uid = uid;
+}
+
+void Event::setUID(const std::string &property)
+{
+ this->uid = property;
+}
+void Event::setSummary(const std::string &property)
+{
+ this->summary = property;
+}
+void Event::setDTStart(const std::string &property)
+{
+ this->dtstart = TimePointFromIcalDate(property);
+}
+void Event::setDTEnd(const std::string &property)
+{
+ this->dtend = TimePointFromIcalDate(property);
+}
+
+auto Event::getUID() const -> std::string
+{
+ return uid;
+}
+
+auto Event::getSummary() const -> std::string
+{
+ return summary;
+}
+
+auto Event::getDTStartTimePoint() const -> TimePoint
+{
+ return dtstart;
+}
+
+auto Event::getDTEndTimePoint() const -> TimePoint
+{
+ return dtend;
+}
+
+auto Event::getDTStartString() const -> std::string
+{
+ return TimePointToIcalDate(dtstart);
+}
+auto Event::getDTEndString() const -> std::string
+{
+ return TimePointToIcalDate(dtend);
+}
+
+void ParserICS::parseFrom(const Event &event)
+{
+ icsData += ical::event::uid + event.getUID() + "\r\n";
+ icsData += ical::event::summary + event.getSummary() + "\r\n";
+ icsData += ical::event::dtstart + event.getDTStartString() + "\r\n";
+ icsData += ical::event::dtend + event.getDTEndString() + "\r\n";
+}
+
+void ParserICS::parseFrom(const Alarm &alarm)
+{
+ auto triggerValue = alarm.getTriggerString();
+ std::string prefix = ical::alarm::value::before;
+ if (triggerValue == (prefix + ical::alarm::value::trigger_invalid)) {
+ LOG_DEBUG("Got Alarm with empty trigger");
+ return;
+ }
+ icsData += ical::alarm::with_linefeed::begin;
+ icsData += ical::alarm::trigger + triggerValue + "\r\n";
+ icsData += ical::alarm::action + alarm.getActionString() + "\r\n";
+ icsData += ical::alarm::with_linefeed::end;
+}
+
+void ParserICS::parseFrom(const RecurrenceRule &rrule)
+{
+ auto freq = rrule.getFrequencyString();
+ if (!freq.empty()) {
+ icsData += std::string(ical::rrule::rrule) + ical::rrule::freq + freq + ";" + ical::rrule::count +
+ rrule.getCountString() + ";" + ical::rrule::interval + rrule.getIntervalString() + "\r\n";
+ }
+ else {
+ LOG_DEBUG("Empty Alarm provided");
+ }
+}
+
+void ParserICS::parseFrom(const ICalEvent &icalEvent)
+{
+ if (icalEvent.event.getUID() == "") {
+ LOG_ERROR("Empty event provided to ical parser");
+ return;
+ }
+ icsData += ical::event::with_linefeed::begin;
+ parseFrom(icalEvent.event);
+ parseFrom(icalEvent.rrule);
+ parseFrom(icalEvent.alarm);
+ icsData += ical::event::with_linefeed::end;
+}
+
+void ParserICS::eventPropertiesFromLine(ICalEvent &icalEvent, const std::string &line) const
+{
+ if (startsWith(line, ical::event::begin)) {
+ icalEvent.event = Event();
+ }
+ else if (startsWith(line, ical::event::uid)) {
+ icalEvent.event.setUID(getProperty(line));
+ }
+ else if (startsWith(line, ical::event::summary)) {
+ icalEvent.event.setSummary(getProperty(line));
+ }
+ else if (startsWith(line, ical::event::dtstart)) {
+ icalEvent.event.setDTStart(getProperty(line));
+ }
+ else if (startsWith(line, ical::event::dtend)) {
+ icalEvent.event.setDTEnd(getProperty(line));
+ }
+}
+
+void ParserICS::rrulePropertiesFromLine(ICalEvent &icalEvent, const std::string &line) const
+{
+ icalEvent.rrule = RecurrenceRule();
+ auto formattedLine = getProperty(line);
+ icalEvent.rrule.setFrequency(getSubProperty(formattedLine, ical::rrule::freq));
+ icalEvent.rrule.setCount(getSubProperty(formattedLine, ical::rrule::count));
+ icalEvent.rrule.setInterval(getSubProperty(formattedLine, ical::rrule::interval));
+}
+
+void ParserICS::alarmPropertiesFromLine(ICalEvent &icalEvent, std::istringstream &input, std::string &line) const
+{
+ icalEvent.alarm = Alarm();
+
+ while (getline(input, line)) {
+ if (startsWith(line, ical::alarm::trigger)) {
+ icalEvent.alarm.setTrigger(getProperty(line));
+ }
+ else if (startsWith(line, ical::alarm::action)) {
+ icalEvent.alarm.setAction(getProperty(line));
+ }
+ else if (startsWith(line, ical::alarm::end)) {
+ break;
+ }
+ }
+}
+
+auto ParserICS::startsWith(const std::string &line, const char *text) const -> bool
+{
+ return (line.find(text) == 0);
+}
+
+auto ParserICS::getProperty(const std::string &line) const -> std::string
+{
+ std::string Temp = line.substr(line.find_first_of(':') + 1);
+ unsigned int Length = Temp.length();
+ if (Length > 0 && Temp[Length - 1] == '\r')
+ Temp.resize(Length - 1);
+ return Temp;
+}
+
+auto ParserICS::getSubProperty(const std::string &Line, const char *propertyName) const -> std::string
+{
+ size_t pos = Line.find(propertyName);
+ if (pos == std::string::npos)
+ return "";
+ pos += strlen(propertyName);
+ return Line.substr(pos, Line.find_first_of(';', pos) - pos);
+}
+
+void ParserICS::importEvents(std::vector<ICalEvent> events)
+{
+ this->icsData = ical::with_linefeed::begin;
+ this->icsData += +ical::with_linefeed::version;
+
+ for (auto event : events) {
+ parseFrom(event);
+ }
+
+ this->icsData += ical::with_linefeed::end;
+}
+
+auto ParserICS::exportEvents() const -> std::vector<ICalEvent>
+{
+ std::vector<ICalEvent> events;
+ ICalEvent icalEvent;
+
+ std::istringstream input;
+ input.str(icsData);
+ std::string line;
+
+ while (getline(input, line)) {
+ eventPropertiesFromLine(icalEvent, line);
+
+ if (startsWith(line, ical::rrule::rrule)) {
+ rrulePropertiesFromLine(icalEvent, line);
+ }
+ else if (startsWith(line, ical::alarm::begin)) {
+ alarmPropertiesFromLine(icalEvent, input, line);
+ }
+ else if (startsWith(line, ical::event::end)) {
+ events.push_back(icalEvent);
+ }
+ }
+
+ return events;
+}
+
+void ParserICS::loadData(const std::string &data)
+{
+ std::istringstream input;
+ input.str(data);
+ std::string line;
+
+ getline(input, line);
+ if (!startsWith(line, ical::begin)) {
+ LOG_ERROR("Wrong format");
+ return;
+ }
+
+ this->icsData = data;
+}
A module-utils/ical/ParserICS.hpp => module-utils/ical/ParserICS.hpp +154 -0
@@ 0,0 1,154 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+#include <module-apps/application-calendar/data/dateCommon.hpp>
+#include "json/json11.hpp"
+#include <memory>
+
+/**
+ * Icalendar Parser complies with:
+ * @version RFC5545
+ * @link https://tools.ietf.org/html/rfc5545
+ */
+
+class Duration
+{
+ uint32_t week = 0, day = 0, hour = 0, minute = 0;
+
+ public:
+ Duration(uint32_t week = 0, uint32_t day = 0, uint32_t hour = 0, uint32_t minute = 0);
+ explicit Duration(const std::string &property);
+
+ [[nodiscard]] auto getDurationInMinutes() const -> uint32_t;
+ [[nodiscard]] auto getDurationString() const -> std::string;
+};
+
+enum class Action
+{
+ invalid,
+ audio,
+ display,
+ procedure
+};
+
+class Alarm
+{
+ Duration trigger;
+ Action action;
+
+ public:
+ Alarm() = default;
+ explicit Alarm(Duration &beforeEvent, Action action = Action::invalid);
+
+ void setAction(const std::string &action);
+ void setTrigger(const std::string &duration);
+
+ [[nodiscard]] auto getTriggerValue() const -> Duration;
+ [[nodiscard]] auto getActionValue() const -> Action;
+
+ [[nodiscard]] auto getTriggerString() const -> std::string;
+ [[nodiscard]] auto getActionString() const -> std::string;
+};
+
+enum class Frequency
+{
+ invalid,
+ daily,
+ weekly,
+ monthly,
+ yearly
+
+};
+
+class RecurrenceRule
+{
+ Frequency frequency = Frequency::invalid;
+ uint32_t count = 0;
+ uint32_t interval = 0;
+
+ public:
+ RecurrenceRule() = default;
+ RecurrenceRule(Frequency freq, uint32_t count, uint32_t interval);
+
+ void setFrequency(const std::string &property);
+ void setCount(const std::string &property);
+ void setInterval(const std::string &property);
+
+ [[nodiscard]] auto getFrequencyValue() const -> Frequency;
+ [[nodiscard]] auto getCountValue() const -> uint32_t;
+ [[nodiscard]] auto getIntervalValue() const -> uint32_t;
+
+ [[nodiscard]] auto getFrequencyString() const -> std::string;
+ [[nodiscard]] auto getCountString() const -> std::string;
+ [[nodiscard]] auto getIntervalString() const -> std::string;
+};
+
+class Event
+{
+ std::string uid;
+ std::string summary;
+ TimePoint dtstart;
+ TimePoint dtend;
+
+ [[nodiscard]] auto getDateFromIcalFormat(const std::string &icalDateTime) const -> std::string;
+ [[nodiscard]] auto getTimeFromIcalFormat(const std::string &icalDateTime) const -> std::string;
+ [[nodiscard]] auto dateStringFrom(const std::string &icalDate) const -> std::string;
+ [[nodiscard]] auto timeStringFrom(const std::string &icalTime) const -> std::string;
+
+ [[nodiscard]] auto TimePointFromIcalDate(const std::string &icalDateTime) const -> TimePoint;
+ [[nodiscard]] auto TimePointToIcalDate(const TimePoint &tp) const -> std::string;
+
+ public:
+ Event() = default;
+ Event(const std::string &summary, TimePoint from, TimePoint till, const std::string &uid);
+
+ void setUID(const std::string &property);
+ void setSummary(const std::string &property);
+ void setDTStart(const std::string &property);
+ void setDTEnd(const std::string &property);
+
+ [[nodiscard]] auto getUID() const -> std::string;
+ [[nodiscard]] auto getSummary() const -> std::string;
+ [[nodiscard]] auto getDTStartTimePoint() const -> TimePoint;
+ [[nodiscard]] auto getDTEndTimePoint() const -> TimePoint;
+
+ [[nodiscard]] auto getDTStartString() const -> std::string;
+ [[nodiscard]] auto getDTEndString() const -> std::string;
+};
+
+struct ICalEvent
+{
+ Event event;
+ Alarm alarm;
+ RecurrenceRule rrule;
+};
+
+class ParserICS
+{
+ std::string icsData;
+
+ void parseFrom(const Event &event);
+ void parseFrom(const Alarm &alarm);
+ void parseFrom(const RecurrenceRule &rrule);
+ void parseFrom(const ICalEvent &icalEvent);
+
+ auto startsWith(const std::string &line, const char *text) const -> bool;
+ auto getProperty(const std::string &line) const -> std::string;
+ auto getSubProperty(const std::string &Line, const char *propertyName) const -> std::string;
+
+ void eventPropertiesFromLine(ICalEvent &icalEvent, const std::string &line) const;
+ void rrulePropertiesFromLine(ICalEvent &icalEvent, const std::string &line) const;
+ void alarmPropertiesFromLine(ICalEvent &icalEvent, std::istringstream &input, std::string &line) const;
+
+ public:
+ ParserICS() = default;
+ void importEvents(std::vector<ICalEvent> events);
+ [[nodiscard]] auto exportEvents() const -> std::vector<ICalEvent>;
+ void loadData(const std::string &data);
+
+ [[nodiscard]] auto getIcsData() const -> std::string
+ {
+ return icsData;
+ }
+};
M module-utils/test/CMakeLists.txt => module-utils/test/CMakeLists.txt +10 -0
@@ 75,6 75,16 @@ add_catch2_executable(
module-utils
)
+# ParserICS tests
+#add_catch2_executable(
+# NAME
+# utils-parserIcs
+# SRCS
+# test_ParserICS.cpp
+# LIBS
+# module-utils
+#)
+
###########################################
# Log functional tests project
project(test_module-utils_log VERSION 1.0
A module-utils/test/test_ParserICS.cpp => module-utils/test/test_ParserICS.cpp +498 -0
@@ 0,0 1,498 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#define CATCH_CONFIG_MAIN
+
+#include <catch2/catch.hpp>
+#include "ical/ParserICS.hpp"
+
+TEST_CASE("Testing Duration class object", "getDurationString method")
+{
+
+ SECTION("Test regular week values")
+ {
+ int test_values[] = {1, 2, 4, 52, 123};
+ std::string expected_values[] = {"1W", "2W", "4W", "52W", "123W"};
+ int index = 0;
+ for (auto value : test_values) {
+ auto duration = Duration(value, 0, 0, 0);
+ CHECK(duration.getDurationString() == expected_values[index]);
+ index++;
+ }
+ }
+
+ SECTION("Test regular day values")
+ {
+ int test_values[] = {1, 2, 3, 7, 30, 333};
+ std::string expected_values[] = {"1D", "2D", "3D", "7D", "30D", "333D"};
+ int index = 0;
+ for (auto value : test_values) {
+ auto duration = Duration(0, value, 0, 0);
+ CHECK(duration.getDurationString() == expected_values[index]);
+ index++;
+ }
+ }
+
+ SECTION("Test regular hour values")
+ {
+ int test_values[] = {1, 2, 3, 8, 24, 999};
+ std::string expected_values[] = {"T1H", "T2H", "T3H", "T8H", "T24H", "T999H"};
+ int index = 0;
+ for (auto value : test_values) {
+ auto duration = Duration(0, 0, value, 0);
+ CHECK(duration.getDurationString() == expected_values[index]);
+ index++;
+ }
+ }
+
+ SECTION("Test regular minutes values")
+ {
+ int test_values[] = {1, 2, 5, 8, 60, 941683};
+ std::string expected_values[] = {"T1M", "T2M", "T5M", "T8M", "T60M", "T941683M"};
+ int index = 0;
+ for (auto value : test_values) {
+ auto duration = Duration(0, 0, 0, value);
+ CHECK(duration.getDurationString() == expected_values[index]);
+ index++;
+ }
+ }
+
+ SECTION("Test regular mixed week and day values")
+ {
+ int week_test_value = 12;
+ int day_test_value = 34;
+ std::string expected_value = "12W34D";
+
+ auto duration = Duration(week_test_value, day_test_value, 0, 0);
+ CHECK(duration.getDurationString() == expected_value);
+ }
+
+ SECTION("Test regular mixed hours and minutes values")
+ {
+ int hours_test_value = 3;
+ int minutes_test_value = 5;
+ std::string expected_value = "T3H5M";
+
+ auto duration = Duration(0, 0, hours_test_value, minutes_test_value);
+ CHECK(duration.getDurationString() == expected_value);
+ }
+
+ SECTION("Test regular mixed weeks and minutes values")
+ {
+ int week_test_value = 4;
+ int day_test_value = 0;
+ int hours_test_value = 0;
+ int minutes_test_value = 5;
+ std::string expected_value = "4WT5M";
+
+ auto duration = Duration(week_test_value, day_test_value, hours_test_value, minutes_test_value);
+ CHECK(duration.getDurationString() == expected_value);
+ }
+
+ SECTION("Test regular mixed all values")
+ {
+ int week_test_value = 1;
+ int day_test_value = 0;
+ int hours_test_value = 8;
+ int minutes_test_value = 23;
+ std::string expected_value = "1WT8H23M";
+
+ auto duration = Duration(week_test_value, day_test_value, hours_test_value, minutes_test_value);
+ CHECK(duration.getDurationString() == expected_value);
+ }
+
+ SECTION("Test getDurationInMinutes() method")
+ {
+ int week_test_value = 2;
+ int day_test_value = 1;
+ int hours_test_value = 2;
+ int minutes_test_value = 30;
+ uint32_t time_in_minutes =
+ week_test_value * 7 * 24 * 60 + day_test_value * 24 * 60 + hours_test_value * 60 + minutes_test_value;
+
+ auto duration = Duration(week_test_value, day_test_value, hours_test_value, minutes_test_value);
+ CHECK(duration.getDurationInMinutes() == time_in_minutes);
+ }
+
+ SECTION("Test Duration(string) constructor")
+ {
+
+ std::string duration_value = "P1WT8H23M";
+ std::string expected_value = "1WT8H23M";
+ auto duration = Duration(duration_value);
+ CHECK(duration.getDurationString() == expected_value);
+
+ std::string duration_value2 = "-P1W1DT8H23M";
+ std::string expected_value2 = "1W1DT8H23M";
+ auto duration2 = Duration(duration_value2);
+ CHECK(duration2.getDurationString() == expected_value2);
+
+ std::string duration_value3 = "-PT8H23M";
+ std::string expected_value3 = "T8H23M";
+ auto duration3 = Duration(duration_value3);
+ CHECK(duration3.getDurationString() == expected_value3);
+
+ std::string duration_value4 = "PT8H23M";
+ std::string expected_value4 = "T8H23M";
+ auto duration4 = Duration(duration_value4);
+ CHECK(duration4.getDurationString() == expected_value4);
+ }
+
+ SECTION("Test Duration(string) constructor invalid")
+ {
+ std::string duration_value = "";
+ std::string expected_value = "T0M";
+ auto duration = Duration(duration_value);
+ CHECK(duration.getDurationString() == expected_value);
+
+ std::string duration_value1 = "DTSTART:20201020T1536";
+ std::string expected_value1 = "T0M";
+ auto duration1 = Duration(duration_value1);
+ CHECK(duration1.getDurationString() == expected_value1);
+ }
+}
+
+TEST_CASE("Testing Alarm class object", "")
+{
+
+ SECTION("Test regural trigger and action audio")
+ {
+ auto action = Action::audio;
+ auto duration = Duration(0, 0, 0, 5);
+ std::string expected_action_value = "AUDIO";
+ std::string expected_trigger_value = "-PT5M";
+
+ auto alarm = Alarm(duration, action);
+ CHECK(alarm.getActionString() == expected_action_value);
+ CHECK(alarm.getTriggerString() == expected_trigger_value);
+ }
+
+ SECTION("Test regural trigger and action audio")
+ {
+ auto action = Action::procedure;
+ auto duration = Duration(0, 0, 1, 0);
+ std::string expected_action_value = "PROCEDURE";
+ std::string expected_trigger_value = "-PT1H";
+
+ auto alarm = Alarm(duration, action);
+ CHECK(alarm.getActionString() == expected_action_value);
+ CHECK(alarm.getTriggerString() == expected_trigger_value);
+ }
+
+ SECTION("Test regural trigger and action display")
+ {
+ auto action = Action::display;
+ auto duration = Duration(0, 1, 1, 0);
+ std::string expected_action_value = "DISPLAY";
+ std::string expected_trigger_value = "-P1DT1H";
+
+ auto alarm = Alarm(duration, action);
+ CHECK(alarm.getActionString() == expected_action_value);
+ CHECK(alarm.getTriggerString() == expected_trigger_value);
+ }
+
+ SECTION("Test invalid trigger and action")
+ {
+ auto invalid_action = Action::invalid;
+ auto invalid_duration = Duration(0, 0, 0, 0);
+ std::string expected_action_value = "";
+ std::string expected_trigger_value = "-PT0M";
+
+ auto alarm = Alarm(invalid_duration, invalid_action);
+ CHECK(alarm.getActionString() == expected_action_value);
+ CHECK(alarm.getTriggerString() == expected_trigger_value);
+ }
+}
+
+TEST_CASE("Testing RecurrenceRule class object", "")
+{
+
+ SECTION("Test frequency daily, count 7 value")
+ {
+ auto freq = Frequency::daily;
+ auto rrule = RecurrenceRule(freq, 7, 1);
+ std::string expected_frequency_value = "DAILY";
+ std::string expected_count_value = "7";
+ std::string expected_interval_value = "1";
+ CHECK(rrule.getFrequencyString() == expected_frequency_value);
+ CHECK(rrule.getCountString() == expected_count_value);
+ CHECK(rrule.getIntervalString() == expected_interval_value);
+ }
+
+ SECTION("Test frequency weekly, count 4 value")
+ {
+ auto freq = Frequency::weekly;
+ auto rrule = RecurrenceRule(freq, 4, 1);
+ std::string expected_frequency_value = "WEEKLY";
+ std::string expected_count_value = "4";
+ std::string expected_interval_value = "1";
+ CHECK(rrule.getFrequencyString() == expected_frequency_value);
+ CHECK(rrule.getCountString() == expected_count_value);
+ CHECK(rrule.getIntervalString() == expected_interval_value);
+ }
+
+ SECTION("Test frequency biweekly, count 4 value")
+ {
+ auto freq = Frequency::weekly;
+ auto rrule = RecurrenceRule(freq, 4, 2);
+ std::string expected_frequency_value = "WEEKLY";
+ std::string expected_count_value = "4";
+ std::string expected_interval_value = "2";
+ CHECK(rrule.getFrequencyString() == expected_frequency_value);
+ CHECK(rrule.getCountString() == expected_count_value);
+ CHECK(rrule.getIntervalString() == expected_interval_value);
+ }
+
+ SECTION("Test frequency monthly, count 12 value")
+ {
+ auto freq = Frequency::monthly;
+ auto rrule = RecurrenceRule(freq, 12, 1);
+ std::string expected_frequency_value = "MONTHLY";
+ std::string expected_count_value = "12";
+ std::string expected_interval_value = "1";
+ CHECK(rrule.getFrequencyString() == expected_frequency_value);
+ CHECK(rrule.getCountString() == expected_count_value);
+ CHECK(rrule.getIntervalString() == expected_interval_value);
+ }
+
+ SECTION("Test frequency yearly, count 4 value")
+ {
+ auto freq = Frequency::yearly;
+ auto rrule = RecurrenceRule(freq, 4, 1);
+ std::string expected_frequency_value = "YEARLY";
+ std::string expected_count_value = "4";
+ std::string expected_interval_value = "1";
+ CHECK(rrule.getFrequencyString() == expected_frequency_value);
+ CHECK(rrule.getCountString() == expected_count_value);
+ CHECK(rrule.getIntervalString() == expected_interval_value);
+ }
+
+ SECTION("Test frequency invalid")
+ {
+ auto freq = Frequency::invalid;
+ auto rrule = RecurrenceRule(freq, 1, 1);
+ std::string expected_frequency_value = "";
+ std::string expected_count_value = "";
+ std::string expected_interval_value = "";
+ CHECK(rrule.getFrequencyString() == expected_frequency_value);
+ CHECK(rrule.getCountString() == expected_count_value);
+ CHECK(rrule.getIntervalString() == expected_interval_value);
+ }
+
+ SECTION("Test count invalid")
+ {
+ auto freq = Frequency::daily;
+ auto rrule = RecurrenceRule(freq, 1, 0);
+ std::string expected_frequency_value = "";
+ std::string expected_count_value = "";
+ std::string expected_interval_value = "";
+ CHECK(rrule.getFrequencyString() == expected_frequency_value);
+ CHECK(rrule.getCountString() == expected_count_value);
+ CHECK(rrule.getIntervalString() == expected_interval_value);
+ }
+
+ SECTION("Test interval invalid")
+ {
+ auto freq = Frequency::yearly;
+ auto rrule = RecurrenceRule(freq, 0, 1);
+ std::string expected_frequency_value = "";
+ std::string expected_count_value = "";
+ std::string expected_interval_value = "";
+ CHECK(rrule.getFrequencyString() == expected_frequency_value);
+ CHECK(rrule.getCountString() == expected_count_value);
+ CHECK(rrule.getIntervalString() == expected_interval_value);
+ }
+}
+
+TEST_CASE("Testing Event class object", "")
+{
+
+ SECTION("Test get DTStart and DTEnd in TimePoint value")
+ {
+ auto summary = "test";
+ auto DTstart = TimePointFromString("2020-11-05 15:00:00");
+ auto DTend = TimePointFromString("2020-11-05 16:00:00");
+
+ auto event = Event(summary, DTstart, DTend, "test_uid");
+
+ std::string expected_summary_value = "test";
+ std::string expected_DTstart_value = "20201105T150000";
+ std::string expected_DTend_value = "20201105T160000";
+ CHECK(event.getSummary() == expected_summary_value);
+ CHECK(event.getDTStartString() == expected_DTstart_value);
+ CHECK(event.getDTEndString() == expected_DTend_value);
+
+ auto dtstart_timepoint = event.getDTStartTimePoint();
+ auto dtend_timepoint = event.getDTEndTimePoint();
+ std::string expected_dtstart_string = "2020-11-05 15:00:00";
+ std::string expected_dtend_string = "2020-11-05 16:00:00";
+ CHECK(TimePointToString(dtstart_timepoint) == expected_dtstart_string);
+ CHECK(TimePointToString(dtend_timepoint) == expected_dtend_string);
+ }
+
+ SECTION("Test event with invalid timepoints values")
+ {
+ auto summary = "invalid";
+ auto DTstart = TimePointFromString("2020-11-05 15:00");
+ auto DTend = TimePointFromString("2020-11 16:00:00");
+
+ auto event = Event(summary, DTstart, DTend, "test_uid");
+
+ std::string expected_summary_value = "invalid";
+ std::string expected_DTstart_value = "19700101T000000";
+ std::string expected_DTend_value = "19700101T000000";
+ CHECK(event.getSummary() == expected_summary_value);
+ CHECK(event.getDTStartString() == expected_DTstart_value);
+ CHECK(event.getDTEndString() == expected_DTend_value);
+
+ auto dtstart_timepoint = event.getDTStartTimePoint();
+ auto dtend_timepoint = event.getDTEndTimePoint();
+ std::string expected_dtstart_string = "1970-01-01 00:00:00";
+ std::string expected_dtend_string = "1970-01-01 00:00:00";
+ CHECK(TimePointToString(dtstart_timepoint) == expected_dtstart_string);
+ CHECK(TimePointToString(dtend_timepoint) == expected_dtend_string);
+ }
+}
+
+TEST_CASE("Testing ParserICS class methods", "")
+{
+ SECTION("Test importEvents and exportEvents")
+ {
+ /// Event1
+ auto summary = "test";
+ auto DTstart = TimePointFromString("2020-11-05 15:00:00");
+ auto DTend = TimePointFromString("2020-11-05 16:00:00");
+ auto UID = createUID();
+ auto event = Event(summary, DTstart, DTend, UID);
+
+ auto freq = Frequency::weekly;
+ auto rrule = RecurrenceRule(freq, 4, 2);
+
+ auto action = Action::audio;
+ auto duration = Duration(0, 0, 0, 5);
+ auto alarm = Alarm(duration, action);
+ auto icalEvent1 = ICalEvent{event, alarm, rrule};
+
+ /// Event2
+ auto summary2 = "test2";
+ auto DTstart2 = TimePointFromString("2019-09-05 10:00:00");
+ auto DTend2 = TimePointFromString("2019-09-05 14:30:00");
+ auto UID2 = createUID();
+ auto event2 = Event(summary2, DTstart2, DTend2, UID2);
+
+ ICalEvent icalEvent2;
+ icalEvent2.event = event2;
+
+ /// Event3
+ auto summary3 = "test3";
+ auto DTstart3 = TimePointFromString("2021-01-01 00:00:00");
+ auto DTend3 = TimePointFromString("2021-01-01 10:45:00");
+ auto UID3 = createUID();
+ auto event3 = Event(summary3, DTstart3, DTend3, UID3);
+
+ auto freq3 = Frequency::daily;
+ auto rrule3 = RecurrenceRule(freq3, 7, 1);
+
+ ICalEvent icalEvent3;
+ icalEvent3.event = event3;
+ icalEvent3.rrule = rrule3;
+
+ /// check
+ auto IcalEventsINPUT = std::vector<ICalEvent>();
+ IcalEventsINPUT.push_back(icalEvent1);
+ IcalEventsINPUT.push_back(icalEvent2);
+ IcalEventsINPUT.push_back(icalEvent3);
+
+ auto parser = ParserICS();
+ parser.importEvents(IcalEventsINPUT);
+
+ [[maybe_unused]] auto icsFormat = parser.getIcsData();
+
+ std::string expected_uid[] = {UID, UID2, UID3};
+ std::string expected_summary[] = {summary, summary2, summary3};
+ std::string expected_DTstart[] = {"20201105T150000", "20190905T100000", "20210101T000000"};
+ std::string expected_DTend[] = {"20201105T160000", "20190905T143000", "20210101T104500"};
+
+ auto icalEventsOUTPUT = parser.exportEvents();
+
+ CHECK(icalEventsOUTPUT[0].event.getUID() == expected_uid[0]);
+ CHECK(icalEventsOUTPUT[0].event.getSummary() == expected_summary[0]);
+ CHECK(icalEventsOUTPUT[0].event.getDTStartString() == expected_DTstart[0]);
+ CHECK(icalEventsOUTPUT[0].event.getDTEndString() == expected_DTend[0]);
+
+ CHECK(icalEventsOUTPUT[1].event.getUID() == expected_uid[1]);
+ CHECK(icalEventsOUTPUT[1].event.getSummary() == expected_summary[1]);
+ CHECK(icalEventsOUTPUT[1].event.getDTStartString() == expected_DTstart[1]);
+ CHECK(icalEventsOUTPUT[1].event.getDTEndString() == expected_DTend[1]);
+
+ CHECK(icalEventsOUTPUT[2].event.getUID() == expected_uid[2]);
+ CHECK(icalEventsOUTPUT[2].event.getSummary() == expected_summary[2]);
+ CHECK(icalEventsOUTPUT[2].event.getDTStartString() == expected_DTstart[2]);
+ CHECK(icalEventsOUTPUT[2].event.getDTEndString() == expected_DTend[2]);
+
+ CHECK(icalEventsOUTPUT[0].rrule.getFrequencyString() == "WEEKLY");
+ CHECK(icalEventsOUTPUT[0].rrule.getCountString() == "4");
+ CHECK(icalEventsOUTPUT[0].rrule.getIntervalString() == "2");
+
+ CHECK(icalEventsOUTPUT[2].rrule.getFrequencyString() == "DAILY");
+ CHECK(icalEventsOUTPUT[2].rrule.getCountString() == "7");
+ CHECK(icalEventsOUTPUT[2].rrule.getIntervalString() == "1");
+
+ CHECK(icalEventsOUTPUT[0].alarm.getActionString() == "AUDIO");
+ CHECK(icalEventsOUTPUT[0].alarm.getTriggerString() == "-PT5M");
+ }
+
+ SECTION("Test importEvents and exportEvents invalid")
+ {
+ /// Event1
+ auto event = Event();
+
+ auto freq = Frequency::weekly;
+ auto rrule = RecurrenceRule(freq, 4, 2);
+
+ auto action = Action::audio;
+ auto duration = Duration(0, 0, 0, 5);
+ auto alarm = Alarm(duration, action);
+
+ auto icalEvent1 = ICalEvent{event, alarm, rrule};
+
+ /// Event2
+ auto summary2 = "test2";
+ auto DTstart2 = TimePointFromString("2019-09-05 10:00:00");
+ auto DTend2 = TimePointFromString("2019-09-05 14:30:00");
+ auto UID2 = createUID();
+ auto event2 = Event(summary2, DTstart2, DTend2, UID2);
+ auto alarm2 = Alarm();
+ auto rrule2 = RecurrenceRule();
+ auto icalEvent2 = ICalEvent{event2, alarm2, rrule2};
+
+ /// check
+ auto IcalEventsINPUT = std::vector<ICalEvent>();
+ IcalEventsINPUT.push_back(icalEvent1);
+ IcalEventsINPUT.push_back(icalEvent2);
+
+ auto parser = ParserICS();
+ parser.importEvents(std::move(IcalEventsINPUT));
+
+ [[maybe_unused]] auto icsFormat = parser.getIcsData();
+
+ std::string expected_uid = UID2;
+ std::string expected_summary = summary2;
+ std::string expected_DTstart = "20190905T100000";
+ std::string expected_DTend = "20190905T143000";
+
+ auto icalEventsOUTPUT = parser.exportEvents();
+
+ CHECK(icalEventsOUTPUT[0].event.getUID() == expected_uid);
+ CHECK(icalEventsOUTPUT[0].event.getSummary() == expected_summary);
+ CHECK(icalEventsOUTPUT[0].event.getDTStartString() == expected_DTstart);
+ CHECK(icalEventsOUTPUT[0].event.getDTEndString() == expected_DTend);
+
+ CHECK(icalEventsOUTPUT[0].rrule.getFrequencyString() == "");
+ CHECK(icalEventsOUTPUT[0].rrule.getCountString() == "");
+ CHECK(icalEventsOUTPUT[0].rrule.getIntervalString() == "");
+
+ CHECK(icalEventsOUTPUT[0].alarm.getActionString() == "");
+ CHECK(icalEventsOUTPUT[0].alarm.getTriggerString() == "-PT0M");
+ }
+}
A test/service-desktop-test/defs.py => test/service-desktop-test/defs.py +27 -0
@@ 0,0 1,27 @@
+# Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+# For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+endpoint = {
+ "deviceInfo": 1,
+ "update": 2,
+ "backup": 3,
+ "restore": 4,
+ "factory": 5,
+ "contacts": 6,
+ "messages": 7,
+ "calllog": 8,
+ "events": 10
+}
+
+method = {
+ "get": 1,
+ "post": 2,
+ "put": 3,
+ "del": 4
+}
+
+status = {
+ "OK": 200,
+ "BadRequest": 400,
+ "InternalServerError": 500
+}
M test/service-desktop-test/main.py => test/service-desktop-test/main.py +2 -1
@@ 9,6 9,7 @@ from tests.deviceinfo import *
from tests.factoryReset import *
from tests.backup import *
from tests.calllog import *
+from tests.calendarEvents import *
from termcolor import colored
from harness.harness import Harness
@@ 23,7 24,7 @@ def main():
serial = test_harness.get_connection()
final_result = True
failed_tests = []
- for test_instance in (DeviceInfoTest(serial), UpdateTest(serial), BackupTest(serial), MessageTest(serial),
+ for test_instance in (DeviceInfoTest(serial), calendarEventsTest(serial), UpdateTest(serial), BackupTest(serial), MessageTest(serial),
MessageTemplateTest(serial), ContactTest(serial), CalllogTest(serial),
FactoryResetTest(serial)):
test_name = type(test_instance).__name__
A test/service-desktop-test/tests/calendarEvents.py => test/service-desktop-test/tests/calendarEvents.py +101 -0
@@ 0,0 1,101 @@
+# Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+# For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+from harness.interface.defs import endpoint, method, status
+
+from test_api import *
+from defs import *
+
+
+class calendarEventsTest:
+ def __init__(self, serial):
+ self.serial = serial.get_serial()
+
+ def run(self):
+ # add event
+ event = "BEGIN:VCALENDAR\nBEGIN:VEVENT\nSUMMARY:Testowy\nDTSTART:20200929T123611\nDTEND:20200929T124611\nBEGIN:VALARM\nTRIGGER:-P5M\nEND:VALARM\nEND:VEVENT\nEND:VCALENDAR\n"
+
+ msg, result_msg = prepare_message(endpoint["events"], method["put"], status["OK"],
+ {"data": event}, None)
+ test = Test(self.serial, msg, result_msg)
+ ret, result = test.execute()
+ if ret == False:
+ return False
+
+ #get all limited events
+ msg, result_msg = prepare_message(endpoint["events"], method["get"], status["OK"],
+ {"offset": 0,
+ "limit": 1},
+ {"data":event,
+ "count": "1"})
+
+ test = Test(self.serial, msg, result_msg)
+ ret, result = test.execute()
+ print(result)
+ uid_index = result["data"].index('UID:')
+ summary_index = result["data"].index('SUMMARY:')
+ UID = result["data"][uid_index+4:summary_index]
+ print(UID)
+
+ if not "SUMMARY:Testowy" in result["data"]:
+ return False
+
+ if not "DTSTART:20200929T123611" in result["data"]:
+ return False
+
+ if not "DTEND:20200929T124611" in result["data"]:
+ return False
+
+ if result["count"] != "1":
+ return False
+
+ eventUpdate = "BEGIN:VCALENDAR\nBEGIN:VEVENT\nUID:"+UID+"\n"+"SUMMARY:Update\nDTSTART:20200928T123611\nDTEND:20200928T124611\nEND:VEVENT\nEND:VCALENDAR\n"
+ print(eventUpdate)
+ # # update event
+ msg, result_msg = prepare_message(endpoint["events"], method["post"], status["OK"],
+ {"data":eventUpdate}, None)
+ test = Test(self.serial, msg, result_msg)
+ ret, result = test.execute()
+ if ret == False:
+ return False
+
+ # check updated event
+ msg, result_msg = prepare_message(endpoint["events"], method["get"], status["OK"],
+ {"offset": 0,
+ "limit": 1},
+ {"data":eventUpdate,
+ "count": "1"})
+ test = Test(self.serial, msg, result_msg)
+ ret, result = test.execute()
+ print(result)
+
+ if not "SUMMARY:Update" in result["data"]:
+ return False
+
+ if not "DTSTART:20200928T123611" in result["data"]:
+ return False
+
+ if not "DTEND:20200928T124611" in result["data"]:
+ return False
+
+ if result["count"] != "1":
+ return False
+
+ #remove event
+ msg, result_msg = prepare_message(endpoint["events"], method["del"], status["OK"],
+ {"UID": UID}, None)
+ test = Test(self.serial, msg, result_msg)
+ ret, result = test.execute()
+ if ret == False:
+ return False
+
+ # check events after remove
+ msg, result_msg = prepare_message(endpoint["events"], method["get"], status["OK"],None,
+ {"data":"",
+ "count": "1"})
+ test = Test(self.serial, msg, result_msg)
+ ret, result = test.execute()
+ if ret == False:
+ return False
+
+ return True