diff --git a/changelog.md b/changelog.md index c41d1899e..847113d13 100644 --- a/changelog.md +++ b/changelog.md @@ -8,6 +8,8 @@ ### Changed +* `[messages]` Use different thread for each of contact's number. + ### Fixed * `[desktopApp]` Fixed endpoint handling. @@ -20,8 +22,6 @@ ### Other * `[desktopApp]` Added functional tests. - - ## [0.36.1 2020-09-04] ### Added diff --git a/image/user/sms.db b/image/user/sms.db index 3da0aade6..7511c6024 100644 Binary files a/image/user/sms.db and b/image/user/sms.db differ diff --git a/module-apps/application-messages/windows/NewMessage.cpp b/module-apps/application-messages/windows/NewMessage.cpp index 6eedcaad3..cc295ea79 100644 --- a/module-apps/application-messages/windows/NewMessage.cpp +++ b/module-apps/application-messages/windows/NewMessage.cpp @@ -32,6 +32,7 @@ namespace gui if (data == nullptr) { return; } + if (auto pdata = dynamic_cast(data); pdata != nullptr) { LOG_INFO("received search results"); recipient->setText(pdata->result->getFormattedName()); @@ -45,11 +46,12 @@ namespace gui } if (auto pdata = dynamic_cast(data); pdata != nullptr) { LOG_INFO("recieved sms send request"); - auto number = pdata->getPhoneNumber(); - auto retContact = DBServiceAPI::MatchContactByPhoneNumber(application, number); + phoneNumber = pdata->getPhoneNumber(); + LOG_INFO("Number to send sms to: %s", phoneNumber.getFormatted().c_str()); + auto retContact = DBServiceAPI::MatchContactByPhoneNumber(application, phoneNumber); if (!retContact) { - LOG_WARN("not valid contact for number %s", number.getEntered().c_str()); - recipient->setText(number.getFormatted()); + LOG_WARN("not valid contact for number %s", phoneNumber.getEntered().c_str()); + recipient->setText(phoneNumber.getFormatted()); message->setText(pdata->textData); return; } @@ -77,9 +79,16 @@ namespace gui { auto app = dynamic_cast(application); assert(app != nullptr); - // if a valid contact was found, choose it. Otherwise, get a raw entered number - auto number = (contact && contact->numbers.size() != 0) ? contact->numbers[0].number - : utils::PhoneNumber(recipient->getText()).getView(); + utils::PhoneNumber::View number; + + if (phoneNumber.getEntered().size() > 0) { + number = phoneNumber; + } + else { + number = (contact && contact->numbers.size() != 0) ? contact->numbers[0].number + : utils::PhoneNumber(recipient->getText()).getView(); + } + auto ret = app->sendSms(number, message->getText()); if (!ret) { LOG_ERROR("sendSms failed"); @@ -102,22 +111,11 @@ namespace gui bool NewSMS_Window::switchToThreadWindow(const utils::PhoneNumber::View &number) { - uint32_t contactId; - if (!contact || contact->numbers.size() == 0) { - // once the sms is send, there is assumption that contact exists - auto retContact = DBServiceAPI::MatchContactByPhoneNumber(application, number); - if (!retContact) { - LOG_ERROR("not valid contact for number %s", number.getFormatted().c_str()); - return false; - } - contact = std::move(retContact); - } - contactId = contact->ID; - - auto thread = DBServiceAPI::ThreadGetByContact(application, contactId); + auto thread = DBServiceAPI::ThreadGetByNumber(application, number, getThreadTimeout); if (thread) { // clear data only when message is sent contact = nullptr; + phoneNumber.clear(); recipient->setText(""); message->setText(""); setFocusItem(body); diff --git a/module-apps/application-messages/windows/NewMessage.hpp b/module-apps/application-messages/windows/NewMessage.hpp index fe116d292..55e258d23 100644 --- a/module-apps/application-messages/windows/NewMessage.hpp +++ b/module-apps/application-messages/windows/NewMessage.hpp @@ -12,10 +12,14 @@ namespace gui class NewSMS_Window : public AppWindow { private: + inline static const std::uint32_t getThreadTimeout = 1000; + gui::Text *recipient = nullptr; gui::Text *message = nullptr; gui::VBox *body = nullptr; std::shared_ptr contact; + utils::PhoneNumber::View phoneNumber; + std::uint32_t numberId = 0; bool selectContact(); bool sendSms(); diff --git a/module-apps/application-messages/windows/ThreadViewWindow.cpp b/module-apps/application-messages/windows/ThreadViewWindow.cpp index ccdaab918..0c205a5d5 100644 --- a/module-apps/application-messages/windows/ThreadViewWindow.cpp +++ b/module-apps/application-messages/windows/ThreadViewWindow.cpp @@ -70,7 +70,7 @@ namespace gui inputMessage->activatedCallback = [&](gui::Item &item) { auto app = dynamic_cast(application); assert(app != nullptr); - if (app->handleSendSmsFromThread(contact->numbers[0].number, inputMessage->inputText->getText())) { + if (app->handleSendSmsFromThread(*number, inputMessage->inputText->getText())) { LOG_ERROR("handleSendSmsFromThread failed"); } inputMessage->inputText->clear(); @@ -372,6 +372,10 @@ namespace gui contact = std::make_shared(ret->front()); // should be name number for now - easier to handle setTitle(ret->front().getFormattedName()); + auto retNumber = DBServiceAPI::GetNumberById(application, pdata->thread->numberID, numberIdTimeout); + assert(retNumber != nullptr); + number = std::move(retNumber); + LOG_INFO("Phone number for thread: %s", number->getFormatted().c_str()); } } if (auto pdata = dynamic_cast(data)) { diff --git a/module-apps/application-messages/windows/ThreadViewWindow.hpp b/module-apps/application-messages/windows/ThreadViewWindow.hpp index 056e2f320..64d9f2b23 100644 --- a/module-apps/application-messages/windows/ThreadViewWindow.hpp +++ b/module-apps/application-messages/windows/ThreadViewWindow.hpp @@ -1,18 +1,19 @@ #pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include #include -#include "AppWindow.hpp" -#include "ListView.hpp" -#include "gui/widgets/Image.hpp" -#include "gui/widgets/Label.hpp" -#include "gui/widgets/Window.hpp" -#include "service-db/api/DBServiceAPI.hpp" -#include -#include -#include "application-messages/widgets/SMSInputWidget.hpp" - namespace gui { class ThreadViewWindow : public AppWindow @@ -38,6 +39,7 @@ namespace gui const ssize_t maxsmsinwindow = 7; std::shared_ptr contact; + std::unique_ptr number; struct { @@ -48,7 +50,8 @@ namespace gui std::unique_ptr> sms = nullptr; // loaded sms from db } SMS; - gui::SMSInputWidget *inputMessage = nullptr; + gui::SMSInputWidget *inputMessage = nullptr; + inline static const std::uint32_t numberIdTimeout = 1000; public: ThreadViewWindow(app::Application *app); diff --git a/module-db/CMakeLists.txt b/module-db/CMakeLists.txt index f280fd5a0..f83e67820 100644 --- a/module-db/CMakeLists.txt +++ b/module-db/CMakeLists.txt @@ -76,6 +76,7 @@ set(SOURCES queries/sms/QuerySMSTemplateGetCount.cpp queries/sms/QuerySMSTemplateRemove.cpp queries/sms/QuerySMSTemplateUpdate.cpp + queries/sms/QueryThreadGetByNumber.cpp queries/calllog/QueryCalllogSetAllRead.cpp queries/calllog/QueryCalllogGet.cpp queries/calllog/QueryCalllogGetCount.cpp @@ -90,6 +91,7 @@ set(SOURCES queries/phonebook/QueryContactAdd.cpp queries/phonebook/QueryContactUpdate.cpp queries/phonebook/QueryContactRemove.cpp + queries/phonebook/QueryNumberGetByID.cpp queries/calendar/QueryEventsRemove.cpp queries/calendar/QueryEventsGet.cpp queries/calendar/QueryEventsGetAll.cpp diff --git a/module-db/Interface/CalllogRecord.cpp b/module-db/Interface/CalllogRecord.cpp index 28dee92ca..747d67ac9 100644 --- a/module-db/Interface/CalllogRecord.cpp +++ b/module-db/Interface/CalllogRecord.cpp @@ -62,14 +62,17 @@ CalllogRecordInterface::~CalllogRecordInterface() bool CalllogRecordInterface::Add(const CalllogRecord &rec) { ContactRecordInterface contactInterface(contactsDB); - auto contactRec = contactInterface.MatchByNumber(rec.phoneNumber, ContactRecordInterface::CreateTempContact::True); - if (!contactRec) { + auto contactMatch = + contactInterface.MatchByNumber(rec.phoneNumber, ContactRecordInterface::CreateTempContact::True); + if (!contactMatch) { LOG_ERROR("Cannot get contact, for number %s", rec.phoneNumber.getNonEmpty().c_str()); return false; } + auto &contactRec = contactMatch->contact; + auto localRec = rec; - localRec.contactId = std::to_string(contactRec->ID); - localRec.name = contactRec->getFormattedName(); + localRec.contactId = std::to_string(contactRec.ID); + localRec.name = contactRec.getFormattedName(); LOG_DEBUG("Adding calllog record %s", utils::to_string(localRec).c_str()); return calllogDB->calls.add(CalllogTableRow{{.ID = localRec.ID}, // this is only to remove warning diff --git a/module-db/Interface/ContactRecord.cpp b/module-db/Interface/ContactRecord.cpp index f86aa6b05..d5dbdd722 100644 --- a/module-db/Interface/ContactRecord.cpp +++ b/module-db/Interface/ContactRecord.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -164,6 +165,9 @@ std::unique_ptr ContactRecordInterface::runQuery(std::shared_pt else if (typeid(*query) == typeid(db::query::ContactRemove)) { return removeQuery(query); } + else if (typeid(*query) == typeid(db::query::NumberGetByID)) { + return numberGetByIdQuery(query); + } else { LOG_ERROR("Unexpected query type."); return nullptr; @@ -274,6 +278,7 @@ std::unique_ptr ContactRecordInterface::updateQuery(std::shared response->setRequestQuery(query); return response; } + std::unique_ptr ContactRecordInterface::removeQuery(std::shared_ptr query) { auto removeQuery = static_cast(query.get()); @@ -283,6 +288,15 @@ std::unique_ptr ContactRecordInterface::removeQuery(std::shared return response; } +std::unique_ptr ContactRecordInterface::numberGetByIdQuery(std::shared_ptr query) +{ + auto numberQuery = static_cast(query.get()); + auto ret = ContactRecordInterface::GetNumberById(numberQuery->getID()); + auto response = std::make_unique(ret); + response->setRequestQuery(query); + return response; +} + std::vector ContactRecordInterface::splitNumberIDs(const std::string &numberIDs) { std::stringstream source(numberIDs); @@ -874,9 +888,10 @@ utils::NumberHolderMatcher ContactRecordInterf std::cend(contactNumberHolders)); } -std::optional ContactRecordInterface::MatchByNumber(const utils::PhoneNumber::View &numberView, - CreateTempContact createTempContact, - utils::PhoneNumber::Match matchLevel) +std::optional ContactRecordInterface::MatchByNumber( + const utils::PhoneNumber::View &numberView, + CreateTempContact createTempContact, + utils::PhoneNumber::Match matchLevel) { std::vector contactNumberHolders; auto numberMatcher = buildNumberMatcher(contactNumberHolders); @@ -898,10 +913,17 @@ std::optional ContactRecordInterface::MatchByNumber(const utils:: return std::nullopt; } - return GetByID(contactDB->getLastInsertRowId()); + auto contactID = contactDB->getLastInsertRowId(); + auto contactTableRow = contactDB->contacts.getById(contactID); + auto numberIDs = splitNumberIDs(contactTableRow.numbersID); + assert(numberIDs.size() == 1); + auto numberID = numberIDs[0]; + return ContactRecordInterface::ContactNumberMatch(GetByID(contactID), contactID, numberID); } - return GetByID(matchedNumber->getContactID()); + auto contactID = matchedNumber->getContactID(); + auto numberID = matchedNumber->getNumberID(); + return ContactRecordInterface::ContactNumberMatch(GetByID(contactID), contactID, numberID); } std::unique_ptr> ContactRecordInterface::GetBySpeedDial(UTF8 speedDial) @@ -1041,3 +1063,15 @@ bool ContactRecord::isOnGroup(uint32_t groupId) { return groups.find(groupId) != groups.end(); } + +ContactRecordInterface::ContactNumberMatch::ContactNumberMatch(ContactRecord rec, + std::uint32_t contactId, + std::uint32_t numberId) + : contact(std::move(rec)), contactId(contactId), numberId(numberId) +{} + +utils::PhoneNumber::View ContactRecordInterface::GetNumberById(std::uint32_t numberId) +{ + auto row = contactDB->number.getById(numberId); + return utils::PhoneNumber(row.numberUser, row.numbere164).getView(); +} diff --git a/module-db/Interface/ContactRecord.hpp b/module-db/Interface/ContactRecord.hpp index 0659b91ba..ff9981e28 100644 --- a/module-db/Interface/ContactRecord.hpp +++ b/module-db/Interface/ContactRecord.hpp @@ -113,8 +113,16 @@ class ContactNumberHolder class ContactRecordInterface : public RecordInterface { - public: + struct ContactNumberMatch + { + ContactRecord contact; + std::uint32_t contactId = DB_ID_NONE; + std::uint32_t numberId = DB_ID_NONE; + + ContactNumberMatch(ContactRecord rec, std::uint32_t contactId, std::uint32_t numberId); + }; + ContactRecordInterface(ContactsDB *db); ~ContactRecordInterface(); @@ -153,7 +161,7 @@ class ContactRecordInterface : public RecordInterface> GetByNumber( const utils::PhoneNumber::View &numberView, CreateTempContact createTempContact = CreateTempContact::False); - std::optional MatchByNumber( + std::optional MatchByNumber( const utils::PhoneNumber::View &numberView, CreateTempContact createTempContact = CreateTempContact::False, utils::PhoneNumber::Match matchLevel = utils::PhoneNumber::Match::POSSIBLE); @@ -166,6 +174,8 @@ class ContactRecordInterface : public RecordInterface runQuery(std::shared_ptr query) override; + utils::PhoneNumber::View GetNumberById(std::uint32_t numberId); + private: ContactsDB *contactDB; @@ -192,4 +202,5 @@ class ContactRecordInterface : public RecordInterface addQuery(std::shared_ptr query); std::unique_ptr updateQuery(std::shared_ptr query); std::unique_ptr removeQuery(std::shared_ptr query); + std::unique_ptr numberGetByIdQuery(std::shared_ptr query); }; diff --git a/module-db/Interface/SMSRecord.cpp b/module-db/Interface/SMSRecord.cpp index 270c25cf3..9b0f4662a 100644 --- a/module-db/Interface/SMSRecord.cpp +++ b/module-db/Interface/SMSRecord.cpp @@ -29,29 +29,32 @@ SMSRecordInterface::SMSRecordInterface(SmsDB *smsDb, ContactsDB *contactsDb) : s bool SMSRecordInterface::Add(const SMSRecord &rec) { ContactRecordInterface contactInterface(contactsDB); - auto contactRec = contactInterface.MatchByNumber(rec.number, ContactRecordInterface::CreateTempContact::True); - if (contactRec == std::nullopt) { + auto contactMatch = contactInterface.MatchByNumber(rec.number, ContactRecordInterface::CreateTempContact::True); + if (contactMatch == std::nullopt) { LOG_ERROR("Cannot find contact, for number %s", rec.number.getFormatted().c_str()); return false; } - uint32_t contactID = contactRec->ID; + auto contactID = contactMatch->contactId; + auto numberID = contactMatch->numberId; + // Search for a thread with specified contactID ThreadRecordInterface threadInterface(smsDB, contactsDB); auto threadRec = - threadInterface.GetLimitOffsetByField(0, 1, ThreadRecordField::ContactID, std::to_string(contactID).c_str()); + threadInterface.GetLimitOffsetByField(0, 1, ThreadRecordField::NumberID, std::to_string(numberID).c_str()); // Thread not found, create one if (threadRec->size() == 0) { ThreadRecord re; re.contactID = contactID; + re.numberID = numberID; if (!threadInterface.Add(re)) { LOG_ERROR("Cannot create new thread"); return false; } - threadRec = threadInterface.GetLimitOffsetByField( - 0, 1, ThreadRecordField::ContactID, std::to_string(contactID).c_str()); + threadRec = + threadInterface.GetLimitOffsetByField(0, 1, ThreadRecordField::NumberID, std::to_string(numberID).c_str()); if (threadRec->size() == 0) { LOG_ERROR("Thread not found"); return false; @@ -289,8 +292,7 @@ SMSRecord SMSRecordInterface::GetByID(uint32_t id) ContactRecordInterface contactInterface(contactsDB); auto contactRec = contactInterface.GetByID(sms.contactID); - // TODO: or numberUser? - auto number = contactRec.numbers.size() != 0 ? contactRec.numbers[0].number : utils::PhoneNumber::View(); + auto number = contactRec.numbers.size() != 0 ? contactRec.numbers[0].number : utils::PhoneNumber::View(); return SMSRecord{sms, number}; } @@ -337,7 +339,6 @@ std::unique_ptr SMSRecordInterface::runQueryIm auto contactRec = contactInterface.GetByID(w.contactID); if (contactRec.numbers.size() != 0) { - // TODO: or numberUser? or other number records->push_back({w, contactRec.numbers[0].number}); } } diff --git a/module-db/Interface/ThreadRecord.cpp b/module-db/Interface/ThreadRecord.cpp index 7a0479c4d..4db71169e 100644 --- a/module-db/Interface/ThreadRecord.cpp +++ b/module-db/Interface/ThreadRecord.cpp @@ -1,5 +1,9 @@ #include "ThreadRecord.hpp" #include "SMSRecord.hpp" +#include "ContactRecord.hpp" + +#include + #include #include @@ -14,6 +18,7 @@ bool ThreadRecordInterface::Add(const ThreadRecord &rec) .msgCount = rec.msgCount, .unreadMsgCount = rec.unreadMsgCount, .contactID = rec.contactID, + .numberID = rec.numberID, .snippet = rec.snippet, .type = rec.type}); @@ -38,6 +43,7 @@ bool ThreadRecordInterface::Update(const ThreadRecord &rec) .msgCount = rec.msgCount, .unreadMsgCount = rec.unreadMsgCount, .contactID = rec.contactID, + .numberID = rec.numberID, .snippet = rec.snippet, .type = rec.type @@ -74,14 +80,19 @@ std::unique_ptr> ThreadRecordInterface::GetLimitOffset { auto records = std::make_unique>(); + ThreadsTableFields threadsField; switch (field) { case ThreadRecordField::ContactID: { - auto ret = smsDB->threads.getLimitOffsetByField(offset, limit, ThreadsTableFields::ContactID, str); - - for (const auto &w : ret) { - records->push_back(w); - } + threadsField = ThreadsTableFields::ContactID; } break; + case ThreadRecordField::NumberID: { + threadsField = ThreadsTableFields::NumberID; + } break; + } + + auto ret = smsDB->threads.getLimitOffsetByField(offset, limit, threadsField, str); + for (const auto &w : ret) { + records->push_back(w); } return records; @@ -119,6 +130,24 @@ ThreadRecord ThreadRecordInterface::GetByContact(uint32_t contact_id) return ThreadRecord(ret[0]); } +ThreadRecord ThreadRecordInterface::GetByNumber(const utils::PhoneNumber::View &phoneNumber) +{ + auto contactInterface = ContactRecordInterface(contactsDB); + auto match = contactInterface.MatchByNumber(phoneNumber); + + if (!match.has_value()) { + return ThreadRecord(); + } + + auto threadRec = GetLimitOffsetByField(0, 1, ThreadRecordField::NumberID, std::to_string(match->numberId).c_str()); + + if (threadRec->size() == 0) { + return ThreadRecord(); + } + + return threadRec->at(0); +} + std::unique_ptr ThreadRecordInterface::runQuery(std::shared_ptr query) { if (const auto localQuery = dynamic_cast(query.get())) { @@ -142,6 +171,13 @@ std::unique_ptr ThreadRecordInterface::runQuery(std::shared_ptr response->setRequestQuery(query); return response; } + + if (const auto local_query = dynamic_cast(query.get())) { + auto response = std::make_unique(GetByNumber(local_query->getNumber())); + response->setRequestQuery(query); + return response; + } + return nullptr; } diff --git a/module-db/Interface/ThreadRecord.hpp b/module-db/Interface/ThreadRecord.hpp index b6d56eba2..f77673bf4 100644 --- a/module-db/Interface/ThreadRecord.hpp +++ b/module-db/Interface/ThreadRecord.hpp @@ -7,6 +7,7 @@ #include "module-db/queries/sms/QuerySMSSearch.hpp" #include "module-db/queries/sms/QuerySMSThreadsGet.hpp" #include "module-db/queries/sms/QuerySmsThreadMarkAsRead.hpp" +#include #include @@ -19,11 +20,12 @@ struct ThreadRecord : Record UTF8 snippet; SMSType type = SMSType::UNKNOWN; uint32_t contactID = DB_ID_NONE; + uint32_t numberID = DB_ID_NONE; ThreadRecord() = default; ThreadRecord(const ThreadsTableRow &rec) : date(rec.date), msgCount(rec.msgCount), unreadMsgCount(rec.unreadMsgCount), snippet(rec.snippet), - type(rec.type), contactID(rec.contactID) + type(rec.type), contactID(rec.contactID), numberID(rec.numberID) { ID = rec.ID; } @@ -37,6 +39,7 @@ struct ThreadRecord : Record enum class ThreadRecordField { ContactID, + NumberID, }; class ThreadRecordInterface : public RecordInterface @@ -50,6 +53,7 @@ class ThreadRecordInterface : public RecordInterfaceexecute("INSERT or ignore INTO threads ( date, msg_count, read, contact_id, snippet, last_dir ) VALUES " - "( %lu, %lu, %lu, %lu, '%q', %lu );", - entry.date, - entry.msgCount, - entry.unreadMsgCount, - entry.contactID, - entry.snippet.c_str(), - entry.type); + return db->execute( + "INSERT or ignore INTO threads ( date, msg_count, read, contact_id, number_id, snippet, last_dir ) VALUES " + "( %lu, %lu, %lu, %lu, %lu, '%q', %lu );", + entry.date, + entry.msgCount, + entry.unreadMsgCount, + entry.contactID, + entry.numberID, + entry.snippet.c_str(), + entry.type); } bool ThreadsTable::removeById(uint32_t id) @@ -41,12 +43,14 @@ bool ThreadsTable::removeById(uint32_t id) bool ThreadsTable::update(ThreadsTableRow entry) { - return db->execute("UPDATE threads SET date = %lu, msg_count = %lu ,read = %lu, contact_id = %lu, snippet = '%q', " + return db->execute("UPDATE threads SET date = %lu, msg_count = %lu ,read = %lu, contact_id = %lu, number_id = %lu, " + "snippet = '%q', " "last_dir = %lu WHERE _id=%lu;", entry.date, entry.msgCount, entry.unreadMsgCount, entry.contactID, + entry.numberID, entry.snippet.c_str(), entry.type, entry.ID); @@ -66,8 +70,9 @@ ThreadsTableRow ThreadsTable::getById(uint32_t id) (*retQuery)[2].getUInt32(), // msgCount (*retQuery)[3].getUInt32(), // unreadMsgCount (*retQuery)[4].getUInt32(), // contactID - (*retQuery)[5].getString(), // snippet - static_cast((*retQuery)[6].getUInt32()), // type/last-dir + (*retQuery)[5].getUInt32(), // numberID + (*retQuery)[6].getString(), // snippet + static_cast((*retQuery)[7].getUInt32()), // type/last-dir }; } @@ -80,8 +85,9 @@ void fillRetQuery(std::vector &ret, const std::unique_ptr((*retQuery)[6].getUInt32()), // type/last-dir + (*retQuery)[5].getUInt32(), // numberID + (*retQuery)[6].getString(), // snippet + static_cast((*retQuery)[7].getUInt32()), // type/last-dir }); } while (retQuery->nextRow()); } @@ -117,6 +123,9 @@ std::vector ThreadsTable::getLimitOffsetByField(uint32_t offset case ThreadsTableFields ::ContactID: fieldName = "contact_id"; break; + case ThreadsTableFields ::NumberID: + fieldName = "number_id"; + break; default: return std::vector(); } diff --git a/module-db/Tables/ThreadsTable.hpp b/module-db/Tables/ThreadsTable.hpp index c34432c05..101dc1428 100644 --- a/module-db/Tables/ThreadsTable.hpp +++ b/module-db/Tables/ThreadsTable.hpp @@ -13,6 +13,7 @@ struct ThreadsTableRow : public Record uint32_t msgCount = 0; uint32_t unreadMsgCount = 0; uint32_t contactID = DB_ID_NONE; + uint32_t numberID = DB_ID_NONE; UTF8 snippet; SMSType type = SMSType::UNKNOWN; }; @@ -23,6 +24,7 @@ enum class ThreadsTableFields MsgCount, MsgRead, ContactID, + NumberID, Type }; @@ -58,6 +60,7 @@ class ThreadsTable : public Table "msg_count INTEGER," "read INTEGER," "contact_id INTEGER," + "number_id INTEGER," "snippet TEXT NOT NULL," "last_dir INTEGER" ");"; diff --git a/module-db/queries/phonebook/QueryNumberGetByID.cpp b/module-db/queries/phonebook/QueryNumberGetByID.cpp new file mode 100644 index 000000000..871753d94 --- /dev/null +++ b/module-db/queries/phonebook/QueryNumberGetByID.cpp @@ -0,0 +1,34 @@ +#include "QueryNumberGetByID.hpp" + +#include +#include + +#include + +using namespace db::query; + +NumberGetByID::NumberGetByID(std::uint32_t id) : Query(Query::Type::Read), id(id) +{} + +NumberGetByIDResult::NumberGetByIDResult(utils::PhoneNumber::View number) : number(std::move(number)) +{} + +[[nodiscard]] auto NumberGetByID::debugInfo() const -> std::string +{ + return "NumberGetByID"; +} + +[[nodiscard]] auto NumberGetByIDResult::debugInfo() const -> std::string +{ + return "NumberGetByIDResult"; +} + +auto NumberGetByID::getID() const noexcept -> std::uint32_t +{ + return id; +} + +auto NumberGetByIDResult::getNumber() -> utils::PhoneNumber::View +{ + return std::move(number); +} diff --git a/module-db/queries/phonebook/QueryNumberGetByID.hpp b/module-db/queries/phonebook/QueryNumberGetByID.hpp new file mode 100644 index 000000000..6afb48b42 --- /dev/null +++ b/module-db/queries/phonebook/QueryNumberGetByID.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +#include + +namespace db::query +{ + + class NumberGetByID : public Query + { + public: + NumberGetByID(std::uint32_t id); + [[nodiscard]] auto debugInfo() const -> std::string override; + auto getID() const noexcept -> std::uint32_t; + + private: + std::uint32_t id; + }; + + class NumberGetByIDResult : public QueryResult + { + public: + NumberGetByIDResult(utils::PhoneNumber::View number); + [[nodiscard]] auto debugInfo() const -> std::string override; + auto getNumber() -> utils::PhoneNumber::View; + + private: + utils::PhoneNumber::View number; + }; + +}; // namespace db::query diff --git a/module-db/queries/sms/QueryThreadGetByNumber.cpp b/module-db/queries/sms/QueryThreadGetByNumber.cpp new file mode 100644 index 000000000..48bc89a56 --- /dev/null +++ b/module-db/queries/sms/QueryThreadGetByNumber.cpp @@ -0,0 +1,36 @@ +#include "QueryThreadGetByNumber.hpp" + +#include +#include + +#include + +namespace db::query +{ + ThreadGetByNumber::ThreadGetByNumber(utils::PhoneNumber::View number) + : Query(Query::Type::Read), number(std::move(number)) + {} + + auto ThreadGetByNumber::getNumber() const -> const utils::PhoneNumber::View & + { + return number; + } + + [[nodiscard]] auto ThreadGetByNumber::debugInfo() const -> std::string + { + return "ThreadGetByNumber"; + } + + ThreadGetByNumberResult::ThreadGetByNumberResult(ThreadRecord thread) : thread(std::move(thread)) + {} + + auto ThreadGetByNumberResult::getThread() -> ThreadRecord + { + return std::move(thread); + } + + [[nodiscard]] auto ThreadGetByNumberResult::debugInfo() const -> std::string + { + return "ThreadGetByNumberResult"; + } +} // namespace db::query diff --git a/module-db/queries/sms/QueryThreadGetByNumber.hpp b/module-db/queries/sms/QueryThreadGetByNumber.hpp new file mode 100644 index 000000000..3152f1657 --- /dev/null +++ b/module-db/queries/sms/QueryThreadGetByNumber.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include + +#include + +namespace db::query +{ + + class ThreadGetByNumber : public Query + { + utils::PhoneNumber::View number; + + public: + ThreadGetByNumber(utils::PhoneNumber::View number); + auto getNumber() const -> const utils::PhoneNumber::View &; + + [[nodiscard]] auto debugInfo() const -> std::string override; + }; + + class ThreadGetByNumberResult : public QueryResult + { + ThreadRecord thread; + + public: + ThreadGetByNumberResult(ThreadRecord record); + [[nodiscard]] auto getThread() -> ThreadRecord; + [[nodiscard]] auto debugInfo() const -> std::string override; + }; + +}; // namespace db::query diff --git a/module-services/service-db/ServiceDB.cpp b/module-services/service-db/ServiceDB.cpp index a6670bb8e..27962d2cb 100644 --- a/module-services/service-db/ServiceDB.cpp +++ b/module-services/service-db/ServiceDB.cpp @@ -341,8 +341,8 @@ sys::Message_t ServiceDB::DataReceivedHandler(sys::DataMessage *msgl, sys::Respo auto ret = contactRecordInterface->MatchByNumber(msg->numberView); if (ret.has_value()) { - responseMsg = std::make_shared(sys::ReturnCodes::Success, - std::make_unique(*ret)); + responseMsg = std::make_shared( + sys::ReturnCodes::Success, std::make_unique(ret->contact)); } else { responseMsg = std::make_shared(sys::ReturnCodes::Failure, diff --git a/module-services/service-db/api/DBServiceAPI.cpp b/module-services/service-db/api/DBServiceAPI.cpp index 6bd0b4730..bc47a5af9 100644 --- a/module-services/service-db/api/DBServiceAPI.cpp +++ b/module-services/service-db/api/DBServiceAPI.cpp @@ -10,6 +10,11 @@ #include #include #include +#include + +#include +#include +#include #include #include @@ -191,6 +196,27 @@ std::unique_ptr DBServiceAPI::ThreadGetByContact(sys::Service *ser } } +std::unique_ptr DBServiceAPI::ThreadGetByNumber(sys::Service *serv, + const utils::PhoneNumber::View &phoneNumber, + std::uint32_t timeout) +{ + auto [code, msg] = DBServiceAPI::GetQueryWithReply( + serv, db::Interface::Name::SMSThread, std::make_unique(phoneNumber), timeout); + + if (code == sys::ReturnCodes::Success && msg != nullptr) { + auto queryResponse = dynamic_cast(msg.get()); + assert(queryResponse != nullptr); + + auto threadResponse = queryResponse->getResult(); + auto threadResult = dynamic_cast(threadResponse.get()); + assert(threadResult != nullptr); + + return std::make_unique(std::move(threadResult->getThread())); + } + + return nullptr; +} + bool DBServiceAPI::ThreadRemove(sys::Service *serv, uint32_t id) { std::shared_ptr msg = std::make_shared(MessageType::DBThreadRemove); @@ -805,3 +831,24 @@ bool DBServiceAPI::DBBackup(sys::Service *serv, std::string backupPath) return false; } } + +std::unique_ptr DBServiceAPI::GetNumberById(sys::Service *serv, + std::uint32_t numberId, + std::uint32_t timeout) +{ + auto [code, msg] = DBServiceAPI::GetQueryWithReply( + serv, db::Interface::Name::Contact, std::make_unique(numberId), timeout); + + if (code == sys::ReturnCodes::Success && msg != nullptr) { + auto queryResponse = dynamic_cast(msg.get()); + assert(queryResponse != nullptr); + + auto numberResponse = queryResponse->getResult(); + auto numberResult = dynamic_cast(numberResponse.get()); + assert(numberResult != nullptr); + + return std::make_unique(std::move(numberResult->getNumber())); + } + + return nullptr; +} diff --git a/module-services/service-db/api/DBServiceAPI.hpp b/module-services/service-db/api/DBServiceAPI.hpp index 06d6c1ea8..a8682b2a3 100644 --- a/module-services/service-db/api/DBServiceAPI.hpp +++ b/module-services/service-db/api/DBServiceAPI.hpp @@ -56,6 +56,9 @@ class DBServiceAPI static std::unique_ptr ThreadGet(sys::Service *serv, uint32_t id); static std::unique_ptr ThreadGetByContact(sys::Service *serv, uint32_t contactID); + static std::unique_ptr ThreadGetByNumber(sys::Service *serv, + const utils::PhoneNumber::View &phoneNumber, + std::uint32_t timeout); 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, EntryState state = EntryState::ALL); @@ -113,6 +116,9 @@ class DBServiceAPI UTF8 primaryName, UTF8 alternativeName, UTF8 number); + static std::unique_ptr GetNumberById(sys::Service *serv, + std::uint32_t numberId, + std::uint32_t timeout); static bool AlarmAdd(sys::Service *serv, const AlarmsRecord &rec); static bool AlarmRemove(sys::Service *serv, uint32_t id); static bool AlarmUpdate(sys::Service *serv, const AlarmsRecord &rec);