diff --git a/.run/Run Tests.run.xml b/.run/Run Tests.run.xml
new file mode 100644
index 0000000000..42b2e07744
--- /dev/null
+++ b/.run/Run Tests.run.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ false
+ false
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 723d50c758..17eaebf5fe 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Session Android
+# Session Android
[Download on the Google Play Store](https://getsession.org/android)
diff --git a/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt b/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt
index 3fd91f7f63..20dc2bbade 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt
@@ -184,16 +184,21 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper)
override fun deleteMessage(messageID: Long, isSms: Boolean) {
val messagingDatabase: MessagingDatabase = if (isSms) DatabaseComponent.get(context).smsDatabase()
else DatabaseComponent.get(context).mmsDatabase()
+
messagingDatabase.deleteMessage(messageID)
DatabaseComponent.get(context).lokiMessageDatabase().deleteMessage(messageID, isSms)
DatabaseComponent.get(context).lokiMessageDatabase().deleteMessageServerHash(messageID, mms = !isSms)
}
override fun deleteMessages(messageIDs: List, threadId: Long, isSms: Boolean) {
+
val messagingDatabase: MessagingDatabase = if (isSms) DatabaseComponent.get(context).smsDatabase()
else DatabaseComponent.get(context).mmsDatabase()
+ // Perform local delete
messagingDatabase.deleteMessages(messageIDs.toLongArray(), threadId)
+
+ // Perform online delete
DatabaseComponent.get(context).lokiMessageDatabase().deleteMessages(messageIDs)
DatabaseComponent.get(context).lokiMessageDatabase().deleteMessageServerHashes(messageIDs, mms = !isSms)
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/ProfilePictureView.kt b/app/src/main/java/org/thoughtcrime/securesms/components/ProfilePictureView.kt
index bb9cee027e..9a5eb730de 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/ProfilePictureView.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/ProfilePictureView.kt
@@ -132,7 +132,8 @@ class ProfilePictureView @JvmOverloads constructor(
.diskCacheStrategy(DiskCacheStrategy.NONE)
.circleCrop()
.into(imageView)
- } else if (recipient.isOpenGroupRecipient && recipient.groupAvatarId == null) {
+ } else if (recipient.isCommunityRecipient && recipient.groupAvatarId == null) {
+ glide.clear(imageView)
glide.load(unknownOpenGroupDrawable)
.centerCrop()
.circleCrop()
diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/ContactSelectionListLoader.kt b/app/src/main/java/org/thoughtcrime/securesms/contacts/ContactSelectionListLoader.kt
index 3a2b2cbb5c..90e0ce50f2 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/contacts/ContactSelectionListLoader.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/ContactSelectionListLoader.kt
@@ -58,7 +58,7 @@ class ContactSelectionListLoader(context: Context, val mode: Int, val filter: St
private fun getOpenGroups(contacts: List): List {
return getItems(contacts, context.getString(R.string.fragment_contact_selection_open_groups_title)) {
- it.address.isOpenGroup
+ it.address.isCommunity
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActionBarView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActionBarView.kt
index 4bbcc3e021..184869b9ad 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActionBarView.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActionBarView.kt
@@ -116,7 +116,7 @@ class ConversationActionBarView @JvmOverloads constructor(
)
}
if (recipient.isGroupRecipient) {
- val title = if (recipient.isOpenGroupRecipient) {
+ val title = if (recipient.isCommunityRecipient) {
val userCount = openGroup?.let { lokiApiDb.getUserCount(it.room, it.server) } ?: 0
context.getString(R.string.ConversationActivity_active_member_count, userCount)
} else {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt
index 5e6dd45c21..39c7bf4196 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt
@@ -395,7 +395,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
messageToScrollAuthor.set(intent.getParcelableExtra(SCROLL_MESSAGE_AUTHOR))
val recipient = viewModel.recipient
val openGroup = recipient.let { viewModel.openGroup }
- if (recipient == null || (recipient.isOpenGroupRecipient && openGroup == null)) {
+ if (recipient == null || (recipient.isCommunityRecipient && openGroup == null)) {
Toast.makeText(this, "This thread has been deleted.", Toast.LENGTH_LONG).show()
return finish()
}
@@ -976,11 +976,11 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
view.glide = glide
view.onCandidateSelected = { handleMentionSelected(it) }
additionalContentContainer.addView(view)
- val candidates = MentionsManager.getMentionCandidates(query, viewModel.threadId, recipient.isOpenGroupRecipient)
+ val candidates = MentionsManager.getMentionCandidates(query, viewModel.threadId, recipient.isCommunityRecipient)
this.mentionCandidatesView = view
view.show(candidates, viewModel.threadId)
} else {
- val candidates = MentionsManager.getMentionCandidates(query, viewModel.threadId, recipient.isOpenGroupRecipient)
+ val candidates = MentionsManager.getMentionCandidates(query, viewModel.threadId, recipient.isCommunityRecipient)
this.mentionCandidatesView!!.setMentionCandidates(candidates)
}
isShowingMentionCandidatesView = true
@@ -1197,7 +1197,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
}
override fun copyOpenGroupUrl(thread: Recipient) {
- if (!thread.isOpenGroupRecipient) { return }
+ if (!thread.isCommunityRecipient) { return }
val threadId = threadDb.getThreadIdIfExistsFor(thread) ?: return
val openGroup = lokiThreadDb.getOpenGroupChat(threadId) ?: return
@@ -1361,7 +1361,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
} else originalMessage.individualRecipient.address
// Send it
reactionMessage.reaction = Reaction.from(originalMessage.timestamp, originalAuthor.serialize(), emoji, true)
- if (recipient.isOpenGroupRecipient) {
+ if (recipient.isCommunityRecipient) {
val messageServerId = lokiMessageDb.getServerID(originalMessage.id, !originalMessage.isMms) ?: return
viewModel.openGroup?.let {
OpenGroupApi.addReaction(it.room, it.server, messageServerId, emoji)
@@ -1385,7 +1385,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
} else originalMessage.individualRecipient.address
message.reaction = Reaction.from(originalMessage.timestamp, originalAuthor.serialize(), emoji, false)
- if (recipient.isOpenGroupRecipient) {
+ if (recipient.isCommunityRecipient) {
val messageServerId = lokiMessageDb.getServerID(originalMessage.id, !originalMessage.isMms) ?: return
viewModel.openGroup?.let {
OpenGroupApi.deleteReaction(it.room, it.server, messageServerId, emoji)
@@ -1782,7 +1782,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
sendAttachments(slideDeck.asAttachments(), body)
}
INVITE_CONTACTS -> {
- if (viewModel.recipient?.isOpenGroupRecipient != true) { return }
+ if (viewModel.recipient?.isCommunityRecipient != true) { return }
val extras = intent?.extras ?: return
if (!intent.hasExtra(selectedContactsKey)) { return }
val selectedContacts = extras.getStringArray(selectedContactsKey)!!
@@ -1848,19 +1848,62 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
handleLongPress(messages.first(), 0) //TODO: begin selection mode
}
+ // The option to "Delete just for me" or "Delete for everyone"
+ private fun showDeleteOrDeleteForEveryoneInCommunityUI(messages: Set) {
+ val bottomSheet = DeleteOptionsBottomSheet()
+ bottomSheet.recipient = viewModel.recipient!!
+ bottomSheet.onDeleteForMeTapped = {
+ messages.forEach(viewModel::deleteLocally)
+ bottomSheet.dismiss()
+ endActionMode()
+ }
+ bottomSheet.onDeleteForEveryoneTapped = {
+ messages.forEach(viewModel::deleteForEveryone)
+ bottomSheet.dismiss()
+ endActionMode()
+ }
+ bottomSheet.onCancelTapped = {
+ bottomSheet.dismiss()
+ endActionMode()
+ }
+ bottomSheet.show(supportFragmentManager, bottomSheet.tag)
+ }
+
+ private fun showDeleteLocallyUI(messages: Set) {
+ val messageCount = 1
+ showSessionDialog {
+ title(resources.getQuantityString(R.plurals.ConversationFragment_delete_selected_messages, messageCount, messageCount))
+ text(resources.getQuantityString(R.plurals.ConversationFragment_this_will_permanently_delete_all_n_selected_messages, messageCount, messageCount))
+ button(R.string.delete) { messages.forEach(viewModel::deleteLocally); endActionMode() }
+ cancelButton(::endActionMode)
+ }
+ }
+
+ // Note: The messages in the provided set may be a single message, or multiple if there are a
+ // group of selected messages.
override fun deleteMessages(messages: Set) {
- val recipient = viewModel.recipient ?: return
+ val recipient = viewModel.recipient
+ if (recipient == null) {
+ Log.w("ConversationActivityV2", "Asked to delete messages but could not obtain viewModel recipient - aborting.")
+ return
+ }
+
val allSentByCurrentUser = messages.all { it.isOutgoing }
val allHasHash = messages.all { lokiMessageDb.getMessageServerHash(it.id, it.isMms) != null }
- if (recipient.isOpenGroupRecipient) {
- val messageCount = 1
+
+ // If the recipient is a community then we delete the message for everyone
+ if (recipient.isCommunityRecipient) {
+ val messageCount = 1 // Only used for plurals string
showSessionDialog {
title(resources.getQuantityString(R.plurals.ConversationFragment_delete_selected_messages, messageCount, messageCount))
text(resources.getQuantityString(R.plurals.ConversationFragment_this_will_permanently_delete_all_n_selected_messages, messageCount, messageCount))
- button(R.string.delete) { messages.forEach(viewModel::deleteForEveryone); endActionMode() }
+ button(R.string.delete) {
+ messages.forEach(viewModel::deleteForEveryone); endActionMode()
+ }
cancelButton { endActionMode() }
}
+ // Otherwise if this is a 1-on-1 conversation we may decided to delete just for ourselves or delete for everyone
} else if (allSentByCurrentUser && allHasHash) {
val bottomSheet = DeleteOptionsBottomSheet()
bottomSheet.recipient = recipient
@@ -1879,13 +1922,17 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
endActionMode()
}
bottomSheet.show(supportFragmentManager, bottomSheet.tag)
- } else {
+ }
+ else // Finally, if this is a closed group and you are deleting someone else's message(s)
+ // then we can only delete locally.
+ {
val messageCount = 1
-
showSessionDialog {
title(resources.getQuantityString(R.plurals.ConversationFragment_delete_selected_messages, messageCount, messageCount))
text(resources.getQuantityString(R.plurals.ConversationFragment_this_will_permanently_delete_all_n_selected_messages, messageCount, messageCount))
- button(R.string.delete) { messages.forEach(viewModel::deleteLocally); endActionMode() }
+ button(R.string.delete) {
+ messages.forEach(viewModel::deleteLocally); endActionMode()
+ }
cancelButton(::endActionMode)
}
}
@@ -1904,7 +1951,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
showSessionDialog {
title(R.string.ConversationFragment_ban_selected_user)
text("This will ban the selected user from this room and delete all messages sent by them. It won't ban them from other rooms or delete the messages they sent there.")
- button(R.string.ban) { viewModel.banAndDeleteAll(messages.first().individualRecipient); endActionMode() }
+ button(R.string.ban) { viewModel.banAndDeleteAll(messages.first()); endActionMode() }
cancelButton(::endActionMode)
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.kt
index 405d2a3c0e..d48d761f94 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.kt
@@ -541,7 +541,7 @@ class ConversationReactionOverlay : FrameLayout {
items += ActionItem(R.attr.menu_copy_icon, R.string.copy, { handleActionItemClicked(Action.COPY_MESSAGE) })
}
// Copy Session ID
- if (recipient.isGroupRecipient && !recipient.isOpenGroupRecipient && message.recipient.address.toString() != userPublicKey) {
+ if (recipient.isGroupRecipient && !recipient.isCommunityRecipient && message.recipient.address.toString() != userPublicKey) {
items += ActionItem(R.attr.menu_copy_icon, R.string.activity_conversation_menu_copy_session_id, { handleActionItemClicked(Action.COPY_SESSION_ID) })
}
// Delete message
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt
index 677dd22f60..80d6df87fe 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt
@@ -1,18 +1,23 @@
package org.thoughtcrime.securesms.conversation.v2
import android.content.Context
+
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
+
import com.goterl.lazysodium.utils.KeyPair
+
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
+
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
+
import org.session.libsession.messaging.messages.ExpirationConfiguration
import org.session.libsession.messaging.open_groups.OpenGroup
import org.session.libsession.messaging.open_groups.OpenGroupApi
@@ -22,9 +27,12 @@ import org.session.libsession.utilities.Address
import org.session.libsession.utilities.recipients.Recipient
import org.session.libsignal.utilities.IdPrefix
import org.session.libsignal.utilities.Log
+import org.thoughtcrime.securesms.database.MmsSmsDatabase
+
import org.thoughtcrime.securesms.database.Storage
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.repository.ConversationRepository
+
import java.util.UUID
class ConversationViewModel(
@@ -144,9 +152,14 @@ class ConversationViewModel(
}
fun deleteForEveryone(message: MessageRecord) = viewModelScope.launch {
- val recipient = recipient ?: return@launch
+ val recipient = recipient ?: return@launch Log.w("Loki", "Recipient was null for delete for everyone - aborting delete operation.")
+
repository.deleteForEveryone(threadId, recipient, message)
+ .onSuccess {
+ Log.d("Loki", "Deleted message ${message.id} ")
+ }
.onFailure {
+ Log.w("Loki", "FAILED TO delete message ${message.id} ")
showMessage("Couldn't delete message due to error: $it")
}
}
@@ -168,10 +181,15 @@ class ConversationViewModel(
}
}
- fun banAndDeleteAll(recipient: Recipient) = viewModelScope.launch {
- repository.banAndDeleteAll(threadId, recipient)
+ fun banAndDeleteAll(messageRecord: MessageRecord) = viewModelScope.launch {
+
+ repository.banAndDeleteAll(threadId, messageRecord.individualRecipient)
.onSuccess {
+ // At this point the server side messages have been successfully deleted..
showMessage("Successfully banned user and deleted all their messages")
+
+ // ..so we can now delete all their messages in this thread from local storage & remove the views.
+ repository.deleteAllLocalMessagesInThreadFromSenderOfMessage(messageRecord)
}
.onFailure {
showMessage("Couldn't execute request due to error: $it")
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationActionModeCallback.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationActionModeCallback.kt
index 3746aa52e4..2788d35dd2 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationActionModeCallback.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationActionModeCallback.kt
@@ -65,7 +65,7 @@ class ConversationActionModeCallback(private val adapter: ConversationAdapter, p
menu.findItem(R.id.menu_context_copy).isVisible = !containsControlMessage && hasText
// Copy Session ID
menu.findItem(R.id.menu_context_copy_public_key).isVisible =
- (thread.isGroupRecipient && !thread.isOpenGroupRecipient && selectedItems.size == 1 && firstMessage.individualRecipient.address.toString() != userPublicKey)
+ (thread.isGroupRecipient && !thread.isCommunityRecipient && selectedItems.size == 1 && firstMessage.individualRecipient.address.toString() != userPublicKey)
// Message detail
menu.findItem(R.id.menu_message_details).isVisible = selectedItems.size == 1
// Resend
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt
index dadf138ead..11069937a0 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt
@@ -50,7 +50,7 @@ object ConversationMenuHelper {
) {
// Prepare
menu.clear()
- val isOpenGroup = thread.isOpenGroupRecipient
+ val isOpenGroup = thread.isCommunityRecipient
// Base menu (options that should always be present)
inflater.inflate(R.menu.menu_conversation, menu)
// Expiring messages
@@ -253,7 +253,7 @@ object ConversationMenuHelper {
}
private fun copyOpenGroupUrl(context: Context, thread: Recipient) {
- if (!thread.isOpenGroupRecipient) { return }
+ if (!thread.isCommunityRecipient) { return }
val listener = context as? ConversationMenuListener ?: return
listener.copyOpenGroupUrl(thread)
}
@@ -300,7 +300,7 @@ object ConversationMenuHelper {
}
private fun inviteContacts(context: Context, thread: Recipient) {
- if (!thread.isOpenGroupRecipient) { return }
+ if (!thread.isCommunityRecipient) { return }
val intent = Intent(context, SelectContactsActivity::class.java)
val activity = context as AppCompatActivity
activity.startActivityForResult(intent, ConversationActivityV2.INVITE_CONTACTS)
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt
index 9dc3d2ab2d..a59a102d1c 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt
@@ -166,7 +166,7 @@ class VisibleMessageView : LinearLayout {
binding.profilePictureView.publicKey = senderSessionID
binding.profilePictureView.update(message.individualRecipient)
binding.profilePictureView.setOnClickListener {
- if (thread.isOpenGroupRecipient) {
+ if (thread.isCommunityRecipient) {
val openGroup = lokiThreadDb.getOpenGroupChat(threadID)
if (IdPrefix.fromValue(senderSessionID) == IdPrefix.BLINDED && openGroup?.canWrite == true) {
// TODO: support v2 soon
@@ -179,7 +179,7 @@ class VisibleMessageView : LinearLayout {
maybeShowUserDetails(senderSessionID, threadID)
}
}
- if (thread.isOpenGroupRecipient) {
+ if (thread.isCommunityRecipient) {
val openGroup = lokiThreadDb.getOpenGroupChat(threadID) ?: return
var standardPublicKey = ""
var blindedPublicKey: String? = null
@@ -195,7 +195,7 @@ class VisibleMessageView : LinearLayout {
}
binding.senderNameTextView.isVisible = !message.isOutgoing && (isStartOfMessageCluster && (isGroupThread || snIsSelected))
val contactContext =
- if (thread.isOpenGroupRecipient) ContactContext.OPEN_GROUP else ContactContext.REGULAR
+ if (thread.isCommunityRecipient) ContactContext.OPEN_GROUP else ContactContext.REGULAR
binding.senderNameTextView.text = contact?.displayName(contactContext) ?: senderSessionID
// Unread marker
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Database.java b/app/src/main/java/org/thoughtcrime/securesms/database/Database.java
index b6b224589e..e1879d5230 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/Database.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/Database.java
@@ -26,6 +26,7 @@ import androidx.annotation.NonNull;
import net.zetetic.database.sqlcipher.SQLiteDatabase;
import org.session.libsession.utilities.WindowDebouncer;
+import org.session.libsignal.utilities.Log;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
@@ -77,11 +78,11 @@ public abstract class Database {
notifyConversationListListeners();
}
- protected void setNotifyConverationListeners(Cursor cursor, long threadId) {
+ protected void setNotifyConversationListeners(Cursor cursor, long threadId) {
cursor.setNotificationUri(context.getContentResolver(), DatabaseContentProviders.Conversation.getUriForThread(threadId));
}
- protected void setNotifyConverationListListeners(Cursor cursor) {
+ protected void setNotifyConversationListListeners(Cursor cursor) {
cursor.setNotificationUri(context.getContentResolver(), DatabaseContentProviders.ConversationList.CONTENT_URI);
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ExpirationConfigurationDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/ExpirationConfigurationDatabase.kt
index a65c22545b..013bbf5cb5 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/ExpirationConfigurationDatabase.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/ExpirationConfigurationDatabase.kt
@@ -6,8 +6,8 @@ import android.database.Cursor
import org.session.libsession.messaging.messages.ExpirationConfiguration
import org.session.libsession.messaging.messages.ExpirationDatabaseMetadata
import org.session.libsession.utilities.GroupUtil.CLOSED_GROUP_PREFIX
-import org.session.libsession.utilities.GroupUtil.OPEN_GROUP_INBOX_PREFIX
-import org.session.libsession.utilities.GroupUtil.OPEN_GROUP_PREFIX
+import org.session.libsession.utilities.GroupUtil.COMMUNITY_INBOX_PREFIX
+import org.session.libsession.utilities.GroupUtil.COMMUNITY_PREFIX
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
class ExpirationConfigurationDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper) {
@@ -38,8 +38,8 @@ class ExpirationConfigurationDatabase(context: Context, helper: SQLCipherOpenHel
INSERT INTO $TABLE_NAME ($THREAD_ID) SELECT ${ThreadDatabase.TABLE_NAME}.${ThreadDatabase.ID}
FROM ${ThreadDatabase.TABLE_NAME}, ${RecipientDatabase.TABLE_NAME}
WHERE ${ThreadDatabase.TABLE_NAME}.${ThreadDatabase.ADDRESS} NOT LIKE '$CLOSED_GROUP_PREFIX%'
- AND ${ThreadDatabase.TABLE_NAME}.${ThreadDatabase.ADDRESS} NOT LIKE '$OPEN_GROUP_PREFIX%'
- AND ${ThreadDatabase.TABLE_NAME}.${ThreadDatabase.ADDRESS} NOT LIKE '$OPEN_GROUP_INBOX_PREFIX%'
+ AND ${ThreadDatabase.TABLE_NAME}.${ThreadDatabase.ADDRESS} NOT LIKE '$COMMUNITY_PREFIX%'
+ AND ${ThreadDatabase.TABLE_NAME}.${ThreadDatabase.ADDRESS} NOT LIKE '$COMMUNITY_INBOX_PREFIX%'
AND EXISTS (SELECT ${RecipientDatabase.EXPIRE_MESSAGES} FROM ${RecipientDatabase.TABLE_NAME} WHERE ${ThreadDatabase.TABLE_NAME}.${ThreadDatabase.ADDRESS} = ${RecipientDatabase.TABLE_NAME}.${RecipientDatabase.ADDRESS} AND ${RecipientDatabase.EXPIRE_MESSAGES} > 0)
""".trimIndent()
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/LokiMessageDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/LokiMessageDatabase.kt
index 441c979108..18dd42818d 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/LokiMessageDatabase.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/LokiMessageDatabase.kt
@@ -4,6 +4,7 @@ import android.content.ContentValues
import android.content.Context
import net.zetetic.database.sqlcipher.SQLiteDatabase.CONFLICT_REPLACE
import org.session.libsignal.database.LokiMessageDatabaseProtocol
+import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiMessageDatabaseProtocol {
@@ -72,7 +73,12 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab
"${Companion.messageID} = ? AND $messageType = ?",
arrayOf(messageID.toString(), (if (isSms) SMS_TYPE else MMS_TYPE).toString())) { cursor ->
cursor.getInt(serverID).toLong()
- } ?: return
+ }
+
+ if (serverID == null) {
+ Log.w(this::class.simpleName, "Could not get server ID to delete message with ID: $messageID")
+ return
+ }
database.beginTransaction()
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MediaDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MediaDatabase.java
index 1b273de929..63db0c66ba 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/MediaDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/MediaDatabase.java
@@ -68,7 +68,7 @@ public class MediaDatabase extends Database {
public Cursor getGalleryMediaForThread(long threadId) {
SQLiteDatabase database = databaseHelper.getReadableDatabase();
Cursor cursor = database.rawQuery(GALLERY_MEDIA_QUERY, new String[]{threadId+""});
- setNotifyConverationListeners(cursor, threadId);
+ setNotifyConversationListeners(cursor, threadId);
return cursor;
}
@@ -83,7 +83,7 @@ public class MediaDatabase extends Database {
public Cursor getDocumentMediaForThread(long threadId) {
SQLiteDatabase database = databaseHelper.getReadableDatabase();
Cursor cursor = database.rawQuery(DOCUMENT_MEDIA_QUERY, new String[]{threadId+""});
- setNotifyConverationListeners(cursor, threadId);
+ setNotifyConversationListeners(cursor, threadId);
return cursor;
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt
index 62db50a1ba..15a515ee5b 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt
@@ -19,9 +19,9 @@ package org.thoughtcrime.securesms.database
import android.content.ContentValues
import android.content.Context
import android.database.Cursor
-import android.provider.ContactsContract.CommonDataKinds.BaseTypes
import com.annimon.stream.Stream
import com.google.android.mms.pdu_alt.PduHeaders
+import org.apache.commons.lang3.StringUtils
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
@@ -214,7 +214,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
fun getMessage(messageId: Long): Cursor {
val cursor = rawQuery(RAW_ID_WHERE, arrayOf(messageId.toString()))
- setNotifyConverationListeners(cursor, getThreadIdForMessage(messageId))
+ setNotifyConversationListeners(cursor, getThreadIdForMessage(messageId))
return cursor
}
@@ -859,8 +859,10 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
*/
private fun deleteMessages(messageIds: Array) {
if (messageIds.isEmpty()) {
+ Log.w(TAG, "No message Ids provided to MmsDatabase.deleteMessages - aborting delete operation!")
return
}
+
// don't need thread IDs
val queryBuilder = StringBuilder()
for (i in messageIds.indices) {
@@ -883,6 +885,8 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
notifyStickerPackListeners()
}
+ // Caution: The bool returned from `deleteMessage` is NOT "Was the message successfully deleted?"
+ // - it is "Was the thread deleted because removing that message resulted in an empty thread"!
override fun deleteMessage(messageId: Long): Boolean {
val threadId = getThreadIdForMessage(messageId)
val attachmentDatabase = get(context).attachmentDatabase()
@@ -899,14 +903,15 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
}
override fun deleteMessages(messageIds: LongArray, threadId: Long): Boolean {
- val attachmentDatabase = get(context).attachmentDatabase()
- val groupReceiptDatabase = get(context).groupReceiptDatabase()
+ val argsArray = messageIds.map { "?" }
+ val argValues = messageIds.map { it.toString() }.toTypedArray()
- queue(Runnable { attachmentDatabase.deleteAttachmentsForMessages(messageIds) })
- groupReceiptDatabase.deleteRowsForMessages(messageIds)
-
- val database = databaseHelper.writableDatabase
- database!!.delete(TABLE_NAME, ID_IN, arrayOf(messageIds.joinToString(",")))
+ val db = databaseHelper.writableDatabase
+ db.delete(
+ TABLE_NAME,
+ ID + " IN (" + StringUtils.join(argsArray, ',') + ")",
+ argValues
+ )
val threadDeleted = get(context).threadDatabase().update(threadId, false, true)
notifyConversationListeners(threadId)
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java
index 63a9ec5c29..98f118d59d 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java
@@ -183,7 +183,7 @@ public class MmsSmsDatabase extends Database {
String limitStr = limit > 0 || offset > 0 ? offset + ", " + limit : null;
Cursor cursor = queryTables(PROJECTION, selection, order, limitStr);
- setNotifyConverationListeners(cursor, threadId);
+ setNotifyConversationListeners(cursor, threadId);
return cursor;
}
@@ -209,6 +209,44 @@ public class MmsSmsDatabase extends Database {
}
}
+ // Builds up and returns a list of all all the messages sent by this user in the given thread.
+ // Used to do a pass through our local database to remove records when a user has "Ban & Delete"
+ // called on them in a Community.
+ public Set getAllMessageRecordsFromSenderInThread(long threadId, String serializedAuthor) {
+ String selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " + MmsSmsColumns.ADDRESS + " = \"" + serializedAuthor + "\"";
+ Set identifiedMessages = new HashSet();
+
+ // Try everything with resources so that they auto-close on end of scope
+ try (Cursor cursor = queryTables(PROJECTION, selection, null, null)) {
+ try (MmsSmsDatabase.Reader reader = readerFor(cursor)) {
+ MessageRecord messageRecord;
+ while ((messageRecord = reader.getNext()) != null) {
+ identifiedMessages.add(messageRecord);
+ }
+ }
+ }
+ return identifiedMessages;
+ }
+
+ // Version of the above `getAllMessageRecordsFromSenderInThread` method that returns the message
+ // Ids rather than the set of MessageRecords - currently unused by potentially useful in the future.
+ public Set getAllMessageIdsFromSenderInThread(long threadId, String serializedAuthor) {
+ String selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " + MmsSmsColumns.ADDRESS + " = \"" + serializedAuthor + "\"";
+
+ Set identifiedMessages = new HashSet();
+
+ // Try everything with resources so that they auto-close on end of scope
+ try (Cursor cursor = queryTables(PROJECTION, selection, null, null)) {
+ try (MmsSmsDatabase.Reader reader = readerFor(cursor)) {
+ MessageRecord messageRecord;
+ while ((messageRecord = reader.getNext()) != null) {
+ identifiedMessages.add(messageRecord.id);
+ }
+ }
+ }
+ return identifiedMessages;
+ }
+
public long getLastSentMessageFromSender(long threadId, String serializedAuthor) {
String order = MmsSmsColumns.NORMALIZED_DATE_SENT + " DESC";
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java
index 69c9fa87f1..8dbef32017 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java
@@ -1,6 +1,6 @@
package org.thoughtcrime.securesms.database;
-import static org.session.libsession.utilities.GroupUtil.OPEN_GROUP_PREFIX;
+import static org.session.libsession.utilities.GroupUtil.COMMUNITY_PREFIX;
import android.content.ContentValues;
import android.content.Context;
@@ -123,18 +123,18 @@ public class RecipientDatabase extends Database {
public static String getUpdateApprovedCommand() {
return "UPDATE "+ TABLE_NAME + " " +
"SET " + APPROVED + " = 1, " + APPROVED_ME + " = 1 " +
- "WHERE " + ADDRESS + " NOT LIKE '" + OPEN_GROUP_PREFIX + "%'";
+ "WHERE " + ADDRESS + " NOT LIKE '" + COMMUNITY_PREFIX + "%'";
}
public static String getUpdateResetApprovedCommand() {
return "UPDATE "+ TABLE_NAME + " " +
"SET " + APPROVED + " = 0, " + APPROVED_ME + " = 0 " +
- "WHERE " + ADDRESS + " NOT LIKE '" + OPEN_GROUP_PREFIX + "%'";
+ "WHERE " + ADDRESS + " NOT LIKE '" + COMMUNITY_PREFIX + "%'";
}
public static String getUpdateApprovedSelectConversations() {
return "UPDATE "+ TABLE_NAME + " SET "+APPROVED+" = 1, "+APPROVED_ME+" = 1 "+
- "WHERE "+ADDRESS+ " NOT LIKE '"+OPEN_GROUP_PREFIX+"%' " +
+ "WHERE "+ADDRESS+ " NOT LIKE '"+ COMMUNITY_PREFIX +"%' " +
"AND ("+ADDRESS+" IN (SELECT "+ThreadDatabase.TABLE_NAME+"."+ThreadDatabase.ADDRESS+" FROM "+ThreadDatabase.TABLE_NAME+" WHERE ("+ThreadDatabase.MESSAGE_COUNT+" != 0) "+
"OR "+ADDRESS+" IN (SELECT "+GroupDatabase.TABLE_NAME+"."+GroupDatabase.ADMINS+" FROM "+GroupDatabase.TABLE_NAME+")))";
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SearchDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SearchDatabase.java
index eac6a5fbc3..0782049478 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/SearchDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/SearchDatabase.java
@@ -119,7 +119,7 @@ public class SearchDatabase extends Database {
int queryLimit = Math.min(query.length()*50,500);
Cursor cursor = db.rawQuery(MESSAGES_QUERY, new String[] { prefixQuery, prefixQuery, String.valueOf(queryLimit) });
- setNotifyConverationListListeners(cursor);
+ setNotifyConversationListListeners(cursor);
return cursor;
}
@@ -128,7 +128,7 @@ public class SearchDatabase extends Database {
String prefixQuery = adjustQuery(query);
Cursor cursor = db.rawQuery(MESSAGES_FOR_THREAD_QUERY, new String[] { prefixQuery, String.valueOf(threadId), prefixQuery, String.valueOf(threadId) });
- setNotifyConverationListListeners(cursor);
+ setNotifyConversationListListeners(cursor);
return cursor;
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java
index 2c0c33dda8..61f17a2d86 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java
@@ -621,10 +621,12 @@ public class SmsDatabase extends MessagingDatabase {
public Cursor getMessageCursor(long messageId) {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
Cursor cursor = db.query(TABLE_NAME, MESSAGE_PROJECTION, ID_WHERE, new String[] {messageId + ""}, null, null, null);
- setNotifyConverationListeners(cursor, getThreadIdForMessage(messageId));
+ setNotifyConversationListeners(cursor, getThreadIdForMessage(messageId));
return cursor;
}
+ // Caution: The bool returned from `deleteMessage` is NOT "Was the message successfully deleted?"
+ // - it is "Was the thread deleted because removing that message resulted in an empty thread"!
@Override
public boolean deleteMessage(long messageId) {
Log.i("MessageDatabase", "Deleting: " + messageId);
@@ -645,9 +647,6 @@ public class SmsDatabase extends MessagingDatabase {
argValues[i] = (messageIds[i] + "");
}
- String combinedMessageIdArgss = StringUtils.join(messageIds, ',');
- String combinedMessageIds = StringUtils.join(messageIds, ',');
- Log.i("MessageDatabase", "Deleting: " + combinedMessageIds);
SQLiteDatabase db = databaseHelper.getWritableDatabase();
db.delete(
TABLE_NAME,
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt
index 584394a86c..ae0569e42a 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt
@@ -121,7 +121,7 @@ open class Storage(
)
volatile.set(newVolatileParams)
}
- } else if (address.isOpenGroup) {
+ } else if (address.isCommunity) {
// these should be added on the group join / group info fetch
Log.w("Loki", "Thread created called for open group address, not adding any extra information")
}
@@ -152,7 +152,7 @@ open class Storage(
val sessionId = GroupUtil.doubleDecodeGroupId(address.serialize())
volatile.eraseLegacyClosedGroup(sessionId)
groups.eraseLegacyGroup(sessionId)
- } else if (address.isOpenGroup) {
+ } else if (address.isCommunity) {
// these should be removed in the group leave / handling new configs
Log.w("Loki", "Thread delete called for open group address, expecting to be handled elsewhere")
}
@@ -257,7 +257,7 @@ open class Storage(
// recipient closed group
recipient.isClosedGroupRecipient -> config.getOrConstructLegacyGroup(GroupUtil.doubleDecodeGroupId(recipient.address.serialize()))
// recipient is open group
- recipient.isOpenGroupRecipient -> {
+ recipient.isCommunityRecipient -> {
val openGroupJoinUrl = getOpenGroup(threadId)?.joinURL ?: return
BaseCommunityInfo.parseFullUrl(openGroupJoinUrl)?.let { (base, room, pubKey) ->
config.getOrConstructCommunity(base, room, pubKey)
@@ -327,7 +327,7 @@ open class Storage(
setRecipientApprovedMe(targetRecipient, true)
}
}
- if (message.threadID == null && !targetRecipient.isOpenGroupRecipient) {
+ if (message.threadID == null && !targetRecipient.isCommunityRecipient) {
// open group recipients should explicitly create threads
message.threadID = getOrCreateThreadIdFor(targetAddress)
}
@@ -1289,7 +1289,7 @@ open class Storage(
priority = if (isPinned) PRIORITY_PINNED else ConfigBase.PRIORITY_VISIBLE
)
groups.set(newGroupInfo)
- } else if (threadRecipient.isOpenGroupRecipient) {
+ } else if (threadRecipient.isCommunityRecipient) {
val openGroup = getOpenGroup(threadID) ?: return
val (baseUrl, room, pubKeyHex) = BaseCommunityInfo.parseFullUrl(openGroup.joinURL) ?: return
val newGroupInfo = groups.getOrConstructCommunityInfo(baseUrl, room, Hex.toStringCondensed(pubKeyHex)).copy (
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java
index fd5042086c..e2f9687451 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java
@@ -18,7 +18,7 @@
package org.thoughtcrime.securesms.database;
import static org.session.libsession.utilities.GroupUtil.CLOSED_GROUP_PREFIX;
-import static org.session.libsession.utilities.GroupUtil.OPEN_GROUP_PREFIX;
+import static org.session.libsession.utilities.GroupUtil.COMMUNITY_PREFIX;
import static org.thoughtcrime.securesms.database.GroupDatabase.GROUP_ID;
import android.content.ContentValues;
@@ -427,7 +427,7 @@ public class ThreadDatabase extends Database {
}
Cursor cursor = cursors.size() > 1 ? new MergeCursor(cursors.toArray(new Cursor[cursors.size()])) : cursors.get(0);
- setNotifyConverationListListeners(cursor);
+ setNotifyConversationListListeners(cursor);
return cursor;
}
@@ -491,7 +491,7 @@ public class ThreadDatabase extends Database {
}
public Cursor getConversationList() {
- String where = "(" + MESSAGE_COUNT + " != 0 OR " + GroupDatabase.TABLE_NAME + "." + GROUP_ID + " LIKE '" + OPEN_GROUP_PREFIX + "%') " +
+ String where = "(" + MESSAGE_COUNT + " != 0 OR " + GroupDatabase.TABLE_NAME + "." + GROUP_ID + " LIKE '" + COMMUNITY_PREFIX + "%') " +
"AND " + ARCHIVED + " = 0 ";
return getConversationList(where);
}
@@ -502,7 +502,7 @@ public class ThreadDatabase extends Database {
}
public Cursor getApprovedConversationList() {
- String where = "((" + HAS_SENT + " = 1 OR " + RecipientDatabase.APPROVED + " = 1 OR "+ GroupDatabase.TABLE_NAME +"."+GROUP_ID+" LIKE '"+CLOSED_GROUP_PREFIX+"%') OR " + GroupDatabase.TABLE_NAME + "." + GROUP_ID + " LIKE '" + OPEN_GROUP_PREFIX + "%') " +
+ String where = "((" + HAS_SENT + " = 1 OR " + RecipientDatabase.APPROVED + " = 1 OR "+ GroupDatabase.TABLE_NAME +"."+GROUP_ID+" LIKE '"+CLOSED_GROUP_PREFIX+"%') OR " + GroupDatabase.TABLE_NAME + "." + GROUP_ID + " LIKE '" + COMMUNITY_PREFIX + "%') " +
"AND " + ARCHIVED + " = 0 ";
return getConversationList(where);
}
@@ -516,7 +516,7 @@ public class ThreadDatabase extends Database {
}
public Cursor getArchivedConversationList() {
- String where = "(" + MESSAGE_COUNT + " != 0 OR " + GroupDatabase.TABLE_NAME + "." + GROUP_ID + " LIKE '" + OPEN_GROUP_PREFIX + "%') " +
+ String where = "(" + MESSAGE_COUNT + " != 0 OR " + GroupDatabase.TABLE_NAME + "." + GROUP_ID + " LIKE '" + COMMUNITY_PREFIX + "%') " +
"AND " + ARCHIVED + " = 1 ";
return getConversationList(where);
}
@@ -526,7 +526,7 @@ public class ThreadDatabase extends Database {
String query = createQuery(where, 0);
Cursor cursor = db.rawQuery(query, null);
- setNotifyConverationListListeners(cursor);
+ setNotifyConversationListListeners(cursor);
return cursor;
}
@@ -547,7 +547,7 @@ public class ThreadDatabase extends Database {
// edge case where we set the last seen time for a conversation before it loads messages (joining community for example)
MmsSmsDatabase mmsSmsDatabase = DatabaseComponent.get(context).mmsSmsDatabase();
Recipient forThreadId = getRecipientForThreadId(threadId);
- if (mmsSmsDatabase.getConversationCount(threadId) <= 0 && forThreadId != null && forThreadId.isOpenGroupRecipient()) return false;
+ if (mmsSmsDatabase.getConversationCount(threadId) <= 0 && forThreadId != null && forThreadId.isCommunityRecipient()) return false;
SQLiteDatabase db = databaseHelper.getWritableDatabase();
@@ -822,7 +822,7 @@ public class ThreadDatabase extends Database {
private boolean deleteThreadOnEmpty(long threadId) {
Recipient threadRecipient = getRecipientForThreadId(threadId);
- return threadRecipient != null && !threadRecipient.isOpenGroupRecipient();
+ return threadRecipient != null && !threadRecipient.isCommunityRecipient();
}
private @NonNull String getFormattedBodyFor(@NonNull MessageRecord messageRecord) {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/ConversationOptionsBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/home/ConversationOptionsBottomSheet.kt
index 702bf33929..82b9f16dcd 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/home/ConversationOptionsBottomSheet.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/home/ConversationOptionsBottomSheet.kt
@@ -11,7 +11,6 @@ import dagger.hilt.android.AndroidEntryPoint
import network.loki.messenger.databinding.FragmentConversationBottomSheetBinding
import org.thoughtcrime.securesms.database.model.ThreadRecord
import org.thoughtcrime.securesms.dependencies.ConfigFactory
-import org.thoughtcrime.securesms.util.UiModeUtilities
import org.thoughtcrime.securesms.util.getConversationUnread
import javax.inject.Inject
@@ -75,7 +74,7 @@ class ConversationOptionsBottomSheet(private val parentContext: Context) : Botto
}
binding.copyConversationId.visibility = if (!recipient.isGroupRecipient && !recipient.isLocalNumber) View.VISIBLE else View.GONE
binding.copyConversationId.setOnClickListener(this)
- binding.copyCommunityUrl.visibility = if (recipient.isOpenGroupRecipient) View.VISIBLE else View.GONE
+ binding.copyCommunityUrl.visibility = if (recipient.isCommunityRecipient) View.VISIBLE else View.GONE
binding.copyCommunityUrl.setOnClickListener(this)
binding.unMuteNotificationsTextView.isVisible = recipient.isMuted && !recipient.isLocalNumber
binding.muteNotificationsTextView.isVisible = !recipient.isMuted && !recipient.isLocalNumber
diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt
index 850f065728..41245f9b85 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt
@@ -496,7 +496,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
manager.setPrimaryClip(clip)
Toast.makeText(this, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show()
}
- else if (thread.recipient.isOpenGroupRecipient) {
+ else if (thread.recipient.isCommunityRecipient) {
val threadId = threadDb.getThreadIdIfExistsFor(thread.recipient) ?: return@onCopyConversationId Unit
val openGroup = DatabaseComponent.get(this@HomeActivity).lokiThreadDatabase().getOpenGroupChat(threadId) ?: return@onCopyConversationId Unit
diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/PathActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/home/PathActivity.kt
index 2922044435..1f3f2ff537 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/home/PathActivity.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/home/PathActivity.kt
@@ -21,6 +21,7 @@ import network.loki.messenger.R
import network.loki.messenger.databinding.ActivityPathBinding
import org.session.libsession.snode.OnionRequestAPI
import org.session.libsession.utilities.getColorFromAttr
+import org.session.libsignal.utilities.Log
import org.session.libsignal.utilities.Snode
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.util.GlowViewUtilities
diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/UserDetailsBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/home/UserDetailsBottomSheet.kt
index acb9caa75f..bd38d0df86 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/home/UserDetailsBottomSheet.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/home/UserDetailsBottomSheet.kt
@@ -91,10 +91,10 @@ class UserDetailsBottomSheet: BottomSheetDialogFragment() {
&& !threadRecipient.isOpenGroupInboxRecipient
&& !threadRecipient.isOpenGroupOutboxRecipient
- publicKeyTextView.isVisible = !threadRecipient.isOpenGroupRecipient
+ publicKeyTextView.isVisible = !threadRecipient.isCommunityRecipient
&& !threadRecipient.isOpenGroupInboxRecipient
&& !threadRecipient.isOpenGroupOutboxRecipient
- messageButton.isVisible = !threadRecipient.isOpenGroupRecipient || IdPrefix.fromValue(publicKey)?.isBlinded() == true
+ messageButton.isVisible = !threadRecipient.isCommunityRecipient || IdPrefix.fromValue(publicKey)?.isBlinded() == true
publicKeyTextView.text = publicKey
publicKeyTextView.setOnLongClickListener {
val clipboard =
diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/MultipleRecipientNotificationBuilder.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/MultipleRecipientNotificationBuilder.java
index a4871f0fc9..cad3b6f6c5 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/notifications/MultipleRecipientNotificationBuilder.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/MultipleRecipientNotificationBuilder.java
@@ -53,7 +53,7 @@ public class MultipleRecipientNotificationBuilder extends AbstractNotificationBu
public void setMostRecentSender(Recipient recipient, Recipient threadRecipient) {
String displayName = recipient.toShortString();
if (threadRecipient.isGroupRecipient()) {
- displayName = getGroupDisplayName(recipient, threadRecipient.isOpenGroupRecipient());
+ displayName = getGroupDisplayName(recipient, threadRecipient.isCommunityRecipient());
}
if (privacy.isDisplayContact()) {
setContentText(context.getString(R.string.MessageNotifier_most_recent_from_s, displayName));
@@ -79,7 +79,7 @@ public class MultipleRecipientNotificationBuilder extends AbstractNotificationBu
public void addMessageBody(@NonNull Recipient sender, Recipient threadRecipient, @Nullable CharSequence body) {
String displayName = sender.toShortString();
if (threadRecipient.isGroupRecipient()) {
- displayName = getGroupDisplayName(sender, threadRecipient.isOpenGroupRecipient());
+ displayName = getGroupDisplayName(sender, threadRecipient.isCommunityRecipient());
}
if (privacy.isDisplayMessage()) {
SpannableStringBuilder builder = new SpannableStringBuilder();
diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java
index 891d0bb2df..2aaa593b58 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java
@@ -125,7 +125,7 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
if (privacy.isDisplayContact() && threadRecipient.isGroupRecipient()) {
- String displayName = getGroupDisplayName(individualRecipient, threadRecipient.isOpenGroupRecipient());
+ String displayName = getGroupDisplayName(individualRecipient, threadRecipient.isCommunityRecipient());
stringBuilder.append(Util.getBoldedString(displayName + ": "));
}
@@ -215,7 +215,7 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
if (privacy.isDisplayContact() && threadRecipient.isGroupRecipient()) {
- String displayName = getGroupDisplayName(individualRecipient, threadRecipient.isOpenGroupRecipient());
+ String displayName = getGroupDisplayName(individualRecipient, threadRecipient.isCommunityRecipient());
stringBuilder.append(Util.getBoldedString(displayName + ": "));
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/repository/ConversationRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/repository/ConversationRepository.kt
index f6277d1a4a..384f47d4d6 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/repository/ConversationRepository.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/repository/ConversationRepository.kt
@@ -1,13 +1,22 @@
package org.thoughtcrime.securesms.repository
import network.loki.messenger.libsession_util.util.ExpiryMode
+
import android.content.ContentResolver
import android.content.Context
+
import app.cash.copper.Query
import app.cash.copper.flow.observeQuery
+
import dagger.hilt.android.qualifiers.ApplicationContext
+
+import kotlin.coroutines.resume
+import kotlin.coroutines.resumeWithException
+import kotlin.coroutines.suspendCoroutine
+
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
+
import org.session.libsession.database.MessageDataProvider
import org.session.libsession.messaging.messages.Destination
import org.session.libsession.messaging.messages.control.MessageRequestResponse
@@ -22,7 +31,10 @@ import org.session.libsession.utilities.Address
import org.session.libsession.utilities.GroupUtil
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.recipients.Recipient
+import org.session.libsignal.utilities.Log
+
import org.session.libsignal.utilities.toHexString
+
import org.thoughtcrime.securesms.database.DatabaseContentProviders
import org.thoughtcrime.securesms.database.DraftDatabase
import org.thoughtcrime.securesms.database.ExpirationConfigurationDatabase
@@ -39,10 +51,8 @@ import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.database.model.ThreadRecord
import org.thoughtcrime.securesms.dependencies.ConfigFactory
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
+
import javax.inject.Inject
-import kotlin.coroutines.resume
-import kotlin.coroutines.resumeWithException
-import kotlin.coroutines.suspendCoroutine
interface ConversationRepository {
fun maybeGetRecipientForThreadId(threadId: Long): Recipient?
@@ -55,37 +65,19 @@ interface ConversationRepository {
fun inviteContacts(threadId: Long, contacts: List)
fun setBlocked(recipient: Recipient, blocked: Boolean)
fun deleteLocally(recipient: Recipient, message: MessageRecord)
+ fun deleteAllLocalMessagesInThreadFromSenderOfMessage(messageRecord: MessageRecord)
fun setApproved(recipient: Recipient, isApproved: Boolean)
-
- suspend fun deleteForEveryone(
- threadId: Long,
- recipient: Recipient,
- message: MessageRecord
- ): ResultOf
-
+ suspend fun deleteForEveryone(threadId: Long, recipient: Recipient, message: MessageRecord): ResultOf
fun buildUnsendRequest(recipient: Recipient, message: MessageRecord): UnsendRequest?
-
- suspend fun deleteMessageWithoutUnsendRequest(
- threadId: Long,
- messages: Set
- ): ResultOf
-
+ suspend fun deleteMessageWithoutUnsendRequest(threadId: Long, messages: Set): ResultOf
suspend fun banUser(threadId: Long, recipient: Recipient): ResultOf
-
suspend fun banAndDeleteAll(threadId: Long, recipient: Recipient): ResultOf
-
suspend fun deleteThread(threadId: Long): ResultOf
-
suspend fun deleteMessageRequest(thread: ThreadRecord): ResultOf
-
suspend fun clearAllMessageRequests(block: Boolean): ResultOf
-
suspend fun acceptMessageRequest(threadId: Long, recipient: Recipient): ResultOf
-
fun declineMessageRequest(threadId: Long)
-
fun hasReceived(threadId: Long): Boolean
-
}
class DefaultConversationRepository @Inject constructor(
@@ -184,6 +176,15 @@ class DefaultConversationRepository @Inject constructor(
messageDataProvider.deleteMessage(message.id, !message.isMms)
}
+ override fun deleteAllLocalMessagesInThreadFromSenderOfMessage(messageRecord: MessageRecord) {
+ val threadId = messageRecord.threadId
+ val senderId = messageRecord.recipient.address.contactIdentifier()
+ val messageRecordsToRemoveFromLocalStorage = mmsSmsDb.getAllMessageRecordsFromSenderInThread(threadId, senderId)
+ for (message in messageRecordsToRemoveFromLocalStorage) {
+ messageDataProvider.deleteMessage(message.id, !message.isMms)
+ }
+ }
+
override fun setApproved(recipient: Recipient, isApproved: Boolean) {
storage.setRecipientApproved(recipient, isApproved)
}
@@ -196,18 +197,38 @@ class DefaultConversationRepository @Inject constructor(
buildUnsendRequest(recipient, message)?.let { unsendRequest ->
MessageSender.send(unsendRequest, recipient.address)
}
+
val openGroup = lokiThreadDb.getOpenGroupChat(threadId)
if (openGroup != null) {
- lokiMessageDb.getServerID(message.id, !message.isMms)?.let { messageServerID ->
+ val serverId = lokiMessageDb.getServerID(message.id, !message.isMms)?.let { messageServerID ->
OpenGroupApi.deleteMessage(messageServerID, openGroup.room, openGroup.server)
.success {
messageDataProvider.deleteMessage(message.id, !message.isMms)
continuation.resume(ResultOf.Success(Unit))
}.fail { error ->
+ Log.w("TAG", "Call to OpenGroupApi.deleteForEveryone failed - attempting to resume..")
continuation.resumeWithException(error)
}
}
- } else {
+
+ // If the server ID is null then this message is stuck in limbo (it has likely been
+ // deleted remotely but that deletion did not occur locally) - so we'll delete the
+ // message locally to clean up.
+ if (serverId == null) {
+ Log.w("ConversationRepository","Found community message without a server ID - deleting locally.")
+
+ // Caution: The bool returned from `deleteMessage` is NOT "Was the message
+ // successfully deleted?" - it is "Was the thread itself also deleted because
+ // removing that message resulted in an empty thread?".
+ if (message.isMms) {
+ mmsDb.deleteMessage(message.id)
+ } else {
+ smsDb.deleteMessage(message.id)
+ }
+ }
+ }
+ else // If this thread is NOT in a Community
+ {
messageDataProvider.deleteMessage(message.id, !message.isMms)
messageDataProvider.getServerHashForMessage(message.id, message.isMms)?.let { serverHash ->
var publicKey = recipient.address.serialize()
@@ -218,6 +239,7 @@ class DefaultConversationRepository @Inject constructor(
.success {
continuation.resume(ResultOf.Success(Unit))
}.fail { error ->
+ Log.w("[onversationRepository", "Call to SnodeAPI.deleteMessage failed - attempting to resume..")
continuation.resumeWithException(error)
}
}
@@ -225,7 +247,7 @@ class DefaultConversationRepository @Inject constructor(
}
override fun buildUnsendRequest(recipient: Recipient, message: MessageRecord): UnsendRequest? {
- if (recipient.isOpenGroupRecipient) return null
+ if (recipient.isCommunityRecipient) return null
messageDataProvider.getServerHashForMessage(message.id, message.isMms) ?: return null
return UnsendRequest(
author = message.takeUnless { it.isOutgoing }?.run { individualRecipient.address.contactIdentifier() } ?: textSecurePreferences.getLocalNumber(),
@@ -279,8 +301,10 @@ class DefaultConversationRepository @Inject constructor(
override suspend fun banAndDeleteAll(threadId: Long, recipient: Recipient): ResultOf =
suspendCoroutine { continuation ->
+ // Note: This sessionId could be the blinded Id
val sessionID = recipient.address.toString()
val openGroup = lokiThreadDb.getOpenGroupChat(threadId)!!
+
OpenGroupApi.banAndDeleteAll(sessionID, openGroup.room, openGroup.server)
.success {
continuation.resume(ResultOf.Success(Unit))
diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ConfigurationMessageUtilities.kt b/app/src/main/java/org/thoughtcrime/securesms/util/ConfigurationMessageUtilities.kt
index 297014d86c..9d10cfdab5 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/util/ConfigurationMessageUtilities.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/util/ConfigurationMessageUtilities.kt
@@ -193,7 +193,7 @@ object ConfigurationMessageUtilities {
while (current != null) {
val recipient = current.recipient
val contact = when {
- recipient.isOpenGroupRecipient -> {
+ recipient.isCommunityRecipient -> {
val openGroup = storage.getOpenGroup(current.threadId) ?: continue
val (base, room, pubKey) = BaseCommunityInfo.parseFullUrl(openGroup.joinURL) ?: continue
convoConfig.getOrConstructCommunity(base, room, pubKey)
@@ -279,7 +279,7 @@ object ConfigurationMessageUtilities {
@JvmField
val DELETE_INACTIVE_ONE_TO_ONES: String = """
- DELETE FROM ${ThreadDatabase.TABLE_NAME} WHERE ${ThreadDatabase.MESSAGE_COUNT} <= 0 AND ${ThreadDatabase.ADDRESS} NOT LIKE '${GroupUtil.CLOSED_GROUP_PREFIX}%' AND ${ThreadDatabase.ADDRESS} NOT LIKE '${GroupUtil.OPEN_GROUP_PREFIX}%' AND ${ThreadDatabase.ADDRESS} NOT LIKE '${GroupUtil.OPEN_GROUP_INBOX_PREFIX}%';
+ DELETE FROM ${ThreadDatabase.TABLE_NAME} WHERE ${ThreadDatabase.MESSAGE_COUNT} <= 0 AND ${ThreadDatabase.ADDRESS} NOT LIKE '${GroupUtil.CLOSED_GROUP_PREFIX}%' AND ${ThreadDatabase.ADDRESS} NOT LIKE '${GroupUtil.COMMUNITY_PREFIX}%' AND ${ThreadDatabase.ADDRESS} NOT LIKE '${GroupUtil.COMMUNITY_INBOX_PREFIX}%';
""".trimIndent()
}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/SharedConfigUtils.kt b/app/src/main/java/org/thoughtcrime/securesms/util/SharedConfigUtils.kt
index b15d82a33e..3984f38b51 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/util/SharedConfigUtils.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/util/SharedConfigUtils.kt
@@ -14,7 +14,7 @@ fun ConversationVolatileConfig.getConversationUnread(thread: ThreadRecord): Bool
return getOneToOne(recipient.address.serialize())?.unread == true
} else if (recipient.isClosedGroupRecipient) {
return getLegacyClosedGroup(GroupUtil.doubleDecodeGroupId(recipient.address.toGroupString()))?.unread == true
- } else if (recipient.isOpenGroupRecipient) {
+ } else if (recipient.isCommunityRecipient) {
val openGroup = MessagingModuleConfiguration.shared.storage.getOpenGroup(thread.threadId) ?: return false
return getCommunity(openGroup.server, openGroup.room)?.unread == true
}
diff --git a/app/src/sharedTest/java/org/thoughtcrime/securesms/NoOpLogger.kt b/app/src/sharedTest/java/org/thoughtcrime/securesms/NoOpLogger.kt
new file mode 100644
index 0000000000..998c3b179d
--- /dev/null
+++ b/app/src/sharedTest/java/org/thoughtcrime/securesms/NoOpLogger.kt
@@ -0,0 +1,19 @@
+package org.thoughtcrime.securesms
+
+import org.session.libsignal.utilities.Log.Logger
+
+object NoOpLogger: Logger() {
+ override fun v(tag: String?, message: String?, t: Throwable?) {}
+
+ override fun d(tag: String?, message: String?, t: Throwable?) {}
+
+ override fun i(tag: String?, message: String?, t: Throwable?) {}
+
+ override fun w(tag: String?, message: String?, t: Throwable?) {}
+
+ override fun e(tag: String?, message: String?, t: Throwable?) {}
+
+ override fun wtf(tag: String?, message: String?, t: Throwable?) {}
+
+ override fun blockUntilAllWritesFinished() {}
+}
\ No newline at end of file
diff --git a/app/src/test/java/org/thoughtcrime/securesms/BaseViewModelTest.kt b/app/src/test/java/org/thoughtcrime/securesms/BaseViewModelTest.kt
index d73bc91a6d..a0f67fa699 100644
--- a/app/src/test/java/org/thoughtcrime/securesms/BaseViewModelTest.kt
+++ b/app/src/test/java/org/thoughtcrime/securesms/BaseViewModelTest.kt
@@ -1,10 +1,20 @@
package org.thoughtcrime.securesms
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import org.junit.BeforeClass
import org.junit.Rule
+import org.session.libsignal.utilities.Log
open class BaseViewModelTest: BaseCoroutineTest() {
+ companion object {
+ @BeforeClass
+ @JvmStatic
+ fun setupLogger() {
+ Log.initialize(NoOpLogger)
+ }
+ }
+
@get:Rule
var instantExecutorRule = InstantTaskExecutorRule()
diff --git a/app/src/test/java/org/thoughtcrime/securesms/conversation/disappearingmessages/DisappearingMessagesViewModelTest.kt b/app/src/test/java/org/thoughtcrime/securesms/conversation/disappearingmessages/DisappearingMessagesViewModelTest.kt
index 22679f311e..a9df5d946e 100644
--- a/app/src/test/java/org/thoughtcrime/securesms/conversation/disappearingmessages/DisappearingMessagesViewModelTest.kt
+++ b/app/src/test/java/org/thoughtcrime/securesms/conversation/disappearingmessages/DisappearingMessagesViewModelTest.kt
@@ -39,7 +39,7 @@ import kotlin.time.Duration.Companion.minutes
private const val THREAD_ID = 1L
private const val LOCAL_NUMBER = "05---local---address"
private val LOCAL_ADDRESS = Address.fromSerialized(LOCAL_NUMBER)
-private const val GROUP_NUMBER = "${GroupUtil.OPEN_GROUP_PREFIX}4133"
+private const val GROUP_NUMBER = "${GroupUtil.COMMUNITY_PREFIX}4133"
private val GROUP_ADDRESS = Address.fromSerialized(GROUP_NUMBER)
@OptIn(ExperimentalCoroutinesApi::class)
diff --git a/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModelTest.kt b/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModelTest.kt
index b89c62b6d5..37303e29d5 100644
--- a/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModelTest.kt
+++ b/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModelTest.kt
@@ -3,12 +3,14 @@ package org.thoughtcrime.securesms.conversation.v2
import com.goterl.lazysodium.utils.KeyPair
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.runBlocking
import org.hamcrest.CoreMatchers.endsWith
import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.CoreMatchers.notNullValue
import org.hamcrest.CoreMatchers.nullValue
import org.hamcrest.MatcherAssert.assertThat
import org.junit.Before
+import org.junit.BeforeClass
import org.junit.Test
import org.mockito.Mockito
import org.mockito.Mockito.anyLong
@@ -18,7 +20,9 @@ import org.mockito.kotlin.any
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import org.session.libsession.utilities.recipients.Recipient
+import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.BaseViewModelTest
+import org.thoughtcrime.securesms.NoOpLogger
import org.thoughtcrime.securesms.database.Storage
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.repository.ConversationRepository
@@ -32,6 +36,7 @@ class ConversationViewModelTest: BaseViewModelTest() {
private val threadId = 123L
private val edKeyPair = mock()
private lateinit var recipient: Recipient
+ private lateinit var messageRecord: MessageRecord
private val viewModel: ConversationViewModel by lazy {
ConversationViewModel(threadId, edKeyPair, repository, storage)
@@ -40,6 +45,9 @@ class ConversationViewModelTest: BaseViewModelTest() {
@Before
fun setUp() {
recipient = mock()
+ messageRecord = mock { record ->
+ whenever(record.individualRecipient).thenReturn(recipient)
+ }
whenever(repository.maybeGetRecipientForThreadId(anyLong())).thenReturn(recipient)
whenever(repository.recipientUpdateFlow(anyLong())).thenReturn(emptyFlow())
}
@@ -144,7 +152,7 @@ class ConversationViewModelTest: BaseViewModelTest() {
val error = Throwable()
whenever(repository.banAndDeleteAll(anyLong(), any())).thenReturn(ResultOf.Failure(error))
- viewModel.banAndDeleteAll(recipient)
+ viewModel.banAndDeleteAll(messageRecord)
assertThat(viewModel.uiState.first().uiMessages.first().message, endsWith("$error"))
}
@@ -153,7 +161,7 @@ class ConversationViewModelTest: BaseViewModelTest() {
fun `should emit a message on ban user and delete all success`() = runBlockingTest {
whenever(repository.banAndDeleteAll(anyLong(), any())).thenReturn(ResultOf.Success(Unit))
- viewModel.banAndDeleteAll(recipient)
+ viewModel.banAndDeleteAll(messageRecord)
assertThat(
viewModel.uiState.first().uiMessages.first().message,
@@ -189,7 +197,7 @@ class ConversationViewModelTest: BaseViewModelTest() {
@Test
fun `open group recipient should have no blinded recipient`() {
- whenever(recipient.isOpenGroupRecipient).thenReturn(true)
+ whenever(recipient.isCommunityRecipient).thenReturn(true)
whenever(recipient.isOpenGroupOutboxRecipient).thenReturn(false)
whenever(recipient.isOpenGroupInboxRecipient).thenReturn(false)
assertThat(viewModel.blindedRecipient, nullValue())
diff --git a/libsession/src/main/java/org/session/libsession/messaging/contacts/Contact.kt b/libsession/src/main/java/org/session/libsession/messaging/contacts/Contact.kt
index 92ff9190c5..7161d070aa 100644
--- a/libsession/src/main/java/org/session/libsession/messaging/contacts/Contact.kt
+++ b/libsession/src/main/java/org/session/libsession/messaging/contacts/Contact.kt
@@ -77,7 +77,7 @@ class Contact(val sessionID: String) {
companion object {
fun contextForRecipient(recipient: Recipient): ContactContext {
- return if (recipient.isOpenGroupRecipient) ContactContext.OPEN_GROUP else ContactContext.REGULAR
+ return if (recipient.isCommunityRecipient) ContactContext.OPEN_GROUP else ContactContext.REGULAR
}
}
}
\ No newline at end of file
diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/OpenGroupDeleteJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/OpenGroupDeleteJob.kt
index 333c87ba78..271549c410 100644
--- a/libsession/src/main/java/org/session/libsession/messaging/jobs/OpenGroupDeleteJob.kt
+++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/OpenGroupDeleteJob.kt
@@ -22,7 +22,7 @@ class OpenGroupDeleteJob(private val messageServerIds: LongArray, private val th
override suspend fun execute(dispatcherName: String) {
val dataProvider = MessagingModuleConfiguration.shared.messageDataProvider
val numberToDelete = messageServerIds.size
- Log.d(TAG, "Deleting $numberToDelete messages")
+ Log.d(TAG, "About to attempt to delete $numberToDelete messages")
// FIXME: This entire process should probably run in a transaction (with the attachment deletion happening only if it succeeded)
try {
@@ -42,6 +42,7 @@ class OpenGroupDeleteJob(private val messageServerIds: LongArray, private val th
delegate?.handleJobSucceeded(this, dispatcherName)
}
catch (e: Exception) {
+ Log.w(TAG, "OpenGroupDeleteJob failed: $e")
delegate?.handleJobFailed(this, dispatcherName, e)
}
}
diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt
index f30c1b9168..faad7aeebf 100644
--- a/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt
+++ b/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt
@@ -43,14 +43,14 @@ sealed class Destination {
val groupPublicKey = GroupUtil.doubleDecodeGroupID(groupID).toHexString()
ClosedGroup(groupPublicKey)
}
- address.isOpenGroup -> {
+ address.isCommunity -> {
val storage = MessagingModuleConfiguration.shared.storage
val threadID = storage.getThreadId(address)!!
storage.getOpenGroup(threadID)?.let {
OpenGroup(roomToken = it.room, server = it.server, fileIds = fileIds)
} ?: throw Exception("Missing open group for thread with ID: $threadID.")
}
- address.isOpenGroupInbox -> {
+ address.isCommunityInbox -> {
val groupInboxId = GroupUtil.getDecodedGroupID(address.serialize()).split("!")
OpenGroupInbox(
groupInboxId.dropLast(2).joinToString("!"),
diff --git a/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt b/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt
index a7b5051f51..1f23a1cc87 100644
--- a/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt
+++ b/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt
@@ -602,8 +602,7 @@ object OpenGroupApi {
// region Message Deletion
@JvmStatic
fun deleteMessage(serverID: Long, room: String, server: String): Promise {
- val request =
- Request(verb = DELETE, room = room, server = server, endpoint = Endpoint.RoomMessageIndividual(room, serverID))
+ val request = Request(verb = DELETE, room = room, server = server, endpoint = Endpoint.RoomMessageIndividual(room, serverID))
return send(request).map {
Log.d("Loki", "Message deletion successful.")
}
@@ -659,7 +658,9 @@ object OpenGroupApi {
}
fun banAndDeleteAll(publicKey: String, room: String, server: String): Promise {
+
val requests = mutableListOf>(
+ // Ban request
BatchRequestInfo(
request = BatchRequest(
method = POST,
@@ -669,6 +670,7 @@ object OpenGroupApi {
endpoint = Endpoint.UserBan(publicKey),
responseType = object: TypeReference(){}
),
+ // Delete request
BatchRequestInfo(
request = BatchRequest(DELETE, "/room/$room/all/$publicKey"),
endpoint = Endpoint.RoomDeleteMessages(room, publicKey),
diff --git a/libsession/src/main/java/org/session/libsession/utilities/Address.kt b/libsession/src/main/java/org/session/libsession/utilities/Address.kt
index e265e28e7d..920b466a8b 100644
--- a/libsession/src/main/java/org/session/libsession/utilities/Address.kt
+++ b/libsession/src/main/java/org/session/libsession/utilities/Address.kt
@@ -22,17 +22,17 @@ class Address private constructor(address: String) : Parcelable, Comparable