diff --git a/module-db/CMakeLists.txt b/module-db/CMakeLists.txt index 7392f9781..adb80d2a1 100644 --- a/module-db/CMakeLists.txt +++ b/module-db/CMakeLists.txt @@ -41,7 +41,7 @@ set(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Tables/ContactsAddressTable.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Interface/Record.cpp - #${CMAKE_CURRENT_SOURCE_DIR}/Interface/SMSRecord.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Interface/SMSRecord.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Interface/ContactRecord.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Interface/ThreadRecord.cpp diff --git a/module-db/Interface/SMSRecord.cpp b/module-db/Interface/SMSRecord.cpp index 1e42be9aa..e87c99928 100644 --- a/module-db/Interface/SMSRecord.cpp +++ b/module-db/Interface/SMSRecord.cpp @@ -10,37 +10,190 @@ #include "SMSRecord.hpp" +#include "../Databases/SmsDB.hpp" +#include "ContactRecord.hpp" +#include "ThreadRecord.hpp" -SMSRecord::SMSRecord(): -Record() { + +bool SMSRecordInterface::Add(const SMSRecord &rec) { + auto smsDB = std::make_unique(); + + + uint32_t contactID = 0; + + ContactRecordInterface contactInterface; + auto contactRec = contactInterface.GetLimitOffsetByField(0, 1, ContactRecordField::NumberE164, rec.number.c_str()); + + // Contact not found, create one + if (contactRec->size() == 0) { + contactInterface.Add(ContactRecord{ + .numberUser=rec.number, + .numberE164=rec.number, + .contactType=ContactType::MESSAGE, + }); + + contactRec = contactInterface.GetLimitOffsetByField(0, 1, ContactRecordField::NumberE164, + rec.number.c_str()); + } + contactID = (*contactRec)[0].dbID; + + + + // Search for a thread with specified contactID + uint32_t threadID =0; + ThreadRecordInterface threadInterface; + auto threadRec = threadInterface.GetLimitOffsetByField(0, 1, ThreadRecordField::ContactID, + std::to_string(contactID).c_str()); + + // Thread not found, create one + if (threadRec->size() == 0) { + + threadInterface.Add(ThreadRecord{ + .contactID=contactID, + }); + + threadRec = threadInterface.GetLimitOffsetByField(0,1,ThreadRecordField::ContactID,std::to_string(contactID).c_str()); + + } + threadID = (*threadRec)[0].dbID; + + // Create SMS + auto ret = smsDB->sms.Add(SMSTableRow{ + .threadID = threadID, + .contactID=contactID, + .date=rec.date, + .dateSent=rec.dateSent, + .errorCode=rec.errorCode, + .body=rec.body, + .isRead=rec.isRead, + .type=rec.type + + }); + + // Update thread + auto thread = (*threadRec)[0]; + thread.snippet = rec.body.substr(0,rec.body.length() >= snippetLength ? snippetLength : rec.body.length()); + thread.date = rec.date; + thread.type = rec.type; + thread.msgCount++; + if(rec.type == SMSType::INBOX){ + thread.msgRead++; + } + + threadInterface.Update(thread); + + + return true; +} + +uint32_t SMSRecordInterface::GetCount() { + auto smsDB = std::make_unique(); + return smsDB->sms.GetCount(); +} + +std::unique_ptr> SMSRecordInterface::GetLimitOffsetByField(uint32_t offset, uint32_t limit, + SMSRecordField field, + const char *str) { } -SMSRecord::~SMSRecord() { + +std::unique_ptr> SMSRecordInterface::GetLimitOffset(uint32_t offset, uint32_t limit) { } -bool SMSRecord::Add() { +bool SMSRecordInterface::Update(const SMSRecord &rec) { + auto smsDB = std::make_unique(); - auto smsdb = std::make_unique(); - auto contactdb = std::make_unique(); + auto sms = smsDB->sms.GetByID(rec.dbID); + if(sms.ID == 0){ + return false; + } + smsDB->sms.Update(SMSTableRow{ + .ID=rec.dbID, + .threadID=sms.threadID, + .contactID=sms.contactID, + .date=rec.date, + .dateSent=rec.dateSent, + .errorCode=rec.errorCode, + .body=rec.body, + .isRead=rec.isRead, + .type=rec.type + }); - // Check if contact exists - auto contact = contactdb->number.GetByName(number.c_str()); - if(contact.ID == 0){ - + // Update messages read count if necessary + if(!sms.isRead && rec.isRead){ + ThreadRecordInterface threadInterface; + auto threadRec = threadInterface.GetByID(sms.threadID); + threadRec.msgRead--; + threadInterface.Update(threadRec); } - - //db->threads.Add() + return true; } -bool SMSRecord::Remove() { +bool SMSRecordInterface::RemoveByID(uint32_t id) { + auto smsDB = std::make_unique(); + + auto sms = smsDB->sms.GetByID(id); + if(sms.ID == 0){ + return false; + } + + ThreadRecordInterface threadInterface; + auto threadRec = threadInterface.GetByID(sms.threadID); + + // If thread not found + if(threadRec.dbID == 0){ + if(smsDB->sms.RemoveByID(id) == false){ + return false; + } + + return false; + } + + // If thread contains only one message remove it + if(threadRec.msgCount == 1){ + threadInterface.RemoveByID(sms.threadID); + } + else{ + // Update msg count + threadRec.msgCount--; + threadInterface.Update(threadRec); + } + + // Remove SMS + if(smsDB->sms.RemoveByID(id) == false){ + return false; + } + + return true; +} + +SMSRecord SMSRecordInterface::GetByID(uint32_t id) { + auto smsDB = std::make_unique(); + auto sms = smsDB->sms.GetByID(id); + + + ContactRecordInterface contactInterface; + auto contactRec = contactInterface.GetByID(sms.contactID); + + return SMSRecord{ + .dbID=sms.ID, + .date=sms.date, + .dateSent=sms.dateSent, + .errorCode=sms.errorCode, + .number=contactRec.numberE164,// TODO: or numberUser? + .body=sms.body, + .isRead=sms.isRead, + .type=sms.type, + .threadID=sms.threadID, + .contactID=sms.contactID + + }; } -bool SMSRecord::Update() { -} \ No newline at end of file diff --git a/module-db/Interface/SMSRecord.hpp b/module-db/Interface/SMSRecord.hpp index edf711c2c..195ef1002 100644 --- a/module-db/Interface/SMSRecord.hpp +++ b/module-db/Interface/SMSRecord.hpp @@ -16,31 +16,42 @@ #include #include "utf8/UTF8.hpp" #include "../Common/Common.hpp" -#include "../Databases/SmsDB.hpp" -#include "../Databases/ContactsDB.hpp" - -class SMSRecord : public Record { -public: - - SMSRecord(); - ~SMSRecord(); - - bool Add() override final; - bool Remove() override final; - bool Update() override final; +struct SMSRecord{ uint32_t dbID; - uint32_t threadID; - uint32_t contactID; uint32_t date; uint32_t dateSent; uint32_t errorCode; UTF8 number; UTF8 body; - uint32_t read; + bool isRead; SMSType type; + uint32_t threadID; + uint32_t contactID; +}; + +enum class SMSRecordField{ + Number, + ThreadID, + ContactID +}; + +class SMSRecordInterface : public RecordInterface { +public: + + bool Add(const SMSRecord& rec) override final; + bool RemoveByID(uint32_t id) override final; + bool Update(const SMSRecord& rec) override final; + SMSRecord GetByID(uint32_t id) override final; + + uint32_t GetCount() override final; + + std::unique_ptr> GetLimitOffset(uint32_t offset,uint32_t limit) override final; + + std::unique_ptr> GetLimitOffsetByField(uint32_t offset,uint32_t limit,SMSRecordField field, const char* str) override final; private: + const uint32_t snippetLength = 45; }; diff --git a/module-db/Interface/ThreadRecord.cpp b/module-db/Interface/ThreadRecord.cpp index 949aa7598..a3eada4b9 100644 --- a/module-db/Interface/ThreadRecord.cpp +++ b/module-db/Interface/ThreadRecord.cpp @@ -35,8 +35,6 @@ bool ThreadRecordInterface::RemoveByID(uint32_t id) { if (ret == false) { return false; } - - //TODO: remove SMS records from SMS tables } bool ThreadRecordInterface::Update(const ThreadRecord &rec) { @@ -83,14 +81,14 @@ std::unique_ptr> ThreadRecordInterface::GetLimitOffset } std::unique_ptr> ThreadRecordInterface::GetLimitOffsetByField(uint32_t offset, uint32_t limit, - ContactRecordField field, + ThreadRecordField field, const char *str) { auto smsDB = std::make_unique(); auto records = std::make_unique>(); switch (field) { - case ContactRecordField::Date: { - auto ret = smsDB->threads.GetLimitOffsetByField(offset, limit,ThreadsTableFields::Date,str); + case ThreadRecordField::ContactID: { + auto ret = smsDB->threads.GetLimitOffsetByField(offset, limit,ThreadsTableFields::ContactID,str); for(const auto &w: ret){ records->push_back(ThreadRecord{ @@ -107,4 +105,22 @@ std::unique_ptr> ThreadRecordInterface::GetLimitOffset break; } + + return records; +} + +ThreadRecord ThreadRecordInterface::GetByID(uint32_t id) { + auto smsDB = std::make_unique(); + + auto rec = smsDB->threads.GetByID(id); + + return ThreadRecord{ + .dbID = rec.ID, + .date = rec.date, + .msgCount=rec.msgCount, + .msgRead=rec.msgRead, + .snippet=rec.snippet, + .type=rec.type, + .contactID=rec.contactID + }; } \ No newline at end of file diff --git a/module-db/Interface/ThreadRecord.hpp b/module-db/Interface/ThreadRecord.hpp index 3ba084f8d..165d6b763 100644 --- a/module-db/Interface/ThreadRecord.hpp +++ b/module-db/Interface/ThreadRecord.hpp @@ -28,11 +28,11 @@ struct ThreadRecord{ uint32_t contactID; }; -enum class ContactRecordField{ - Date, +enum class ThreadRecordField{ + ContactID, }; -class ThreadRecordInterface : public RecordInterface{ +class ThreadRecordInterface : public RecordInterface{ public: bool Add(const ThreadRecord& rec) override final; @@ -44,7 +44,7 @@ public: std::unique_ptr> GetLimitOffset(uint32_t offset,uint32_t limit) override final; - std::unique_ptr> GetLimitOffsetByField(uint32_t offset,uint32_t limit,ContactRecordField field, const char* str) override final; + std::unique_ptr> GetLimitOffsetByField(uint32_t offset,uint32_t limit,ThreadRecordField field, const char* str) override final; }; diff --git a/module-db/Tables/ThreadsTable.cpp b/module-db/Tables/ThreadsTable.cpp index c230e53c4..29ea5acc9 100644 --- a/module-db/Tables/ThreadsTable.cpp +++ b/module-db/Tables/ThreadsTable.cpp @@ -112,6 +112,9 @@ ThreadsTable::GetLimitOffsetByField(uint32_t offset, uint32_t limit, ThreadsTabl case ThreadsTableFields::MsgCount: fieldName = "msg_count"; break; + case ThreadsTableFields ::ContactID: + fieldName = "contact_id"; + break; default: return std::vector(); diff --git a/module-db/tests/CMakeLists.txt b/module-db/tests/CMakeLists.txt index ef7df4078..63e217d5b 100644 --- a/module-db/tests/CMakeLists.txt +++ b/module-db/tests/CMakeLists.txt @@ -19,6 +19,7 @@ add_executable( ${PROJECT_NAME} "${CMAKE_CURRENT_SOURCE_DIR}/ContactsAddressTable_tests.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ContactsRecord_tests.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/SMSRecord_tests.cpp" ) target_link_libraries( ${PROJECT_NAME} PRIVATE module-db ) diff --git a/module-db/tests/SMSRecord_tests.cpp b/module-db/tests/SMSRecord_tests.cpp new file mode 100644 index 000000000..b8ce09721 --- /dev/null +++ b/module-db/tests/SMSRecord_tests.cpp @@ -0,0 +1,66 @@ + +/* + * @file SMSRecord_tests.cpp + * @author Mateusz Piesta (mateusz.piesta@mudita.com) + * @date 05.06.19 + * @brief + * @copyright Copyright (C) 2019 mudita.com + * @details + */ + + +#include "vfs.hpp" + +#include "catch.hpp" + +#include +#include +#include +#include + +#include + +#include "../Database/Database.hpp" +#include "../Databases/ContactsDB.hpp" +#include "../Databases/SmsDB.hpp" +#include "../Interface/SMSRecord.hpp" + +struct test{ + UTF8 test; + UTF8 test2; +}; + + +TEST_CASE("SMS Record tests") +{ + Database::Initialize(); + + vfs.remove(ContactsDB::GetDBName()); + vfs.remove(SmsDB::GetDBName()); + + + const uint32_t dateTest = 123456789; + const uint32_t dateSentTest = 987654321; + const uint32_t errorCodeTest = 555; + const char *numberTest = "111222333"; + const char *bodyTest = "Test SMS Body"; + const bool isReadTest = true; + const SMSType typeTest = SMSType ::DRAFT; + + + SMSRecordInterface smsRecInterface; + + SMSRecord recordIN; + recordIN.date = dateTest; + recordIN.dateSent = dateSentTest; + recordIN.errorCode = errorCodeTest; + recordIN.number = numberTest; + recordIN.body = bodyTest; + recordIN.isRead = isReadTest; + recordIN.type = typeTest; + + REQUIRE(smsRecInterface.Add(recordIN)); + + REQUIRE(smsRecInterface.RemoveByID(1)); + +} \ No newline at end of file diff --git a/module-utils/utf8/UTF8.cpp b/module-utils/utf8/UTF8.cpp index ac3118f4f..3414c206a 100644 --- a/module-utils/utf8/UTF8.cpp +++ b/module-utils/utf8/UTF8.cpp @@ -138,6 +138,7 @@ UTF8::UTF8( const UTF8& utf ) { else { sizeAllocated = stringExpansion; data = new uint8_t[sizeAllocated]; + memset(data,0,sizeAllocated); sizeUsed = 0; } lastIndex = 0; @@ -314,7 +315,7 @@ bool UTF8::operator==( const UTF8& utf ) const { const char* UTF8::c_str() const { return reinterpret_cast(data); } -UTF8 UTF8::substr( const uint32_t begin, const uint32_t length) { +UTF8 UTF8::substr( const uint32_t begin, const uint32_t length) const { if( ( begin + length > this->length() ) || ( length == 0) ) diff --git a/module-utils/utf8/UTF8.hpp b/module-utils/utf8/UTF8.hpp index 42ec70555..a677ff6ae 100644 --- a/module-utils/utf8/UTF8.hpp +++ b/module-utils/utf8/UTF8.hpp @@ -76,7 +76,7 @@ public: *@return substring created from source string. *@note In case of start index greater than length of source string or length that exceeds character empty string is returned. **/ - UTF8 substr( const uint32_t begin, const uint32_t length ); + UTF8 substr( const uint32_t begin, const uint32_t length ) const; /** * @brief Finds first occurrence of substring in string