M module-db/Interface/ContactRecord.cpp => module-db/Interface/ContactRecord.cpp +36 -10
@@ 124,9 124,13 @@ auto ContactRecordInterface::Update(const ContactRecord &rec) -> bool
}
auto oldNumberIDs = splitNumberIDs(contact.numbersID);
- auto newNumbersIDs = getNumbersIDs(contact.ID, rec);
+ auto newNumbersIDs = getNumbersIDs(contact.ID, rec, utils::PhoneNumber::Match::EXACT);
for (auto oldNumberID : oldNumberIDs) {
if (std::find(std::begin(newNumbersIDs), std::end(newNumbersIDs), oldNumberID) == std::end(newNumbersIDs)) {
+ // If oldNumberID is NOT in newNumbersIDs vector then:
+ // -> remove oldNumberID from DB - if the old number is the same as one of the new ones
+ // but with different country number (to prevent a mismatch of same numbers)
+ // -> make temporary contact with this oldNumberID - otherwise
auto numberRecord = contactDB->number.getById(oldNumberID);
if (!numberRecord.isValid()) {
return false;
@@ 141,13 145,34 @@ auto ContactRecordInterface::Update(const ContactRecord &rec) -> bool
e.what());
return false;
}
- const auto tmpContactRecord = addTemporaryContactForNumber(number);
- if (!tmpContactRecord.has_value()) {
- return false;
+
+ bool isOldNumberToRemove = false;
+ utils::PhoneNumber oldPhoneNumber(numberRecord.numberUser, numberRecord.numbere164);
+ for (const auto newNumberID : newNumbersIDs) {
+ auto newNumberRecord = contactDB->number.getById(newNumberID);
+ utils::PhoneNumber newPhoneNumber(newNumberRecord.numberUser, newNumberRecord.numbere164);
+ if (newPhoneNumber.match(oldPhoneNumber) >= utils::PhoneNumber::Match::POSSIBLE &&
+ oldPhoneNumber.getCountryCode() != newPhoneNumber.getCountryCode()) {
+ isOldNumberToRemove = true;
+ }
}
- numberRecord.contactID = tmpContactRecord.value().ID;
- if (!contactDB->number.update(numberRecord)) {
- return false;
+
+ if (isOldNumberToRemove) {
+ // remove old number from DB table
+ if (!contactDB->number.removeById(oldNumberID)) {
+ return false;
+ }
+ }
+ else {
+ // make temporary contact with old number
+ const auto tmpContactRecord = addTemporaryContactForNumber(number);
+ if (!tmpContactRecord.has_value()) {
+ return false;
+ }
+ numberRecord.contactID = tmpContactRecord.value().ID;
+ if (!contactDB->number.update(numberRecord)) {
+ return false;
+ }
}
}
}
@@ 195,8 220,9 @@ auto ContactRecordInterface::Update(const ContactRecord &rec) -> bool
return true;
}
-auto ContactRecordInterface::getNumbersIDs(std::uint32_t contactID, const ContactRecord &contact)
- -> std::vector<std::uint32_t>
+auto ContactRecordInterface::getNumbersIDs(std::uint32_t contactID,
+ const ContactRecord &contact,
+ utils::PhoneNumber::Match matchLevel) -> std::vector<std::uint32_t>
{
std::vector<std::uint32_t> result;
@@ 213,7 239,7 @@ auto ContactRecordInterface::getNumbersIDs(std::uint32_t contactID, const Contac
return {};
}
- auto numberMatch = numberMatcher.bestMatch(phoneNumber, utils::PhoneNumber::Match::POSSIBLE);
+ auto numberMatch = numberMatcher.bestMatch(phoneNumber, matchLevel);
if (!numberMatch.has_value()) {
// number does not exist in the DB yet. Let's add it.
if (!contactDB->number.add(ContactsNumberTableRow{Record(DB_ID_NONE),
M module-db/Interface/ContactRecord.hpp => module-db/Interface/ContactRecord.hpp +4 -1
@@ 289,7 289,10 @@ class ContactRecordInterface : public RecordInterface<ContactRecord, ContactReco
-> const std::unique_ptr<db::QueryResult>;
auto addTemporaryContactForNumber(const ContactRecord::Number &number) -> std::optional<ContactRecord>;
- auto getNumbersIDs(std::uint32_t contactID, const ContactRecord &contact) -> std::vector<std::uint32_t>;
+ auto getNumbersIDs(std::uint32_t contactID,
+ const ContactRecord &contact,
+ utils::PhoneNumber::Match matchLevel = utils::PhoneNumber::Match::POSSIBLE)
+ -> std::vector<std::uint32_t>;
auto addNumbers(std::uint32_t contactID, const std::vector<ContactRecord::Number> &numbers)
-> std::optional<std::string>;
auto addOrUpdateName(std::uint32_t contactID, std::uint32_t nameID, const ContactRecord &contact)
M module-db/tests/ContactsRecord_tests.cpp => module-db/tests/ContactsRecord_tests.cpp +255 -1
@@ 264,7 264,12 @@ TEST_CASE("Contact record numbers update")
auto records = ContactRecordInterface(&contactDB);
ContactRecord testRecord, otherRecord;
- std::array<std::string, 4> numbers = {{{"600100100"}, {"600100200"}, {"600100300"}, {"600100400"}}};
+ std::array<std::string, 4> numbers = {{{"600100100"}, {"600100200"}, {"600100300"}, {"600100400"}}};
+ std::array<std::string, 4> numbersPL = {
+ {{"+48600100100"}, {"+48600100200"}, {"+48600100300"}, {"+48600100400"}}}; // Poland country code
+ std::array<std::string, 4> numbersFR = {
+ {{"+33600100100"}, {"+33600100200"}, {"+33600100300"}, {"+33600100400"}}}; // France country code
+ std::array<std::string, 2> unUsedNumbers = {{{"612130140"}, {"612130141"}}};
testRecord.primaryName = "number";
testRecord.alternativeName = "test";
@@ 369,6 374,223 @@ TEST_CASE("Contact record numbers update")
REQUIRE(validatationRecord.numbers[0].number.getEntered() == numbers[3]);
}
+ SECTION("Single number update - new unused number")
+ {
+ auto newRecord = records.GetByID(1);
+ REQUIRE(newRecord.numbers.size() == 2);
+
+ newRecord.numbers =
+ std::vector<ContactRecord::Number>({ContactRecord::Number(unUsedNumbers[0], std::string("")),
+ ContactRecord::Number(numbers[1], std::string(""))});
+ REQUIRE(records.Update(newRecord));
+ REQUIRE(contactDB.contacts.count() == 2); // amount of non-temporary contacts
+ REQUIRE(contactDB.number.count() == 5);
+ REQUIRE(contactDB.number.getById(1).contactID != 1); // old numbers do not belong to any contact
+ REQUIRE(contactDB.number.getById(1).contactID != 2);
+
+ auto validationRecord = records.GetByID(1);
+ REQUIRE(validationRecord.numbers.size() == 2);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == unUsedNumbers[0]);
+ REQUIRE(validationRecord.numbers[1].number.getEntered() == numbers[1]);
+
+ validationRecord = records.GetByID(2);
+ REQUIRE(validationRecord.numbers.size() == 2);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == numbers[2]);
+ REQUIRE(validationRecord.numbers[1].number.getEntered() == numbers[3]);
+
+ // A temporary contact for number[0] (which was previously assigned to recordID=1) has been created.
+ validationRecord = records.GetByIdWithTemporary(3);
+ REQUIRE(validationRecord.ID != DB_ID_NONE);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == numbers[0]);
+ }
+
+ SECTION("Single number update twice - new unused number")
+ {
+ auto newRecord = records.GetByID(1);
+ REQUIRE(newRecord.numbers.size() == 2);
+
+ newRecord.numbers =
+ std::vector<ContactRecord::Number>({ContactRecord::Number(unUsedNumbers[0], std::string("")),
+ ContactRecord::Number(numbers[1], std::string(""))});
+ REQUIRE(records.Update(newRecord));
+
+ newRecord.numbers =
+ std::vector<ContactRecord::Number>({ContactRecord::Number(unUsedNumbers[1], std::string("")),
+ ContactRecord::Number(numbers[1], std::string(""))});
+ REQUIRE(records.Update(newRecord));
+ REQUIRE(contactDB.contacts.count() == 2); // amount of non-temporary contacts
+ REQUIRE(contactDB.number.count() == 6);
+ REQUIRE(contactDB.number.getById(1).contactID != 1); // old numbers do not belong to any contact
+ REQUIRE(contactDB.number.getById(1).contactID != 2);
+ REQUIRE(contactDB.number.getById(5).contactID != 1);
+ REQUIRE(contactDB.number.getById(5).contactID != 2);
+
+ auto validationRecord = records.GetByID(1);
+ REQUIRE(validationRecord.numbers.size() == 2);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == unUsedNumbers[1]);
+ REQUIRE(validationRecord.numbers[1].number.getEntered() == numbers[1]);
+
+ validationRecord = records.GetByID(2);
+ REQUIRE(validationRecord.numbers.size() == 2);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == numbers[2]);
+ REQUIRE(validationRecord.numbers[1].number.getEntered() == numbers[3]);
+
+ // A temporary contact for number ID 1 (which was previously assigned to recordID=1) has been created.
+ validationRecord = records.GetByIdWithTemporary(3);
+ REQUIRE(validationRecord.ID != DB_ID_NONE);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == numbers[0]);
+
+ // A temporary contact for numberID 5 (which was previously assigned to recordID=1 for a moment) has been
+ // created.
+ validationRecord = records.GetByIdWithTemporary(4);
+ REQUIRE(validationRecord.ID != DB_ID_NONE);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == unUsedNumbers[0]);
+ }
+
+ SECTION("Both numbers update - new newer used number")
+ {
+ auto newRecord = records.GetByID(1);
+ REQUIRE(newRecord.numbers.size() == 2);
+
+ newRecord.numbers =
+ std::vector<ContactRecord::Number>({ContactRecord::Number(unUsedNumbers[0], std::string("")),
+ ContactRecord::Number(unUsedNumbers[1], std::string(""))});
+ REQUIRE(records.Update(newRecord));
+ REQUIRE(contactDB.contacts.count() == 2); // amount of non-temporary contacts
+ REQUIRE(contactDB.number.count() == 6);
+ REQUIRE(contactDB.number.getById(1).contactID != 1); // old numbers do not belong to any contact
+ REQUIRE(contactDB.number.getById(1).contactID != 2);
+ REQUIRE(contactDB.number.getById(2).contactID != 1);
+ REQUIRE(contactDB.number.getById(2).contactID != 2);
+
+ auto validationRecord = records.GetByID(1);
+ REQUIRE(validationRecord.numbers.size() == 2);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == unUsedNumbers[0]);
+ REQUIRE(validationRecord.numbers[1].number.getEntered() == unUsedNumbers[1]);
+
+ validationRecord = records.GetByID(2);
+ REQUIRE(validationRecord.numbers.size() == 2);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == numbers[2]);
+ REQUIRE(validationRecord.numbers[1].number.getEntered() == numbers[3]);
+
+ // A temporary contact for number ID 1 (which was previously assigned to recordID=1) has been created.
+ validationRecord = records.GetByIdWithTemporary(3);
+ REQUIRE(validationRecord.ID != DB_ID_NONE);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == numbers[0]);
+
+ // A temporary contact for numberID 2 (which was previously assigned to recordID=1) has been created.
+ validationRecord = records.GetByIdWithTemporary(4);
+ REQUIRE(validationRecord.ID != DB_ID_NONE);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == numbers[1]);
+ }
+
+ SECTION("Single number update - add country code")
+ {
+ auto newRecord = records.GetByID(1);
+ REQUIRE(newRecord.numbers.size() == 2);
+
+ newRecord.numbers = std::vector<ContactRecord::Number>(
+ {ContactRecord::Number(numbersPL[0], std::string("")), ContactRecord::Number(numbers[1], std::string(""))});
+ REQUIRE(records.Update(newRecord));
+ REQUIRE(contactDB.number.count() == 4);
+
+ auto validationRecord = records.GetByID(1);
+ REQUIRE(validationRecord.numbers.size() == 2);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == numbersPL[0]);
+ REQUIRE(validationRecord.numbers[1].number.getEntered() == numbers[1]);
+
+ validationRecord = records.GetByID(2);
+ REQUIRE(validationRecord.numbers.size() == 2);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == numbers[2]);
+ REQUIRE(validationRecord.numbers[1].number.getEntered() == numbers[3]);
+
+ // there is no new temporary number
+ validationRecord = records.GetByIdWithTemporary(3);
+ REQUIRE(validationRecord.ID == DB_ID_NONE);
+ REQUIRE(validationRecord.numbers.empty());
+ }
+
+ SECTION("Single number update - change country code")
+ {
+ auto newRecord = records.GetByID(1);
+ REQUIRE(newRecord.numbers.size() == 2);
+
+ newRecord.numbers = std::vector<ContactRecord::Number>({ContactRecord::Number(numbersPL[0], std::string("")),
+ ContactRecord::Number(numbersPL[1], std::string(""))});
+ REQUIRE(records.Update(newRecord));
+ REQUIRE(contactDB.number.count() == 4);
+
+ auto validationRecord = records.GetByID(1);
+ REQUIRE(validationRecord.numbers.size() == 2);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == numbersPL[0]);
+ REQUIRE(validationRecord.numbers[1].number.getEntered() == numbersPL[1]);
+ REQUIRE(contactDB.contacts.count() == 2); // amount of non-temporary contacts
+
+ newRecord.numbers = std::vector<ContactRecord::Number>({ContactRecord::Number(numbersFR[0], std::string("")),
+ ContactRecord::Number(numbersPL[1], std::string(""))});
+ REQUIRE(records.Update(newRecord));
+ REQUIRE(contactDB.number.count() == 5);
+
+ validationRecord = records.GetByID(1);
+ REQUIRE(validationRecord.numbers.size() == 2);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == numbersFR[0]);
+ REQUIRE(validationRecord.numbers[1].number.getEntered() == numbersPL[1]);
+
+ validationRecord = records.GetByID(2);
+ REQUIRE(validationRecord.numbers.size() == 2);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == numbers[2]);
+ REQUIRE(validationRecord.numbers[1].number.getEntered() == numbers[3]);
+
+ // There is new temporary contact for number[0] (which was previously assigned to recordID=1) with
+ // old country code
+ validationRecord = records.GetByIdWithTemporary(3);
+ REQUIRE(validationRecord.ID != DB_ID_NONE);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == numbersPL[0]);
+
+ // There is new temporary contact for number[1] (which was previously assigned to recordID=1) with
+ // old country code
+ validationRecord = records.GetByIdWithTemporary(4);
+ REQUIRE(validationRecord.ID == DB_ID_NONE);
+ REQUIRE(validationRecord.numbers.empty());
+ }
+
+ SECTION("Both number update - remove country code")
+ {
+ auto newRecord = records.GetByID(1);
+ REQUIRE(newRecord.numbers.size() == 2);
+
+ newRecord.numbers = std::vector<ContactRecord::Number>({ContactRecord::Number(numbersPL[0], std::string("")),
+ ContactRecord::Number(numbersFR[1], std::string(""))});
+ REQUIRE(records.Update(newRecord));
+ REQUIRE(contactDB.number.count() == 4);
+
+ auto validationRecord = records.GetByID(1);
+ REQUIRE(validationRecord.numbers.size() == 2);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == numbersPL[0]);
+ REQUIRE(validationRecord.numbers[1].number.getEntered() == numbersFR[1]);
+ REQUIRE(contactDB.contacts.count() == 2); // amount of non-temporary contacts
+
+ newRecord.numbers = std::vector<ContactRecord::Number>(
+ {ContactRecord::Number(numbers[0], std::string("")), ContactRecord::Number(numbers[1], std::string(""))});
+ REQUIRE(records.Update(newRecord));
+ REQUIRE(contactDB.number.count() == 4);
+
+ validationRecord = records.GetByID(1);
+ REQUIRE(validationRecord.numbers.size() == 2);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == numbers[0]);
+ REQUIRE(validationRecord.numbers[1].number.getEntered() == numbers[1]);
+
+ validationRecord = records.GetByID(2);
+ REQUIRE(validationRecord.numbers.size() == 2);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == numbers[2]);
+ REQUIRE(validationRecord.numbers[1].number.getEntered() == numbers[3]);
+
+ // There is no new temporary number
+ validationRecord = records.GetByIdWithTemporary(3);
+ REQUIRE(validationRecord.ID == DB_ID_NONE);
+ REQUIRE(validationRecord.numbers.empty());
+ }
+
SECTION("Change both numbers")
{
auto newRecord = records.GetByID(1);
@@ 400,6 622,38 @@ TEST_CASE("Contact record numbers update")
REQUIRE(validationRecord.numbers[0].number.getEntered() == numbers[1]);
}
+ SECTION("Change both numbers - same number with different country code")
+ {
+ auto newRecord = records.GetByID(1);
+ REQUIRE(newRecord.numbers.size() == 2);
+
+ newRecord.numbers = std::vector<ContactRecord::Number>({ContactRecord::Number(numbersPL[0], std::string("")),
+ ContactRecord::Number(numbersFR[0], std::string(""))});
+ REQUIRE(records.Update(newRecord));
+ REQUIRE(contactDB.number.count() == 5);
+
+ auto validationRecord = records.GetByIdWithTemporary(1);
+ REQUIRE(validationRecord.ID != DB_ID_NONE);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == numbersPL[0]);
+ REQUIRE(validationRecord.numbers[1].number.getEntered() == numbersFR[0]);
+ REQUIRE(contactDB.contacts.count() == 2); // amount of non-temporary contacts
+
+ validationRecord = records.GetByID(2);
+ REQUIRE(validationRecord.numbers.size() == 2);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == numbers[2]);
+ REQUIRE(validationRecord.numbers[1].number.getEntered() == numbers[3]);
+
+ // A temporary contact for number[1] (which was previously assigned to recordID=1) has been created.
+ validationRecord = records.GetByIdWithTemporary(3);
+ REQUIRE(validationRecord.ID != DB_ID_NONE);
+ REQUIRE(validationRecord.numbers[0].number.getEntered() == numbers[1]);
+
+ // There is no new temporary number
+ validationRecord = records.GetByIdWithTemporary(4);
+ REQUIRE(validationRecord.ID == DB_ID_NONE);
+ REQUIRE(validationRecord.numbers.empty());
+ }
+
Database::deinitialize();
}
M pure_changelog.md => pure_changelog.md +1 -0
@@ 41,6 41,7 @@
* Fixed windows flow regarding PUK requests after too many PIN mistakes
* Fixed disappearing "confirm" button in PIN entering screen
* Fixed looping on the SIM card selection screen
+* Fixed adding country code prefix to existing contact
### Added
* Added a popup for changing the SIM card