From 3baa85363dbf71d09daaff7ad781f7b5873b4620 Mon Sep 17 00:00:00 2001 From: Alek Rudnik <54846206+alekrudnik@users.noreply.github.com> Date: Fri, 10 Jul 2020 11:57:19 +0200 Subject: [PATCH] Egd 2835 sms unread vs unseen notifications (#514) * [EGD-2835] thread table based sms not read notifications * [EGD-2835] removed redundant read field from sms db table * [EGD-2835] clear unread status of a thread if thre thread is open * [EGD-2835] updated database documentation * [EGD-2835] added changelog --- changelog.md | 1 + doc/database_v2.md | 18 +++- image/user/sms.db | Bin 24576 -> 24576 bytes .../ApplicationDesktop.cpp | 5 +- .../widgets/ThreadItem.cpp | 2 +- .../windows/ThreadViewWindow.cpp | 11 +- module-db/Common/Common.hpp | 12 +-- module-db/Interface/SMSRecord.cpp | 15 +-- module-db/Interface/SMSRecord.hpp | 6 +- module-db/Interface/ThreadRecord.cpp | 36 ++++--- module-db/Interface/ThreadRecord.hpp | 34 ++++--- module-db/Tables/SMSTable.cpp | 37 ++----- module-db/Tables/SMSTable.hpp | 3 - module-db/Tables/ThreadsTable.cpp | 45 ++++++--- module-db/Tables/ThreadsTable.hpp | 17 ++-- module-db/tests/SMSRecord_tests.cpp | 9 -- module-db/tests/SMSTable_tests.cpp | 1 - module-db/tests/ThreadRecord_tests.cpp | 95 +++++++++++------- module-db/tests/ThreadsTable_tests.cpp | 18 ++-- module-services/service-db/ServiceDB.cpp | 9 +- .../service-db/api/DBServiceAPI.cpp | 8 +- .../service-db/api/DBServiceAPI.hpp | 4 +- .../service-db/messages/DBSMSMessage.cpp | 2 +- .../service-db/messages/DBSMSMessage.hpp | 3 +- .../service-db/messages/DBThreadMessage.cpp | 4 + .../service-db/messages/DBThreadMessage.hpp | 7 ++ 26 files changed, 219 insertions(+), 183 deletions(-) diff --git a/changelog.md b/changelog.md index 89346f91a..d6f1f5033 100644 --- a/changelog.md +++ b/changelog.md @@ -13,6 +13,7 @@ * `[gui]` Selector for newline in special character selection * `[phonebook]` New implementation of Add/Edit Contact window * `[messages]` Options have contact in bold +* `[messages]``[home screen]` Splited unread from unseen new sms notifications. ### Changed * `[phonebook]` Improved contact searching. diff --git a/doc/database_v2.md b/doc/database_v2.md index 19e9231f8..be1002190 100644 --- a/doc/database_v2.md +++ b/doc/database_v2.md @@ -147,7 +147,6 @@ Name: sms | date_sent | (m) | INTEGER | Date when message was sent to recipients | | error_code | (m) | INTEGER | ID of the error code for this message | | body | (m) | TEXT | Text of the message that was provided by the user. This is UTF8 encoded text. | -| read | (m) | INTEGER | Boolean value that defines whether message was seen by the user | | type | (m) | INTEGER | Defines what is the type of the message | Possible values of the type field @@ -308,6 +307,23 @@ Name: calllog. | CT_BLOCKED | 0x06 | Call log type for calls blocked automatically. | | CT_ANSW_EXT | 0x07 | Call log type for a call which was answered on another device. Used in situations where a call rings on multiple devices simultaneously and it ended up being answered on a device other than the current one. | +#### 14. Table with information about notifications +Name: notifications. + +| Field | Scope | Type | Description | +| -------- | ----------- | ------- | -------------------| +| _id | (um) | INTEGER PRIMARY KEY | Unique ID. | +| key | (m) | INTEGER | unique notification key identifier | +| value | (m) | INTEGER | number of notifcations | + +**key** field + +| Name | Value | Description | +| ---- | ----- | ----------- | +| NotValidKey | 0x00 | Not valid key | +| Calls | 0x01 | Missed calls notifications | +| Sms | 0x02 | Unread incoming sms notifications | + ## Database Triggers This trigger is responsible for taking action when new thread is created and inserted to threads table. As a result value of the count column with _id equal to 1 in the threads_count table is incremented by 1. diff --git a/image/user/sms.db b/image/user/sms.db index cad3f617661d5f6ece591a742910be929506dc3e..3ae01e3215f9f5d03cfe000e6fb8441aac22f5b0 100644 GIT binary patch delta 721 zcmZ9I&1(}u7>9QzlaJYCHrTjSkS60+C6Q2~9wZ`^HJ#RI+?4Gq7KO0QE=@ppOR^%l zm?nznmIZG@^=c7H4qkil>b;2K#e;u<2dSWw4;Is5-^2UN^Zs~uwhzJfA=o*4svrnL zgcsxmcuBkYtFr}RVeyDa#{x>s3({@!jZ_o!@!to%7x5YC7~JRHuvyVY`AwYqCf+Z(RcQLw=t7*wkoHSJ!dGFqXtHRUZ=byi-{ z=pDA6{cpb<)!8!BnO0(Jbi&(8R#_NsnWI&WF0l&Zzg$w+O6n5h(W`p-uBxw(lSZ1D z8&t_YK>WeO1F-rxd9VY)J6cc(e^f&Dgyd23ee$*RQ~Dsil5)}v`9pq?&*UT78=Rxh zNmnLV004oQ3?h+7H@Bmkq?hr3&FNPzMzDY}0-y+nQV2Rt`>AC*HhtD-8x%7FY3_+S#^U-6diFPYfjkyoe+Itad|tfwc>Q_SY-Z%w z;t^nU07}3CqtV31Nxbvnd>~`9Kkphw)g~rJc5z{0#^&sj#H5_m;@n~&VsZ|0bqsM; z2yt}saaAbJom|Z)#Zi(`l$w|lpE-FupKN_fVo9okr(cMxyK9gRh!bC&nwJ6>Ni8bM zFN#mjPeCY3%1^0O2yu-FQSkE*iT4Zj@zDX92iHF%fC?HZ{8vo}Rk zA;{IuHOSS^+0`Xj0U}(i5uXW^@b^=2arJQpI@#GV*xAv=RY8-NcM$_GZxjb#8J|0U zJ>LcXg?!6-U-G};J;u9^w~M!kHwqX|7QFRhyj%>7j4X^Cq8yBDY%w;sA21bU=B0Cp z@gT%mS>fVLV%!LE78bZT3-4V99$4^-aUs+&Gegwm=cTiVa)QMWAfLyg?juV zOi(4lAT#UdGBK4`7IW}FK{(5b6{;ehbMlTjLuHs(fr(Fy1Lj*!MkXeZZ&@-@GwfLw LDHtqf diff --git a/module-apps/application-desktop/ApplicationDesktop.cpp b/module-apps/application-desktop/ApplicationDesktop.cpp index 0fff93056..33e40afc4 100644 --- a/module-apps/application-desktop/ApplicationDesktop.cpp +++ b/module-apps/application-desktop/ApplicationDesktop.cpp @@ -99,7 +99,8 @@ namespace app return requestNotSeenNotifications(); } - if ((msg->interface == db::Interface::Name::Calllog || msg->interface == db::Interface::Name::SMSThread) && + if ((msg->interface == db::Interface::Name::Calllog || msg->interface == db::Interface::Name::SMSThread || + msg->interface == db::Interface::Name::SMS) && msg->type != db::Query::Type::Read) { requestNotReadNotifications(); windows[app::window::name::desktop_menu]->rebuild(); @@ -167,7 +168,7 @@ namespace app bool ApplicationDesktop::requestNotReadNotifications() { notifications.notRead.Calls = DBServiceAPI::CalllogGetCount(this, EntryState::UNREAD); - notifications.notRead.SMS = DBServiceAPI::SMSGetCount(this, EntryState::UNREAD); + notifications.notRead.SMS = DBServiceAPI::ThreadGetCount(this, EntryState::UNREAD); return true; } diff --git a/module-apps/application-messages/widgets/ThreadItem.cpp b/module-apps/application-messages/widgets/ThreadItem.cpp index 494c80ef3..5f6aad55c 100644 --- a/module-apps/application-messages/widgets/ThreadItem.cpp +++ b/module-apps/application-messages/widgets/ThreadItem.cpp @@ -11,7 +11,7 @@ namespace gui ThreadItem *ThreadItem::makeThreadItem(ThreadModel *model, std::shared_ptr thread) { ThreadItem *threadItem = nullptr; - threadItem = thread->msgRead > 0 ? new ThreadItemNotRead(model) : new ThreadItem(model); + threadItem = thread->isUnread() ? new ThreadItemNotRead(model) : new ThreadItem(model); threadItem->setThreadItem(thread); diff --git a/module-apps/application-messages/windows/ThreadViewWindow.cpp b/module-apps/application-messages/windows/ThreadViewWindow.cpp index 828956fd9..76fbfa163 100644 --- a/module-apps/application-messages/windows/ThreadViewWindow.cpp +++ b/module-apps/application-messages/windows/ThreadViewWindow.cpp @@ -147,6 +147,11 @@ namespace gui } SMS.dbsize = threadDetails->msgCount; + if (threadDetails != nullptr && threadDetails->isUnread()) { + threadDetails->unreadMsgCount = 0; + DBServiceAPI::ThreadUpdate(application, *threadDetails); + } + LOG_DEBUG("start: %d end: %d db: %d", SMS.start, SMS.end, SMS.dbsize); if (what == Action::Init || what == Action::NewestPage) { if (what == Action::NewestPage) { @@ -398,12 +403,6 @@ namespace gui LOG_INFO("received sms templates data \"%s\"", txt.c_str()); text->setText(text->getText() + txt); } - - std::unique_ptr threadDetails = DBServiceAPI::ThreadGet(this->application, SMS.thread); - if (threadDetails != nullptr && threadDetails->msgRead > 0) { - threadDetails->msgRead = 0; - DBServiceAPI::ThreadUpdate(application, *threadDetails); - } } bool ThreadViewWindow::onInput(const InputEvent &inputEvent) diff --git a/module-db/Common/Common.hpp b/module-db/Common/Common.hpp index 674118116..5488a6bba 100644 --- a/module-db/Common/Common.hpp +++ b/module-db/Common/Common.hpp @@ -14,12 +14,12 @@ */ enum class SMSType { - DRAFT = 0x01, - FAILED = 0x02, - INBOX = 0x04, - OUTBOX = 0x08, - QUEUED = 0x10, - ALL = 0xFF + DRAFT = 0x01, + FAILED = 0x02, + INBOX = 0x04, + OUTBOX = 0x08, + QUEUED = 0x10, + UNKNOWN = 0xFF }; enum class EntryState diff --git a/module-db/Interface/SMSRecord.cpp b/module-db/Interface/SMSRecord.cpp index 29dbb9d55..a649994ee 100644 --- a/module-db/Interface/SMSRecord.cpp +++ b/module-db/Interface/SMSRecord.cpp @@ -24,7 +24,6 @@ SMSRecord::SMSRecord(const SMSTableRow &w, const utils::PhoneNumber::View &num) errorCode = w.errorCode; number = num; body = w.body; - isRead = w.isRead; type = w.type; threadID = w.threadID; contactID = w.contactID; @@ -33,9 +32,6 @@ SMSRecord::SMSRecord(const SMSTableRow &w, const utils::PhoneNumber::View &num) SMSRecordInterface::SMSRecordInterface(SmsDB *smsDb, ContactsDB *contactsDb) : smsDB(smsDb), contactsDB(contactsDb) {} -SMSRecordInterface::~SMSRecordInterface() -{} - bool SMSRecordInterface::Add(const SMSRecord &rec) { ContactRecordInterface contactInterface(contactsDB); @@ -70,7 +66,6 @@ bool SMSRecordInterface::Add(const SMSRecord &rec) .dateSent = rec.dateSent, .errorCode = rec.errorCode, .body = rec.body, - .isRead = rec.isRead, .type = rec.type }); @@ -84,21 +79,16 @@ bool SMSRecordInterface::Add(const SMSRecord &rec) thread.type = rec.type; thread.msgCount++; if (rec.type == SMSType::INBOX) { - thread.msgRead++; + thread.unreadMsgCount++; } threadInterface.Update(thread); return true; } -uint32_t SMSRecordInterface::GetCount(EntryState state) -{ - return smsDB->sms.GetCount(state); -} - uint32_t SMSRecordInterface::GetCount() { - return GetCount(EntryState::ALL); + return smsDB->sms.GetCount(); } uint32_t SMSRecordInterface::GetLastID(void) @@ -173,7 +163,6 @@ bool SMSRecordInterface::Update(const SMSRecord &rec) .dateSent = rec.dateSent, .errorCode = rec.errorCode, .body = rec.body, - .isRead = rec.isRead, .type = rec.type}); return true; diff --git a/module-db/Interface/SMSRecord.hpp b/module-db/Interface/SMSRecord.hpp index 695d939e5..735a5f113 100644 --- a/module-db/Interface/SMSRecord.hpp +++ b/module-db/Interface/SMSRecord.hpp @@ -24,8 +24,7 @@ struct SMSRecord : public Record uint32_t dateSent = 0; uint32_t errorCode = 0; UTF8 body = ""; - bool isRead = false; - SMSType type = SMSType::ALL; + SMSType type = SMSType::UNKNOWN; uint32_t threadID = 0; uint32_t contactID = 0; utils::PhoneNumber::View number; @@ -45,7 +44,7 @@ class SMSRecordInterface : public RecordInterface { public: SMSRecordInterface(SmsDB *smsDb, ContactsDB *contactsDb); - ~SMSRecordInterface(); + ~SMSRecordInterface() = default; bool Add(const SMSRecord &rec) override final; bool RemoveByID(uint32_t id) override final; @@ -54,7 +53,6 @@ class SMSRecordInterface : public RecordInterface SMSRecord GetByID(uint32_t id) override final; uint32_t GetCount() override final; - uint32_t GetCount(EntryState state); uint32_t GetLastID(void); std::unique_ptr> GetLimitOffset(uint32_t offset, uint32_t limit) override final; diff --git a/module-db/Interface/ThreadRecord.cpp b/module-db/Interface/ThreadRecord.cpp index 8764309a1..1303feda8 100644 --- a/module-db/Interface/ThreadRecord.cpp +++ b/module-db/Interface/ThreadRecord.cpp @@ -23,14 +23,12 @@ ThreadRecordInterface::~ThreadRecordInterface() bool ThreadRecordInterface::Add(const ThreadRecord &rec) { - auto ret = smsDB->threads.Add(ThreadsTableRow{.date = rec.date, - .msgCount = rec.msgCount, - .msgRead = rec.msgRead, - .contactID = rec.contactID, - .snippet = rec.snippet, - .type = rec.type - - }); + auto ret = smsDB->threads.Add(ThreadsTableRow{.date = rec.date, + .msgCount = rec.msgCount, + .unreadMsgCount = rec.unreadMsgCount, + .contactID = rec.contactID, + .snippet = rec.snippet, + .type = rec.type}); return ret; } @@ -49,23 +47,29 @@ bool ThreadRecordInterface::RemoveByID(uint32_t id) bool ThreadRecordInterface::Update(const ThreadRecord &rec) { - return smsDB->threads.Update(ThreadsTableRow{.ID = rec.ID, - .date = rec.date, - .msgCount = rec.msgCount, - .msgRead = rec.msgRead, - .contactID = rec.contactID, - .snippet = rec.snippet, - .type = rec.type + return smsDB->threads.Update(ThreadsTableRow{.ID = rec.ID, + .date = rec.date, + .msgCount = rec.msgCount, + .unreadMsgCount = rec.unreadMsgCount, + .contactID = rec.contactID, + .snippet = rec.snippet, + .type = rec.type }); } uint32_t ThreadRecordInterface::GetCount() { - return smsDB->threads.GetCount(); } +uint32_t ThreadRecordInterface::GetCount(EntryState state) +{ + return smsDB->threads.GetCount(state); +} + +bool markAsRead(); + std::unique_ptr> ThreadRecordInterface::GetLimitOffset(uint32_t offset, uint32_t limit) { auto records = std::make_unique>(); diff --git a/module-db/Interface/ThreadRecord.hpp b/module-db/Interface/ThreadRecord.hpp index c02504096..5de3a9cdc 100644 --- a/module-db/Interface/ThreadRecord.hpp +++ b/module-db/Interface/ThreadRecord.hpp @@ -19,23 +19,28 @@ struct ThreadRecord : Record { - uint32_t date = 0; - uint32_t msgCount = 0; - uint32_t msgRead = 0; - UTF8 snippet = ""; - SMSType type = SMSType::ALL; - uint32_t contactID = 0; + uint32_t date = 0; + uint32_t msgCount = 0; + uint32_t unreadMsgCount = 0; + UTF8 snippet = ""; + SMSType type = SMSType::UNKNOWN; + uint32_t contactID = DB_ID_NONE; ThreadRecord() = default; ThreadRecord(const ThreadsTableRow &rec) { - ID = rec.ID; - date = rec.date; - msgCount = rec.msgCount; - msgRead = rec.msgRead; - snippet = rec.snippet; - type = rec.type; - contactID = rec.contactID; + ID = rec.ID; + date = rec.date; + msgCount = rec.msgCount; + unreadMsgCount = rec.unreadMsgCount; + snippet = rec.snippet; + type = rec.type; + contactID = rec.contactID; + } + + bool isUnread() const + { + return unreadMsgCount > 0; } }; @@ -57,6 +62,9 @@ class ThreadRecordInterface : public RecordInterface> GetLimitOffset(uint32_t offset, uint32_t limit) override final; diff --git a/module-db/Tables/SMSTable.cpp b/module-db/Tables/SMSTable.cpp index 13b12c876..7d5beb681 100644 --- a/module-db/Tables/SMSTable.cpp +++ b/module-db/Tables/SMSTable.cpp @@ -24,14 +24,13 @@ bool SMSTable::Create() bool SMSTable::Add(SMSTableRow entry) { - return db->Execute("INSERT or ignore INTO sms ( thread_id,contact_id, date, date_send, error_code, body, read, " - "type ) VALUES (%lu,%lu,%lu,%lu,0,'%q',%d,%d);", + return db->Execute("INSERT or ignore INTO sms ( thread_id,contact_id, date, date_send, error_code, body, " + "type ) VALUES (%lu,%lu,%lu,%lu,0,'%q',%d);", entry.threadID, entry.contactID, entry.date, entry.dateSent, entry.body.c_str(), - entry.isRead, entry.type); } @@ -66,13 +65,12 @@ bool SMSTable::RemoveByField(SMSTableFields field, const char *str) bool SMSTable::Update(SMSTableRow entry) { return db->Execute("UPDATE sms SET thread_id = %lu, contact_id = %lu ,date = %lu, date_send = %lu, error_code = 0, " - "body = '%q', read = %d, type =%d WHERE _id=%lu;", + "body = '%q', type =%d WHERE _id=%lu;", entry.threadID, entry.contactID, entry.date, entry.dateSent, entry.body.c_str(), - entry.isRead, entry.type, entry.ID); } @@ -93,8 +91,7 @@ SMSTableRow SMSTable::GetByID(uint32_t id) (*retQuery)[4].GetUInt32(), // dateSent (*retQuery)[5].GetUInt32(), // errorCode (*retQuery)[6].GetString(), // body - (*retQuery)[7].GetBool(), // isRead - static_cast((*retQuery)[8].GetUInt32()), // type + static_cast((*retQuery)[7].GetUInt32()), // type }; } @@ -117,8 +114,7 @@ std::vector SMSTable::GetLimitOffset(uint32_t offset, uint32_t limi (*retQuery)[4].GetUInt32(), // dateSent (*retQuery)[5].GetUInt32(), // errorCode (*retQuery)[6].GetString(), // body - (*retQuery)[7].GetBool(), // isRead - static_cast((*retQuery)[8].GetUInt32()), // type + static_cast((*retQuery)[7].GetUInt32()), // type }); } while (retQuery->NextRow()); @@ -167,27 +163,15 @@ std::vector SMSTable::GetLimitOffsetByField(uint32_t offset, (*retQuery)[4].GetUInt32(), // dateSent (*retQuery)[5].GetUInt32(), // errorCode (*retQuery)[6].GetString(), // body - (*retQuery)[7].GetBool(), // isRead - static_cast((*retQuery)[8].GetUInt32()), // type + static_cast((*retQuery)[7].GetUInt32()), // type }); } while (retQuery->NextRow()); return ret; } -uint32_t SMSTable::GetCount(EntryState state) +uint32_t SMSTable::GetCount() { - std::string query = "SELECT COUNT(*) FROM sms "; - switch (state) { - case EntryState::ALL: - break; - case EntryState::READ: - query += "WHERE sms.read=1"; - break; - case EntryState::UNREAD: - query += "WHERE sms.read=0"; - break; - }; - query += ";"; + std::string query = "SELECT COUNT(*) FROM sms;"; auto queryRet = db->Query(query.c_str()); if (queryRet == nullptr || queryRet->GetRowCount() == 0) { @@ -197,11 +181,6 @@ uint32_t SMSTable::GetCount(EntryState state) return uint32_t{(*queryRet)[0].GetUInt32()}; } -uint32_t SMSTable::GetCount() -{ - return GetCount(EntryState::ALL); -} - uint32_t SMSTable::GetCountByFieldID(const char *field, uint32_t id) { auto queryRet = db->Query("SELECT COUNT(*) FROM sms WHERE %q=%lu;", field, id); diff --git a/module-db/Tables/SMSTable.hpp b/module-db/Tables/SMSTable.hpp index 721bcc6f6..eec52db4d 100644 --- a/module-db/Tables/SMSTable.hpp +++ b/module-db/Tables/SMSTable.hpp @@ -24,7 +24,6 @@ struct SMSTableRow uint32_t dateSent; uint32_t errorCode; UTF8 body; - bool isRead; SMSType type; }; @@ -54,7 +53,6 @@ class SMSTable : public Table const char *str) override final; uint32_t GetCount() override final; - uint32_t GetCount(EntryState state); uint32_t GetCountByFieldID(const char *field, uint32_t id) override final; private: @@ -66,7 +64,6 @@ class SMSTable : public Table "date_send INTEGER," "error_code INTEGER," "body TEXT NOT_NULL," - "read INTEGER," "type INTEGER," "FOREIGN KEY(thread_id) REFERENCES threads(_id) ON DELETE CASCADE );"; }; diff --git a/module-db/Tables/ThreadsTable.cpp b/module-db/Tables/ThreadsTable.cpp index bf3b7c437..4d0facc4a 100644 --- a/module-db/Tables/ThreadsTable.cpp +++ b/module-db/Tables/ThreadsTable.cpp @@ -38,8 +38,10 @@ bool ThreadsTable::Add(ThreadsTableRow entry) { return db->Execute("INSERT or ignore INTO threads ( date, msg_count, read, contact_id, snippet, last_dir ) VALUES " - "( %lu, 0, 0, %lu, '%q', %lu );", + "( %lu, %lu, %lu, %lu, '%q', %lu );", entry.date, + entry.msgCount, + entry.unreadMsgCount, entry.contactID, entry.snippet.c_str(), entry.type); @@ -56,7 +58,7 @@ bool ThreadsTable::Update(ThreadsTableRow entry) "last_dir = %lu WHERE _id=%lu;", entry.date, entry.msgCount, - entry.msgRead, + entry.unreadMsgCount, entry.contactID, entry.snippet.c_str(), entry.type, @@ -75,7 +77,7 @@ ThreadsTableRow ThreadsTable::GetByID(uint32_t id) (*retQuery)[0].GetUInt32(), // ID (*retQuery)[1].GetUInt32(), // date (*retQuery)[2].GetUInt32(), // msgCount - (*retQuery)[3].GetUInt32(), // msgRead + (*retQuery)[3].GetUInt32(), // unreadMsgCount (*retQuery)[4].GetUInt32(), // contactID (*retQuery)[5].GetString(), // snippet static_cast((*retQuery)[6].GetUInt32()), // type/last-dir @@ -89,7 +91,7 @@ void fillRetQuery(std::vector &ret, const std::unique_ptr((*retQuery)[6].GetUInt32()), // type/last-dir @@ -154,9 +156,26 @@ std::vector ThreadsTable::GetLimitOffsetByField(uint32_t offset uint32_t ThreadsTable::GetCount() { - auto queryRet = db->Query("SELECT COUNT(*) FROM threads;"); + return GetCount(EntryState::ALL); +} - if (queryRet->GetRowCount() == 0) { +uint32_t ThreadsTable::GetCount(EntryState state) +{ + std::string query = "SELECT COUNT(*) FROM threads "; + switch (state) { + case EntryState::ALL: + break; + case EntryState::READ: + query += "WHERE threads.read=0"; + break; + case EntryState::UNREAD: + query += "WHERE threads.read>0"; + break; + }; + query += ";"; + + auto queryRet = db->Query(query.c_str()); + if (queryRet == nullptr || queryRet->GetRowCount() == 0) { return 0; } @@ -189,13 +208,13 @@ std::pair> ThreadsTable::getBySMSQuery(st offset); do { ret.second.push_back(ThreadsTableRow{ - .ID = (*retQuery)[0].GetUInt32(), - .date = (*retQuery)[3].GetUInt32(), - .msgCount = 0, - .msgRead = (*retQuery)[7].GetUInt32(), - .contactID = (*retQuery)[2].GetUInt32(), - .snippet = (*retQuery)[6].GetString(), - .type = static_cast((*retQuery)[8].GetUInt32()), + .ID = (*retQuery)[0].GetUInt32(), + .date = (*retQuery)[3].GetUInt32(), + .msgCount = 0, + .unreadMsgCount = (*retQuery)[7].GetUInt32(), + .contactID = (*retQuery)[2].GetUInt32(), + .snippet = (*retQuery)[6].GetString(), + .type = static_cast((*retQuery)[8].GetUInt32()), }); } while (retQuery->NextRow()); } diff --git a/module-db/Tables/ThreadsTable.hpp b/module-db/Tables/ThreadsTable.hpp index ca1101552..bafc892e1 100644 --- a/module-db/Tables/ThreadsTable.hpp +++ b/module-db/Tables/ThreadsTable.hpp @@ -11,19 +11,21 @@ #pragma once #include "Table.hpp" +#include "Record.hpp" #include "Database/Database.hpp" -#include "utf8/UTF8.hpp" #include "Common/Common.hpp" +#include + struct ThreadsTableRow { - uint32_t ID = 0; - uint32_t date; - uint32_t msgCount; - uint32_t msgRead; - uint32_t contactID; + uint32_t ID = DB_ID_NONE; + uint32_t date = 0; + uint32_t msgCount = 0; + uint32_t unreadMsgCount = 0; + uint32_t contactID = DB_ID_NONE; UTF8 snippet; - SMSType type; + SMSType type = SMSType::UNKNOWN; }; enum class ThreadsTableFields @@ -53,6 +55,7 @@ class ThreadsTable : public Table const char *str) override final; uint32_t GetCount() override final; + uint32_t GetCount(EntryState state); uint32_t GetCountByFieldID(const char *field, uint32_t id) override final; ThreadsTableRow getByContact(uint32_t contact_id); diff --git a/module-db/tests/SMSRecord_tests.cpp b/module-db/tests/SMSRecord_tests.cpp index d7d1ca943..30e627c13 100644 --- a/module-db/tests/SMSRecord_tests.cpp +++ b/module-db/tests/SMSRecord_tests.cpp @@ -40,7 +40,6 @@ TEST_CASE("SMS Record tests") auto numberTest2 = utils::PhoneNumber("222333444", utils::country::Id::UNKNOWN).getView(); const char *bodyTest = "Test SMS Body"; const char *bodyTest2 = "Test SMS Body2"; - const bool isReadTest = true; const SMSType typeTest = SMSType ::DRAFT; SMSRecordInterface smsRecInterface(smsDB.get(), contactsDB.get()); @@ -51,7 +50,6 @@ TEST_CASE("SMS Record tests") recordIN.errorCode = errorCodeTest; recordIN.number = numberTest; recordIN.body = bodyTest; - recordIN.isRead = isReadTest; recordIN.type = typeTest; // Add 2 records @@ -66,7 +64,6 @@ TEST_CASE("SMS Record tests") for (const auto &w : *records) { REQUIRE(w.body == bodyTest); REQUIRE(w.number == numberTest); - REQUIRE(w.isRead == isReadTest); } // Get all available records by specified thread ID and check for invalid data @@ -75,7 +72,6 @@ TEST_CASE("SMS Record tests") for (const auto &w : *records) { REQUIRE(w.body == bodyTest); REQUIRE(w.number == numberTest); - REQUIRE(w.isRead == isReadTest); } // Get all available records by specified contact ID and check for invalid data @@ -84,7 +80,6 @@ TEST_CASE("SMS Record tests") for (const auto &w : *records) { REQUIRE(w.body == bodyTest); REQUIRE(w.number == numberTest); - REQUIRE(w.isRead == isReadTest); } // Remove records one by one @@ -129,7 +124,6 @@ TEST_CASE("SMS Record tests") for (const auto &w : *records) { REQUIRE(w.body == bodyTest); REQUIRE(w.number == numberTest); - REQUIRE(w.isRead == isReadTest); } // Get all available records by specified thread ID and check for invalid data @@ -138,7 +132,6 @@ TEST_CASE("SMS Record tests") for (const auto &w : *records) { REQUIRE(w.body == bodyTest); REQUIRE(w.number == numberTest2); - REQUIRE(w.isRead == isReadTest); } // Get all available records by specified contact ID and check for invalid data @@ -147,7 +140,6 @@ TEST_CASE("SMS Record tests") for (const auto &w : *records) { REQUIRE(w.body == bodyTest); REQUIRE(w.number == numberTest); - REQUIRE(w.isRead == isReadTest); } // Get all available records by specified contact ID and check for invalid data @@ -156,7 +148,6 @@ TEST_CASE("SMS Record tests") for (const auto &w : *records) { REQUIRE(w.body == bodyTest); REQUIRE(w.number == numberTest2); - REQUIRE(w.isRead == isReadTest); } // Remove sms records in order to check automatic management of threads and contact databases diff --git a/module-db/tests/SMSTable_tests.cpp b/module-db/tests/SMSTable_tests.cpp index 6066962a7..c6394510f 100644 --- a/module-db/tests/SMSTable_tests.cpp +++ b/module-db/tests/SMSTable_tests.cpp @@ -39,7 +39,6 @@ TEST_CASE("SMS Table tests") .dateSent = 0, .errorCode = 0, .body = "Test SMS message 1", - .isRead = true, .type = SMSType ::INBOX }; diff --git a/module-db/tests/ThreadRecord_tests.cpp b/module-db/tests/ThreadRecord_tests.cpp index 745102743..86017d4a0 100644 --- a/module-db/tests/ThreadRecord_tests.cpp +++ b/module-db/tests/ThreadRecord_tests.cpp @@ -39,7 +39,7 @@ TEST_CASE("Thread Record tests") const uint32_t dateTest = 123456789; const char *snippetTest = "Test snippet"; const char *snippetTest2 = "Test snippet2"; - const SMSType typeTest = SMSType ::ALL; + const SMSType typeTest = SMSType ::UNKNOWN; const uint32_t contactIDTest = 100; ThreadRecordInterface threadRecordInterface1(smsDB.get(), contactsDB.get()); @@ -54,53 +54,70 @@ TEST_CASE("Thread Record tests") REQUIRE(threadRecordInterface1.Add(recordIN)); REQUIRE(threadRecordInterface1.Add(recordIN)); - // Get all available records - auto records = threadRecordInterface1.GetLimitOffset(0, 100); - REQUIRE((*records).size() == 2); - - // Check if fetched records contain valid data - for (const auto &w : *records) { - REQUIRE(w.date == dateTest); - REQUIRE(w.snippet == snippetTest); - REQUIRE(w.type == typeTest); - REQUIRE(w.contactID == contactIDTest); + SECTION("isUnread") + { + REQUIRE_FALSE(recordIN.isUnread()); + recordIN.unreadMsgCount = 10; + REQUIRE(recordIN.isUnread()); } - // Get all available records by specified thread ID and check for invalid data - records = threadRecordInterface1.GetLimitOffsetByField( - 0, 100, ThreadRecordField ::ContactID, std::to_string(contactIDTest).c_str()); - REQUIRE((*records).size() == 2); - for (const auto &w : *records) { - REQUIRE(w.date == dateTest); - REQUIRE(w.snippet == snippetTest); - REQUIRE(w.type == typeTest); - REQUIRE(w.contactID == contactIDTest); + SECTION("Get Count") + { + recordIN.unreadMsgCount = 10; + REQUIRE(threadRecordInterface1.Add(recordIN)); + REQUIRE(threadRecordInterface1.GetCount() == 3); + REQUIRE(threadRecordInterface1.GetCount(EntryState::ALL) == 3); + REQUIRE(threadRecordInterface1.GetCount(EntryState::READ) == 2); + REQUIRE(threadRecordInterface1.GetCount(EntryState::UNREAD) == 1); } - // Remove records one by one - REQUIRE(threadRecordInterface1.RemoveByID(1)); - REQUIRE(threadRecordInterface1.RemoveByID(2)); + SECTION("Get all available records") + { + auto records = threadRecordInterface1.GetLimitOffset(0, 100); + REQUIRE((*records).size() == 2); - // SMS database should not contain any records - REQUIRE(threadRecordInterface1.GetCount() == 0); + // Check if fetched records contain valid data + for (const auto &w : *records) { + REQUIRE(w.date == dateTest); + REQUIRE(w.snippet == snippetTest); + REQUIRE(w.type == typeTest); + REQUIRE(w.contactID == contactIDTest); + } + } - // Test updating record - REQUIRE(threadRecordInterface1.Add(recordIN)); - recordIN.ID = 1; - recordIN.snippet = snippetTest2; - REQUIRE(threadRecordInterface1.Update(recordIN)); + SECTION("Get all available records by specified thread ID and check for invalid data") + { + auto records = threadRecordInterface1.GetLimitOffsetByField( + 0, 100, ThreadRecordField ::ContactID, std::to_string(contactIDTest).c_str()); + REQUIRE((*records).size() == 2); + for (const auto &w : *records) { + REQUIRE(w.date == dateTest); + REQUIRE(w.snippet == snippetTest); + REQUIRE(w.type == typeTest); + REQUIRE(w.contactID == contactIDTest); + } + } - auto record = threadRecordInterface1.GetByID(1); - REQUIRE(record.isValid()); - REQUIRE(record.snippet == snippetTest2); + SECTION("Remove records one by one") + { + REQUIRE(threadRecordInterface1.RemoveByID(1)); + REQUIRE(threadRecordInterface1.RemoveByID(2)); - // SMS database should contain 1 record - REQUIRE(threadRecordInterface1.GetCount() == 1); + // SMS database should not contain any records + REQUIRE(threadRecordInterface1.GetCount() == 0); + } - // Remove existing record - REQUIRE(threadRecordInterface1.RemoveByID(1)); - // SMS database should be empty - REQUIRE(threadRecordInterface1.GetCount() == 0); + SECTION("Test updating record") + { + // REQUIRE(threadRecordInterface1.Add(recordIN)); + recordIN.ID = 1; + recordIN.snippet = snippetTest2; + REQUIRE(threadRecordInterface1.Update(recordIN)); + + auto record = threadRecordInterface1.GetByID(1); + REQUIRE(record.isValid()); + REQUIRE(record.snippet == snippetTest2); + } Database::Deinitialize(); } diff --git a/module-db/tests/ThreadsTable_tests.cpp b/module-db/tests/ThreadsTable_tests.cpp index 5c0c14f76..624a96db6 100644 --- a/module-db/tests/ThreadsTable_tests.cpp +++ b/module-db/tests/ThreadsTable_tests.cpp @@ -31,13 +31,13 @@ TEST_CASE("Threads Table tests") SmsDB smsdb; REQUIRE(smsdb.IsInitialized()); - ThreadsTableRow testRow1 = {.ID = 0, - .date = 0, - .msgCount = 0, - .msgRead = 0, - .contactID = 0, - .snippet = "Test snippet", - .type = SMSType ::DRAFT + ThreadsTableRow testRow1 = {.ID = 0, + .date = 0, + .msgCount = 0, + .unreadMsgCount = 0, + .contactID = 0, + .snippet = "Test snippet", + .type = SMSType ::DRAFT }; @@ -45,10 +45,14 @@ TEST_CASE("Threads Table tests") REQUIRE(smsdb.threads.Add(testRow1)); REQUIRE(smsdb.threads.Add(testRow1)); REQUIRE(smsdb.threads.Add(testRow1)); + testRow1.unreadMsgCount = 10; REQUIRE(smsdb.threads.Add(testRow1)); // Table should have 4 elements REQUIRE(smsdb.threads.GetCount() == 4); + REQUIRE(smsdb.threads.GetCount(EntryState::ALL) == 4); + REQUIRE(smsdb.threads.GetCount(EntryState::READ) == 3); + REQUIRE(smsdb.threads.GetCount(EntryState::UNREAD) == 1); // Update existing element in table testRow1.ID = 4; diff --git a/module-services/service-db/ServiceDB.cpp b/module-services/service-db/ServiceDB.cpp index f7c2a7762..2806e7f33 100644 --- a/module-services/service-db/ServiceDB.cpp +++ b/module-services/service-db/ServiceDB.cpp @@ -171,7 +171,7 @@ sys::Message_t ServiceDB::DataReceivedHandler(sys::DataMessage *msgl, sys::Respo auto msg = dynamic_cast(msgl); assert(msg); auto time = utils::time::Scoped("DBSMSGetCount"); - auto ret = smsRecordInterface->GetCount(msg->state); + auto ret = smsRecordInterface->GetCount(); responseMsg = std::make_shared(nullptr, true, ret); break; } @@ -218,9 +218,9 @@ sys::Message_t ServiceDB::DataReceivedHandler(sys::DataMessage *msgl, sys::Respo } break; case MessageType::DBThreadGetCount: { - // DBThreadMessage *msg = reinterpret_cast(msgl); - auto time = utils::time::Scoped("DBThreadGetCount"); - auto ret = threadRecordInterface->GetCount(); + auto *msg = static_cast(msgl); + auto time = utils::time::Scoped("DBThreadGetCountMessage"); + auto ret = threadRecordInterface->GetCount(msg->state); responseMsg = std::make_shared(nullptr, true, 0, 0, ret); } break; @@ -229,6 +229,7 @@ sys::Message_t ServiceDB::DataReceivedHandler(sys::DataMessage *msgl, sys::Respo auto msg = static_cast(msgl); auto ret = threadRecordInterface->Update(msg->record); responseMsg = std::make_shared(nullptr, true, 0, 0, ret); + sendUpdateNotification(db::Interface::Name::SMSThread, db::Query::Type::Update); } break; /** diff --git a/module-services/service-db/api/DBServiceAPI.cpp b/module-services/service-db/api/DBServiceAPI.cpp index a61576735..4ec00736b 100644 --- a/module-services/service-db/api/DBServiceAPI.cpp +++ b/module-services/service-db/api/DBServiceAPI.cpp @@ -150,9 +150,9 @@ std::unique_ptr> DBServiceAPI::SMSGetLimitOffsetByThreadI } } -uint32_t DBServiceAPI::SMSGetCount(sys::Service *serv, EntryState state) +uint32_t DBServiceAPI::SMSGetCount(sys::Service *serv) { - std::shared_ptr msg = std::make_shared(state); + std::shared_ptr msg = std::make_shared(); auto ret = sys::Bus::SendUnicast(msg, service::name::db, serv, 5000); auto *sms = reinterpret_cast(ret.second.get()); @@ -219,9 +219,9 @@ bool DBServiceAPI::ThreadGetLimitOffset(sys::Service *serv, uint32_t offset, uin return true; } -uint32_t DBServiceAPI::ThreadGetCount(sys::Service *serv) +uint32_t DBServiceAPI::ThreadGetCount(sys::Service *serv, EntryState state) { - std::shared_ptr msg = std::make_shared(MessageType::DBThreadGetCount); + auto msg = std::make_shared(state); auto ret = sys::Bus::SendUnicast(msg, service::name::db, serv, 5000); DBThreadResponseMessage *threadResponse = reinterpret_cast(ret.second.get()); diff --git a/module-services/service-db/api/DBServiceAPI.hpp b/module-services/service-db/api/DBServiceAPI.hpp index 4bda85f6b..b5b03038f 100644 --- a/module-services/service-db/api/DBServiceAPI.hpp +++ b/module-services/service-db/api/DBServiceAPI.hpp @@ -44,7 +44,7 @@ class DBServiceAPI uint32_t offset, uint32_t limit, uint32_t id); - static uint32_t SMSGetCount(sys::Service *serv, EntryState state = EntryState::ALL); + static uint32_t SMSGetCount(sys::Service *serv); /** * @brief Function is getting last modified SMS record. * @param serv Pointer to Service based object that is sending request. @@ -56,7 +56,7 @@ class DBServiceAPI static std::unique_ptr ThreadGetByContact(sys::Service *serv, uint32_t contactID); static bool ThreadRemove(sys::Service *serv, uint32_t id); static bool ThreadGetLimitOffset(sys::Service *serv, uint32_t offset, uint32_t limit); - static uint32_t ThreadGetCount(sys::Service *serv); + static uint32_t ThreadGetCount(sys::Service *serv, EntryState state = EntryState::ALL); static bool ThreadUpdate(sys::Service *serv, const ThreadRecord &rec); static bool SMSTemplateAdd(sys::Service *serv, const SMSTemplateRecord &rec); diff --git a/module-services/service-db/messages/DBSMSMessage.cpp b/module-services/service-db/messages/DBSMSMessage.cpp index 58d6d2137..18677639c 100644 --- a/module-services/service-db/messages/DBSMSMessage.cpp +++ b/module-services/service-db/messages/DBSMSMessage.cpp @@ -3,7 +3,7 @@ DBSMSMessage::DBSMSMessage(MessageType messageType, const SMSRecord &rec) : DBMessage(messageType), record(rec) {} -DBSMSGetCount::DBSMSGetCount(EntryState state) : DBSMSMessage(MessageType::DBSMSGetCount), state(state) +DBSMSGetCount::DBSMSGetCount() : DBSMSMessage(MessageType::DBSMSGetCount) {} DBSMSResponseMessage::DBSMSResponseMessage(std::unique_ptr> rec, diff --git a/module-services/service-db/messages/DBSMSMessage.hpp b/module-services/service-db/messages/DBSMSMessage.hpp index 19c07c2b9..f85fea01c 100644 --- a/module-services/service-db/messages/DBSMSMessage.hpp +++ b/module-services/service-db/messages/DBSMSMessage.hpp @@ -13,8 +13,7 @@ class DBSMSMessage : public DBMessage class DBSMSGetCount : public DBSMSMessage { public: - EntryState state; - DBSMSGetCount(EntryState state = EntryState::ALL); + DBSMSGetCount(); }; class DBSMSResponseMessage : public DBResponseMessage diff --git a/module-services/service-db/messages/DBThreadMessage.cpp b/module-services/service-db/messages/DBThreadMessage.cpp index 4be854a39..933d93297 100644 --- a/module-services/service-db/messages/DBThreadMessage.cpp +++ b/module-services/service-db/messages/DBThreadMessage.cpp @@ -7,6 +7,10 @@ DBThreadMessageGet::DBThreadMessageGet(MessageType messageType, uint32_t contact : DBMessage(messageType), contactID(contactID) {} +DBThreadGetCountMessage::DBThreadGetCountMessage(EntryState state) + : DBMessage(MessageType::DBThreadGetCount), state(state) +{} + DBThreadResponseMessage::DBThreadResponseMessage(std::unique_ptr> rec, uint32_t retCode, uint32_t limit, diff --git a/module-services/service-db/messages/DBThreadMessage.hpp b/module-services/service-db/messages/DBThreadMessage.hpp index fa408dbf5..f58c21961 100644 --- a/module-services/service-db/messages/DBThreadMessage.hpp +++ b/module-services/service-db/messages/DBThreadMessage.hpp @@ -10,6 +10,13 @@ class DBThreadMessage : public DBMessage ThreadRecord record; }; +class DBThreadGetCountMessage : public DBMessage +{ + public: + EntryState state; + DBThreadGetCountMessage(EntryState state = EntryState::ALL); +}; + class DBThreadMessageGet : public DBMessage { public: