Fixed edit contact groups list after labels changes.

MAILAND-1525
This commit is contained in:
Tomasz Giszczak 2021-09-01 16:01:10 +02:00 committed by stefanija
parent 7c70fdcf77
commit b1af58877a
15 changed files with 280 additions and 321 deletions

View File

@ -348,7 +348,7 @@ internal class ContactDaoTest {
}
@Test
fun saveContactEmail() {
fun saveContactEmail() = runBlocking {
val inserted = ContactEmail(
"z",
"z@z.com",

View File

@ -177,7 +177,8 @@ class ProtonMailApiManager @Inject constructor(var api: ProtonMailApi) :
override suspend fun deleteContact(contactIds: IDList): DeleteResponse = api.deleteContact(contactIds)
override fun labelContacts(labelContactsBody: LabelContactsBody): Completable = api.labelContacts(labelContactsBody)
override suspend fun labelContacts(labelContactsBody: LabelContactsBody) =
api.labelContacts(labelContactsBody)
override fun unlabelContactEmailsCompletable(labelContactsBody: LabelContactsBody): Completable =
api.unlabelContactEmailsCompletable(labelContactsBody)

View File

@ -37,8 +37,7 @@ import io.reactivex.Single
import java.io.IOException
class ContactApi(private val service: ContactService) : BaseApi(), ContactApiSpec {
@Throws(IOException::class)
override fun labelContacts(labelContactsBody: LabelContactsBody): Completable =
override suspend fun labelContacts(labelContactsBody: LabelContactsBody) =
service.labelContacts(labelContactsBody)
@Throws(IOException::class)

View File

@ -62,8 +62,7 @@ interface ContactApiSpec {
suspend fun deleteContact(contactIds: IDList): DeleteResponse
@Throws(IOException::class)
fun labelContacts(labelContactsBody: LabelContactsBody): Completable
suspend fun labelContacts(labelContactsBody: LabelContactsBody)
@Throws(IOException::class)
fun unlabelContactEmailsCompletable(labelContactsBody: LabelContactsBody): Completable

View File

@ -93,7 +93,7 @@ interface ContactService {
@PUT("contacts/emails/label")
@Headers(CONTENT_TYPE, ACCEPT_HEADER_V1)
fun labelContacts(@Body labelContactsBody: LabelContactsBody): Completable
suspend fun labelContacts(@Body labelContactsBody: LabelContactsBody)
@PUT("contacts/emails/unlabel")
@Headers(CONTENT_TYPE, ACCEPT_HEADER_V1)

View File

@ -31,9 +31,7 @@ import ch.protonmail.android.labels.data.model.LabelResponse
import ch.protonmail.android.worker.CreateContactGroupWorker
import ch.protonmail.android.worker.RemoveMembersFromContactGroupWorker
import com.birbit.android.jobqueue.JobManager
import io.reactivex.Completable
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.runBlocking
import me.proton.core.domain.entity.UserId
import me.proton.core.network.domain.ApiResult
import timber.log.Timber
@ -73,29 +71,30 @@ class ContactGroupEditCreateRepository @Inject constructor(
fun getContactGroupEmails(id: String): Flow<List<ContactEmail>> =
contactRepository.observeAllContactEmailsByContactGroupId(id)
fun removeMembersFromContactGroup(
suspend fun removeMembersFromContactGroup(
contactGroupId: String,
contactGroupName: String,
membersList: List<String>
): Completable {
) {
if (membersList.isEmpty()) {
return Completable.complete()
Timber.v("No group members to remove")
return
}
val labelContactsBody = LabelContactsBody(contactGroupId, membersList)
return apiManager.unlabelContactEmailsCompletable(labelContactsBody)
.doOnComplete {
runBlocking {
val contactEmails =
contactRepository.findAllContactEmailsByContactGroupId(contactGroupId)
contactEmails.forEach { contactEmail ->
val updatedList = contactEmail.labelIds?.toMutableList()
if (updatedList != null) {
updatedList.remove(contactGroupName)
contactRepository.saveContactEmail(contactEmail.copy(labelIds = updatedList))
}
runCatching {
val labelContactsBody = LabelContactsBody(contactGroupId, membersList)
apiManager.unlabelContactEmails(labelContactsBody)
}.fold(
onSuccess = {
val contactEmails = contactRepository.findAllContactEmailsByContactGroupId(contactGroupId)
contactEmails.forEach { contactEmail ->
val updatedList = contactEmail.labelIds?.toMutableList()
if (updatedList != null) {
updatedList.remove(contactGroupName)
contactRepository.saveContactEmail(contactEmail.copy(labelIds = updatedList))
}
}
}.doOnError { throwable ->
},
onFailure = { throwable ->
if (throwable is IOException) {
RemoveMembersFromContactGroupWorker.Enqueuer(workManager).enqueue(
contactGroupId,
@ -104,38 +103,41 @@ class ContactGroupEditCreateRepository @Inject constructor(
)
}
}
)
}
fun setMembersForContactGroup(
suspend fun setMembersForContactGroup(
contactGroupId: String,
contactGroupName: String,
membersList: List<String>
): Completable {
) {
if (membersList.isEmpty()) {
return Completable.complete()
Timber.v("No group members to update")
return
}
val labelContactsBody = LabelContactsBody(contactGroupId, membersList)
return apiManager.labelContacts(labelContactsBody)
.doOnComplete {
runBlocking {
val contactEmails =
contactRepository.findAllContactEmailsByContactGroupId(contactGroupId)
contactEmails.forEach { contactEmail ->
val updatedList = contactEmail.labelIds?.toMutableList()
if (updatedList != null) {
updatedList.add(contactGroupName)
contactRepository.saveContactEmail(contactEmail.copy(labelIds = updatedList))
}
Timber.v("Set contact Members contactGroupId: $contactGroupId, contactGroupName: $contactGroupName")
runCatching {
val labelContactsBody = LabelContactsBody(contactGroupId, membersList)
apiManager.labelContacts(labelContactsBody)
}.fold(
onSuccess = {
val contactEmails = contactRepository.findAllContactEmailsByContactGroupId(contactGroupId)
contactEmails.forEach { contactEmail ->
val updatedList = contactEmail.labelIds?.toMutableList()
if (updatedList != null) {
updatedList.add(contactGroupName)
contactRepository.saveContactEmail(contactEmail.copy(labelIds = updatedList))
}
}
}
.doOnError { throwable ->
},
onFailure = { throwable ->
if (throwable is IOException) {
jobManager.addJobInBackground(
SetMembersForContactGroupJob(contactGroupId, contactGroupName, membersList, labelRepository)
)
}
}
)
}
suspend fun createContactGroup(contactLabel: LabelEntity, userId: UserId): ApiResult<LabelResponse> {

View File

@ -19,7 +19,6 @@
package ch.protonmail.android.contacts.groups.jobs
import ch.protonmail.android.api.models.contacts.send.LabelContactsBody
import ch.protonmail.android.api.rx.ThreadSchedulers
import ch.protonmail.android.core.Constants
import ch.protonmail.android.jobs.Priority
import ch.protonmail.android.jobs.ProtonMailBaseJob
@ -42,10 +41,9 @@ class SetMembersForContactGroupJob(
id = contactLabel?.id?.id ?: ""
}
}
val labelContactsBody = LabelContactsBody(id, membersList)
getApi().labelContacts(labelContactsBody)
.subscribeOn(ThreadSchedulers.io())
.observeOn(ThreadSchedulers.io())
.blockingAwait()
runBlocking {
val labelContactsBody = LabelContactsBody(id, membersList)
getApi().labelContacts(labelContactsBody)
}
}
}

View File

@ -79,7 +79,7 @@ class ContactsRepository @Inject constructor(
fun observeFilterContactEmailsByContactGroup(groupLabelId: String, filter: String): Flow<List<ContactEmail>> =
contactDao.observeFilterContactEmailsByContactGroup(groupLabelId.take(IMPORTANT_LABEL_CHARACTERS_COUNT), filter)
fun saveContactEmail(contactEmail: ContactEmail) =
suspend fun saveContactEmail(contactEmail: ContactEmail) =
contactDao.saveContactEmail(contactEmail)
private suspend fun getUniqueContactGroupsIds(): Set<String> {

View File

@ -153,7 +153,7 @@ interface ContactDao {
fun deleteAllContactsEmails(contactEmail: Collection<ContactEmail>)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun saveContactEmail(contactEmail: ContactEmail): Long
suspend fun saveContactEmail(contactEmail: ContactEmail): Long
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun saveAllContactsEmails(emailData: Collection<ContactEmail>): List<Long>
@ -183,7 +183,7 @@ interface ContactDao {
"""
SELECT * FROM $TABLE_CONTACT_EMAILS
WHERE $COLUMN_CONTACT_EMAILS_LABEL_IDS LIKE '%' || :contactGroupId || '%'
AND $COLUMN_CONTACT_EMAILS_EMAIL LIKE :filter
AND $COLUMN_CONTACT_EMAILS_EMAIL LIKE '%' || :filter || '%'
"""
)
fun observeFilterContactEmailsByContactGroup(contactGroupId: String, filter: String): Flow<List<ContactEmail>>

View File

@ -343,15 +343,9 @@ class ConvertLocalContactsJob(
contactDao.saveAllContactsEmailsBlocking(contact.emails!!)
contactGroupIds.forEach { contactGroupId ->
val emailsList = contact.emails!!.map { it.contactEmailId }
getApi().labelContacts(LabelContactsBody(contactGroupId, emailsList))
.doOnComplete {
//val joins = contactDao.fetchJoinsBlocking(contactGroupId) as ArrayList
for (contactEmail in emailsList) {
// joins.add(ContactEmailContactLabelJoin(contactEmail, contactGroupId))
}
//contactDao.saveContactEmailContactLabelBlocking(joins)
}
.blockingAwait()
runBlocking {
getApi().labelContacts(LabelContactsBody(contactGroupId, emailsList))
}
}
}
return ContactEvent.SUCCESS

View File

@ -1,257 +0,0 @@
/*
* Copyright (c) 2020 Proton Technologies AG
*
* This file is part of ProtonMail.
*
* ProtonMail is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonMail is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonMail. If not, see https://www.gnu.org/licenses/.
*/
package ch.protonmail.android.jobs;
import static ch.protonmail.android.api.segments.BaseApiKt.RESPONSE_CODE_ERROR_EMAIL_DUPLICATE_FAILED;
import static ch.protonmail.android.api.segments.BaseApiKt.RESPONSE_CODE_ERROR_EMAIL_EXIST;
import static ch.protonmail.android.api.segments.BaseApiKt.RESPONSE_CODE_ERROR_INVALID_EMAIL;
import android.database.sqlite.SQLiteBlobTooBigException;
import androidx.annotation.NonNull;
import com.birbit.android.jobqueue.Params;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import ch.protonmail.android.api.models.ContactEncryptedData;
import ch.protonmail.android.api.models.CreateContactV2BodyItem;
import ch.protonmail.android.api.models.contacts.send.LabelContactsBody;
import ch.protonmail.android.api.rx.ThreadSchedulers;
import ch.protonmail.android.contacts.details.presentation.model.ContactLabelUiModel;
import ch.protonmail.android.contacts.groups.jobs.SetMembersForContactGroupJob;
import ch.protonmail.android.core.Constants;
import ch.protonmail.android.crypto.CipherText;
import ch.protonmail.android.crypto.Crypto;
import ch.protonmail.android.crypto.UserCrypto;
import ch.protonmail.android.data.local.ContactDao;
import ch.protonmail.android.data.local.ContactDatabase;
import ch.protonmail.android.data.local.model.ContactData;
import ch.protonmail.android.data.local.model.ContactEmail;
import ch.protonmail.android.data.local.model.FullContactDetails;
import ch.protonmail.android.data.local.model.FullContactDetailsResponse;
import ch.protonmail.android.events.ContactEvent;
import ch.protonmail.android.labels.data.LabelRepository;
import ch.protonmail.android.utils.AppUtil;
import ezvcard.Ezvcard;
import ezvcard.VCard;
import ezvcard.property.Email;
import timber.log.Timber;
public class UpdateContactJob extends ProtonMailEndlessJob {
private final String mContactId;
private final String mContactName;
private final List<ContactEmail> mContactEmails;
private final String mEncryptedData;
private final String mSignedData;
private final Map<ContactEmail, List<ContactLabelUiModel>> mMapEmailGroupsIds;
private final LabelRepository labelRepository;
private transient ContactDao mContactDao;
public UpdateContactJob(
String contactId,
@NonNull String contactName,
@NonNull List<ContactEmail> contactEmails,
String encryptedData,
String signedData,
Map<ContactEmail, List<ContactLabelUiModel>> mapEmailGroupsIds,
LabelRepository labelRepository
) {
super(new Params(Priority.MEDIUM).requireNetwork().persist().groupBy(Constants.JOB_GROUP_CONTACT));
mContactId = contactId;
mContactName = contactName;
mContactEmails = contactEmails;
mEncryptedData = encryptedData;
mSignedData = signedData;
mMapEmailGroupsIds = mapEmailGroupsIds;
this.labelRepository = labelRepository;
}
@Override
public void onAdded() {
UserCrypto crypto = Crypto.forUser(getUserManager(), getUserId());
try {
CipherText tct = crypto.encrypt(mEncryptedData, false);
String encryptedDataSignature = crypto.sign(mEncryptedData);
String signedDataSignature = crypto.sign(mSignedData);
updateContact(mContactName, mContactEmails, tct.getArmored(), encryptedDataSignature, signedDataSignature, false);
AppUtil.postEventOnUi(new ContactEvent(ContactEvent.SAVED, true));
} catch (Exception e) {
e.printStackTrace();
}
if (!getQueueNetworkUtil().isConnected()) {
AppUtil.postEventOnUi(new ContactEvent(ContactEvent.NO_NETWORK, true));
}
}
@Override
public void onRun() throws Throwable {
UserCrypto crypto = Crypto.forUser(getUserManager(), getUserId());
requireContactDao();
CipherText tct = crypto.encrypt(mEncryptedData, false);
String encryptedDataSignature = crypto.sign(mEncryptedData);
String signedDataSignature = crypto.sign(mSignedData);
CreateContactV2BodyItem body = new CreateContactV2BodyItem(mSignedData, signedDataSignature,
tct.getArmored(), encryptedDataSignature);
FullContactDetailsResponse response = getApi().updateContact(mContactId, body);
if (response != null) {
Timber.v("Update contacts response code:%s error:%s", response.getCode(), response.getError());
if (response.getCode() == RESPONSE_CODE_ERROR_EMAIL_EXIST) {
// TODO: 9/14/17 todoContacts throw error
AppUtil.postEventOnUi(new ContactEvent(ContactEvent.ALREADY_EXIST, true));
} else if (response.getCode() == RESPONSE_CODE_ERROR_INVALID_EMAIL) {
// TODO: 9/14/17 todoContacts throw error
AppUtil.postEventOnUi(new ContactEvent(ContactEvent.INVALID_EMAIL, true));
} else if (response.getCode() == RESPONSE_CODE_ERROR_EMAIL_DUPLICATE_FAILED) {
AppUtil.postEventOnUi(new ContactEvent(ContactEvent.DUPLICATE_EMAIL, true));
} else {
updateContact(mContactName, response.getContact().getEmails(), tct.getArmored(), encryptedDataSignature, signedDataSignature, true);
AppUtil.postEventOnUi(new ContactEvent(ContactEvent.SUCCESS, true));
}
}
}
private void updateContact(
@NonNull String contactName,
@NonNull List<ContactEmail> contactEmails,
String encryptedData,
String encryptedDataSignature,
String signedDataSignature,
boolean updateJoins
) {
requireContactDao();
final ContactData contactData = mContactDao.findContactDataById(mContactId);
if (contactData != null) {
contactData.setName(contactName);
mContactDao.saveContactData(contactData);
}
List<ContactEmail> emails = mContactDao.findContactEmailsByContactIdBlocking(mContactId);
mContactDao.deleteAllContactsEmails(emails);
for (ContactEmail email : contactEmails) {
final String emailToClear = email.getEmail();
mContactDao.clearByEmailBlocking(emailToClear);
}
mContactDao.saveAllContactsEmailsBlocking(contactEmails);
Map<ContactLabelUiModel, List<String>> mapContactGroupContactEmails = new HashMap<>();
if (updateJoins) {
for (ContactEmail email : contactEmails) {
List<ContactLabelUiModel> labels = findContactLabelsByEmail(email);
for (ContactLabelUiModel label : labels) {
List<String> labelEmails = mapContactGroupContactEmails.get(label);
if (labelEmails == null) {
labelEmails = new ArrayList<>();
}
labelEmails.add(email.getContactEmailId());
mapContactGroupContactEmails.put(label, labelEmails);
}
}
}
FullContactDetails contact = null;
try {
contact = mContactDao.findFullContactDetailsByIdBlocking(mContactId);
} catch (SQLiteBlobTooBigException tooBigException) {
Timber.i(tooBigException,"Data too big to be fetched");
}
if (contact != null) {
ContactEncryptedData contactEncryptedData = new ContactEncryptedData(encryptedData, encryptedDataSignature, Constants.VCardType.SIGNED_ENCRYPTED);
ContactEncryptedData contactSignedData = new ContactEncryptedData(mSignedData, signedDataSignature, Constants.VCardType.SIGNED);
ContactEncryptedData contactEncryptedDataType0 = null;
List<ContactEncryptedData> contactEncryptedDataList = contact.getEncryptedData();
for (ContactEncryptedData data : contactEncryptedDataList) {
if (data.getType() == 0) {
contactEncryptedDataType0 = data;
break;
}
}
if (contactEncryptedDataType0 != null) {
String vCardType0String = contactEncryptedDataType0.getData();
final VCard vCardType0 = vCardType0String != null ? Ezvcard.parse(vCardType0String).first() : null;
List<Email> emailsType0 = vCardType0.getEmails();
vCardType0.getEmails().removeAll(emailsType0);
contact.addEncryptedData(new ContactEncryptedData(vCardType0.write(), "", Constants.VCardType.UNSIGNED));
}
contact.addEncryptedData(contactSignedData);
contact.addEncryptedData(contactEncryptedData);
contact.setName(contactName);
contact.setEmails(contactEmails);
mContactDao.insertFullContactDetailsBlocking(contact);
if (updateJoins) {
for (Map.Entry<ContactLabelUiModel, List<String>> entry : mapContactGroupContactEmails.entrySet()) {
updateJoins(entry.getKey().getId().getId(), entry.getKey().getName(), entry.getValue());
}
} else {
AppUtil.postEventOnUi(new ContactEvent(ContactEvent.SAVED, true));
}
}
}
private void updateJoins(String contactGroupId, String contactGroupName, List<String> membersList) {
LabelContactsBody labelContactsBody = new LabelContactsBody(contactGroupId, membersList);
try {
getApi().labelContacts(labelContactsBody)
.doOnComplete(() -> {
//List<ContactEmailContactLabelJoin> joins = mContactDao.fetchJoinsBlocking(contactGroupId);
for (String contactEmail : membersList) {
// joins.add(new ContactEmailContactLabelJoin(contactEmail, contactGroupId));
}
//mContactDao.saveContactEmailContactLabelBlocking(joins);
})
.doOnError(throwable ->
getJobManager().addJobInBackground(
new SetMembersForContactGroupJob(contactGroupId, contactGroupName, membersList, labelRepository)
)
)
.subscribeOn(ThreadSchedulers.io())
.observeOn(ThreadSchedulers.io())
.subscribe();
} catch (Exception e) {
AppUtil.postEventOnUi(new ContactEvent(ContactEvent.ERROR, false));
}
}
private List<ContactLabelUiModel> findContactLabelsByEmail(ContactEmail contactEmail) {
for (Map.Entry<ContactEmail, List<ContactLabelUiModel>> entry : mMapEmailGroupsIds.entrySet()) {
if (entry.getKey().getEmail().equals(contactEmail.getEmail())) {
return entry.getValue();
}
}
return Collections.emptyList();
}
private void requireContactDao() {
if (mContactDao == null) {
mContactDao = ContactDatabase.Companion
.getInstance(getApplicationContext(), getUserId())
.getDao();
}
}
}

View File

@ -0,0 +1,215 @@
/*
* Copyright (c) 2020 Proton Technologies AG
*
* This file is part of ProtonMail.
*
* ProtonMail is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonMail is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonMail. If not, see https://www.gnu.org/licenses/.
*/
package ch.protonmail.android.jobs
import android.database.sqlite.SQLiteBlobTooBigException
import ch.protonmail.android.api.models.ContactEncryptedData
import ch.protonmail.android.api.models.CreateContactV2BodyItem
import ch.protonmail.android.api.models.contacts.send.LabelContactsBody
import ch.protonmail.android.api.segments.RESPONSE_CODE_ERROR_EMAIL_DUPLICATE_FAILED
import ch.protonmail.android.api.segments.RESPONSE_CODE_ERROR_EMAIL_EXIST
import ch.protonmail.android.api.segments.RESPONSE_CODE_ERROR_INVALID_EMAIL
import ch.protonmail.android.contacts.details.presentation.model.ContactLabelUiModel
import ch.protonmail.android.contacts.groups.jobs.SetMembersForContactGroupJob
import ch.protonmail.android.core.Constants
import ch.protonmail.android.crypto.Crypto.Companion.forUser
import ch.protonmail.android.data.local.ContactDao
import ch.protonmail.android.data.local.ContactDatabase
import ch.protonmail.android.data.local.model.ContactEmail
import ch.protonmail.android.data.local.model.FullContactDetails
import ch.protonmail.android.events.ContactEvent
import ch.protonmail.android.labels.data.LabelRepository
import ch.protonmail.android.utils.AppUtil
import com.birbit.android.jobqueue.Params
import ezvcard.Ezvcard
import kotlinx.coroutines.runBlocking
import timber.log.Timber
import java.util.ArrayList
import java.util.HashMap
class UpdateContactJob(
private val contactId: String,
private val contactName: String,
private val contactEmails: List<ContactEmail>,
private val encryptedData: String,
private val signedData: String,
private val mapEmailGroupsIds: Map<ContactEmail, List<ContactLabelUiModel>>,
private val labelRepository: LabelRepository
) : ProtonMailEndlessJob(Params(Priority.MEDIUM).requireNetwork().persist().groupBy(Constants.JOB_GROUP_CONTACT)) {
@Transient
private var contactDao: ContactDao? = null
override fun onAdded() {
val crypto = forUser(getUserManager(), userId!!)
try {
val tct = crypto.encrypt(encryptedData, false)
val encryptedDataSignature = crypto.sign(encryptedData)
val signedDataSignature = crypto.sign(signedData)
updateContact(contactName, contactEmails, tct.armored, encryptedDataSignature, signedDataSignature, false)
AppUtil.postEventOnUi(ContactEvent(ContactEvent.SAVED, true))
} catch (e: Exception) {
Timber.w(e, "UpdateContact error")
}
if (!getQueueNetworkUtil().isConnected()) {
AppUtil.postEventOnUi(ContactEvent(ContactEvent.NO_NETWORK, true))
}
}
@Throws(Throwable::class)
override fun onRun() {
val crypto = forUser(getUserManager(), userId!!)
requireContactDao()
val tct = crypto.encrypt(encryptedData, false)
val encryptedDataSignature = crypto.sign(encryptedData)
val signedDataSignature = crypto.sign(signedData)
val body = CreateContactV2BodyItem(
signedData, signedDataSignature,
tct.armored, encryptedDataSignature
)
val response = getApi().updateContact(contactId, body)
if (response != null) {
Timber.v("Update contacts response code:%s error:%s", response.code, response.error)
if (response.code == RESPONSE_CODE_ERROR_EMAIL_EXIST) {
// TODO: 9/14/17 todoContacts throw error
AppUtil.postEventOnUi(ContactEvent(ContactEvent.ALREADY_EXIST, true))
} else if (response.code == RESPONSE_CODE_ERROR_INVALID_EMAIL) {
// TODO: 9/14/17 todoContacts throw error
AppUtil.postEventOnUi(ContactEvent(ContactEvent.INVALID_EMAIL, true))
} else if (response.code == RESPONSE_CODE_ERROR_EMAIL_DUPLICATE_FAILED) {
AppUtil.postEventOnUi(ContactEvent(ContactEvent.DUPLICATE_EMAIL, true))
} else {
updateContact(
contactName, response.contact.emails!!, tct.armored, encryptedDataSignature, signedDataSignature,
true
)
AppUtil.postEventOnUi(ContactEvent(ContactEvent.SUCCESS, true))
}
}
}
private fun updateContact(
contactName: String,
contactEmails: List<ContactEmail>,
encryptedData: String,
encryptedDataSignature: String,
signedDataSignature: String,
updateJoins: Boolean
) {
requireContactDao()
val contactData = contactDao!!.findContactDataById(contactId)
if (contactData != null) {
contactData.name = contactName
contactDao!!.saveContactData(contactData)
}
val emails = contactDao!!.findContactEmailsByContactIdBlocking(contactId)
contactDao!!.deleteAllContactsEmails(emails)
for (email in contactEmails) {
val emailToClear = email.email
contactDao!!.clearByEmailBlocking(emailToClear)
}
contactDao!!.saveAllContactsEmailsBlocking(contactEmails)
val mapContactGroupContactEmails: MutableMap<ContactLabelUiModel, MutableList<String>> = HashMap()
if (updateJoins) {
for (email in contactEmails) {
val labels = findContactLabelsByEmail(email)
for (label in labels) {
var labelEmails = mapContactGroupContactEmails[label]
if (labelEmails == null) {
labelEmails = ArrayList()
}
labelEmails.add(email.contactEmailId)
mapContactGroupContactEmails[label] = labelEmails
}
}
}
var contact: FullContactDetails? = null
try {
contact = contactDao!!.findFullContactDetailsByIdBlocking(contactId)
} catch (tooBigException: SQLiteBlobTooBigException) {
Timber.i(tooBigException, "Data too big to be fetched")
}
if (contact != null) {
val contactEncryptedData =
ContactEncryptedData(encryptedData, encryptedDataSignature, Constants.VCardType.SIGNED_ENCRYPTED)
val contactSignedData = ContactEncryptedData(signedData, signedDataSignature, Constants.VCardType.SIGNED)
var contactEncryptedDataType0: ContactEncryptedData? = null
val contactEncryptedDataList: List<ContactEncryptedData>? = contact.encryptedData
for (data in contactEncryptedDataList!!) {
if (data.type == 0) {
contactEncryptedDataType0 = data
break
}
}
if (contactEncryptedDataType0 != null) {
val vCardType0String = contactEncryptedDataType0.data
val vCardType0 = if (vCardType0String != null) Ezvcard.parse(vCardType0String).first() else null
val emailsType0 = vCardType0!!.emails
vCardType0.emails.removeAll(emailsType0)
contact.addEncryptedData(ContactEncryptedData(vCardType0.write(), "", Constants.VCardType.UNSIGNED))
}
contact.addEncryptedData(contactSignedData)
contact.addEncryptedData(contactEncryptedData)
contact.name = contactName
contact.emails = contactEmails
contactDao!!.insertFullContactDetailsBlocking(contact)
if (updateJoins) {
for ((key, value) in mapContactGroupContactEmails) {
updateJoins(key.id.id, key.name, value)
}
} else {
AppUtil.postEventOnUi(ContactEvent(ContactEvent.SAVED, true))
}
}
}
private fun updateJoins(
contactGroupId: String,
contactGroupName: String,
membersList: List<String>
) {
val labelContactsBody = LabelContactsBody(contactGroupId, membersList)
runBlocking {
runCatching {
getApi().labelContacts(labelContactsBody)
}.onFailure {
getJobManager().addJobInBackground(
SetMembersForContactGroupJob(contactGroupId, contactGroupName, membersList, labelRepository)
)
AppUtil.postEventOnUi(ContactEvent(ContactEvent.ERROR, false))
}
}
}
private fun findContactLabelsByEmail(contactEmail: ContactEmail): List<ContactLabelUiModel> {
for ((key, value) in mapEmailGroupsIds) {
if (key.email == contactEmail.email) {
return value
}
}
return emptyList()
}
private fun requireContactDao() {
if (contactDao == null) {
contactDao = ContactDatabase
.getInstance(applicationContext, userId!!)
.getDao()
}
}
}

View File

@ -31,6 +31,7 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.runBlocking
import me.proton.core.domain.entity.UserId
@ -52,6 +53,9 @@ internal class LabelRepositoryImpl @Inject constructor(
fetchAndSaveAllLabels(userId)
}
}
.onEach {
Timber.v("Emitting new labels size: ${it.size} user: $userId")
}
override suspend fun findAllLabels(userId: UserId, shallRefresh: Boolean): List<LabelEntity> =
observeAllLabels(userId, shallRefresh).first()

View File

@ -47,7 +47,11 @@ class LabelApi(private val apiProvider: ApiProvider) : LabelApiSpec {
createLabel(label)
}
override suspend fun updateLabel(userId: UserId, labelId: String, labelRequestBody: LabelRequestBody):
override suspend fun updateLabel(
userId: UserId,
labelId: String,
labelRequestBody: LabelRequestBody
):
ApiResult<LabelResponse> = apiProvider.get<LabelService>(userId).invoke {
updateLabel(labelId, labelRequestBody)
}

View File

@ -100,10 +100,10 @@ class ContactGroupEditCreateRepositoryTest {
name = "name",
color = "color",
type = testType.typeInt,
notify = 0,
notify = null,
parentId = testParentId,
expanded = 0,
sticky = 0
expanded = null,
sticky = null
)
// when