mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-05-08 09:18:39 +01:00
Convert GroupTable to kotlin.
Also required converting some tests to mockk.
This commit is contained in:
+4
-4
@@ -11,9 +11,9 @@ import org.signal.core.util.logging.Log
|
|||||||
import org.signal.storageservice.protos.groups.local.DecryptedGroup
|
import org.signal.storageservice.protos.groups.local.DecryptedGroup
|
||||||
import org.signal.storageservice.protos.groups.local.DecryptedPendingMember
|
import org.signal.storageservice.protos.groups.local.DecryptedPendingMember
|
||||||
import org.thoughtcrime.securesms.contacts.sync.ContactDiscovery
|
import org.thoughtcrime.securesms.contacts.sync.ContactDiscovery
|
||||||
import org.thoughtcrime.securesms.database.GroupTable
|
|
||||||
import org.thoughtcrime.securesms.database.MediaTable
|
import org.thoughtcrime.securesms.database.MediaTable
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord
|
||||||
import org.thoughtcrime.securesms.database.model.IdentityRecord
|
import org.thoughtcrime.securesms.database.model.IdentityRecord
|
||||||
import org.thoughtcrime.securesms.database.model.StoryViewState
|
import org.thoughtcrime.securesms.database.model.StoryViewState
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||||
@@ -70,7 +70,7 @@ class ConversationSettingsRepository(
|
|||||||
fun isInternalRecipientDetailsEnabled(): Boolean = SignalStore.internalValues().recipientDetails()
|
fun isInternalRecipientDetailsEnabled(): Boolean = SignalStore.internalValues().recipientDetails()
|
||||||
|
|
||||||
fun hasGroups(consumer: (Boolean) -> Unit) {
|
fun hasGroups(consumer: (Boolean) -> Unit) {
|
||||||
SignalExecutors.BOUNDED.execute { consumer(SignalDatabase.groups.activeGroupCount > 0) }
|
SignalExecutors.BOUNDED.execute { consumer(SignalDatabase.groups.getActiveGroupCount() > 0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getIdentity(recipientId: RecipientId, consumer: (IdentityRecord?) -> Unit) {
|
fun getIdentity(recipientId: RecipientId, consumer: (IdentityRecord?) -> Unit) {
|
||||||
@@ -91,7 +91,7 @@ class ConversationSettingsRepository(
|
|||||||
.getPushGroupsContainingMember(recipientId)
|
.getPushGroupsContainingMember(recipientId)
|
||||||
.asSequence()
|
.asSequence()
|
||||||
.filter { it.members.contains(Recipient.self().id) }
|
.filter { it.members.contains(Recipient.self().id) }
|
||||||
.map(GroupTable.GroupRecord::getRecipientId)
|
.map(GroupRecord::recipientId)
|
||||||
.map(Recipient::resolved)
|
.map(Recipient::resolved)
|
||||||
.sortedBy { gr -> gr.getDisplayName(context) }
|
.sortedBy { gr -> gr.getDisplayName(context) }
|
||||||
.toList()
|
.toList()
|
||||||
@@ -129,7 +129,7 @@ class ConversationSettingsRepository(
|
|||||||
|
|
||||||
fun getGroupCapacity(groupId: GroupId, consumer: (GroupCapacityResult) -> Unit) {
|
fun getGroupCapacity(groupId: GroupId, consumer: (GroupCapacityResult) -> Unit) {
|
||||||
SignalExecutors.BOUNDED.execute {
|
SignalExecutors.BOUNDED.execute {
|
||||||
val groupRecord: GroupTable.GroupRecord = SignalDatabase.groups.getGroup(groupId).get()
|
val groupRecord: GroupRecord = SignalDatabase.groups.getGroup(groupId).get()
|
||||||
consumer(
|
consumer(
|
||||||
if (groupRecord.isV2Group) {
|
if (groupRecord.isV2Group) {
|
||||||
val decryptedGroup: DecryptedGroup = groupRecord.requireV2GroupProperties().decryptedGroup
|
val decryptedGroup: DecryptedGroup = groupRecord.requireV2GroupProperties().decryptedGroup
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import org.thoughtcrime.securesms.database.GroupTable;
|
|||||||
import org.thoughtcrime.securesms.database.RecipientTable;
|
import org.thoughtcrime.securesms.database.RecipientTable;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
import org.thoughtcrime.securesms.database.ThreadTable;
|
import org.thoughtcrime.securesms.database.ThreadTable;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||||
import org.thoughtcrime.securesms.phonenumbers.NumberUtil;
|
import org.thoughtcrime.securesms.phonenumbers.NumberUtil;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
@@ -221,11 +222,11 @@ public class ContactsCursorLoader extends AbstractContactsCursorLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Cursor getGroupsCursor() {
|
private Cursor getGroupsCursor() {
|
||||||
MatrixCursor groupContacts = ContactsCursorRows.createMatrixCursor();
|
MatrixCursor groupContacts = ContactsCursorRows.createMatrixCursor();
|
||||||
Map<RecipientId, GroupTable.GroupRecord> groups = new LinkedHashMap<>();
|
Map<RecipientId, GroupRecord> groups = new LinkedHashMap<>();
|
||||||
|
|
||||||
try (GroupTable.Reader reader = SignalDatabase.groups().queryGroupsByTitle(getFilter(), flagSet(mode, DisplayMode.FLAG_INACTIVE_GROUPS), hideGroupsV1(mode), !smsEnabled(mode))) {
|
try (GroupTable.Reader reader = SignalDatabase.groups().queryGroupsByTitle(getFilter(), flagSet(mode, DisplayMode.FLAG_INACTIVE_GROUPS), hideGroupsV1(mode), !smsEnabled(mode))) {
|
||||||
GroupTable.GroupRecord groupRecord;
|
GroupRecord groupRecord;
|
||||||
while ((groupRecord = reader.getNext()) != null) {
|
while ((groupRecord = reader.getNext()) != null) {
|
||||||
groups.put(groupRecord.getRecipientId(), groupRecord);
|
groups.put(groupRecord.getRecipientId(), groupRecord);
|
||||||
}
|
}
|
||||||
@@ -240,14 +241,14 @@ public class ContactsCursorLoader extends AbstractContactsCursorLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try (GroupTable.Reader reader = SignalDatabase.groups().queryGroupsByMembership(filteredContacts, flagSet(mode, DisplayMode.FLAG_INACTIVE_GROUPS), hideGroupsV1(mode), !smsEnabled(mode))) {
|
try (GroupTable.Reader reader = SignalDatabase.groups().queryGroupsByMembership(filteredContacts, flagSet(mode, DisplayMode.FLAG_INACTIVE_GROUPS), hideGroupsV1(mode), !smsEnabled(mode))) {
|
||||||
GroupTable.GroupRecord groupRecord;
|
GroupRecord groupRecord;
|
||||||
while ((groupRecord = reader.getNext()) != null) {
|
while ((groupRecord = reader.getNext()) != null) {
|
||||||
groups.put(groupRecord.getRecipientId(), groupRecord);
|
groups.put(groupRecord.getRecipientId(), groupRecord);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (GroupTable.GroupRecord groupRecord : groups.values()) {
|
for (GroupRecord groupRecord : groups.values()) {
|
||||||
groupContacts.addRow(ContactsCursorRows.forGroup(groupRecord));
|
groupContacts.addRow(ContactsCursorRows.forGroup(groupRecord));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import android.provider.ContactsContract;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.whispersystems.signalservice.api.util.OptionalUtil;
|
import org.whispersystems.signalservice.api.util.OptionalUtil;
|
||||||
@@ -74,7 +74,7 @@ public final class ContactsCursorRows {
|
|||||||
/**
|
/**
|
||||||
* Create a row for a contacts cursor based off the given group record.
|
* Create a row for a contacts cursor based off the given group record.
|
||||||
*/
|
*/
|
||||||
public static @NonNull Object[] forGroup(@NonNull GroupTable.GroupRecord groupRecord) {
|
public static @NonNull Object[] forGroup(@NonNull GroupRecord groupRecord) {
|
||||||
return new Object[]{groupRecord.getRecipientId().serialize(),
|
return new Object[]{groupRecord.getRecipientId().serialize(),
|
||||||
groupRecord.getTitle(),
|
groupRecord.getTitle(),
|
||||||
groupRecord.getId(),
|
groupRecord.getId(),
|
||||||
|
|||||||
+3
-2
@@ -10,6 +10,7 @@ import androidx.annotation.Nullable;
|
|||||||
import org.signal.core.util.Conversions;
|
import org.signal.core.util.Conversions;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
import org.thoughtcrime.securesms.database.GroupTable;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.profiles.AvatarHelper;
|
import org.thoughtcrime.securesms.profiles.AvatarHelper;
|
||||||
|
|
||||||
@@ -30,8 +31,8 @@ public final class GroupRecordContactPhoto implements ContactPhoto {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InputStream openInputStream(Context context) throws IOException {
|
public InputStream openInputStream(Context context) throws IOException {
|
||||||
GroupTable groupDatabase = SignalDatabase.groups();
|
GroupTable groupDatabase = SignalDatabase.groups();
|
||||||
Optional<GroupTable.GroupRecord> groupRecord = groupDatabase.getGroup(groupId);
|
Optional<GroupRecord> groupRecord = groupDatabase.getGroup(groupId);
|
||||||
|
|
||||||
if (!groupRecord.isPresent() || !AvatarHelper.hasAvatar(context, groupRecord.get().getRecipientId())) {
|
if (!groupRecord.isPresent() || !AvatarHelper.hasAvatar(context, groupRecord.get().getRecipientId())) {
|
||||||
throw new IOException("No avatar for group: " + groupId);
|
throw new IOException("No avatar for group: " + groupId);
|
||||||
|
|||||||
+1
-1
@@ -6,8 +6,8 @@ import org.thoughtcrime.securesms.contacts.paged.collections.ContactSearchCollec
|
|||||||
import org.thoughtcrime.securesms.contacts.paged.collections.ContactSearchIterator
|
import org.thoughtcrime.securesms.contacts.paged.collections.ContactSearchIterator
|
||||||
import org.thoughtcrime.securesms.contacts.paged.collections.CursorSearchIterator
|
import org.thoughtcrime.securesms.contacts.paged.collections.CursorSearchIterator
|
||||||
import org.thoughtcrime.securesms.contacts.paged.collections.StoriesSearchCollection
|
import org.thoughtcrime.securesms.contacts.paged.collections.StoriesSearchCollection
|
||||||
import org.thoughtcrime.securesms.database.GroupTable.GroupRecord
|
|
||||||
import org.thoughtcrime.securesms.database.model.DistributionListPrivacyMode
|
import org.thoughtcrime.securesms.database.model.DistributionListPrivacyMode
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||||
import org.thoughtcrime.securesms.keyvalue.StorySend
|
import org.thoughtcrime.securesms.keyvalue.StorySend
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
|
|||||||
+2
-2
@@ -8,10 +8,10 @@ import org.thoughtcrime.securesms.contacts.ContactRepository
|
|||||||
import org.thoughtcrime.securesms.contacts.paged.collections.ContactSearchIterator
|
import org.thoughtcrime.securesms.contacts.paged.collections.ContactSearchIterator
|
||||||
import org.thoughtcrime.securesms.database.DistributionListTables
|
import org.thoughtcrime.securesms.database.DistributionListTables
|
||||||
import org.thoughtcrime.securesms.database.GroupTable
|
import org.thoughtcrime.securesms.database.GroupTable
|
||||||
import org.thoughtcrime.securesms.database.GroupTable.GroupRecord
|
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||||
import org.thoughtcrime.securesms.database.ThreadTable
|
import org.thoughtcrime.securesms.database.ThreadTable
|
||||||
import org.thoughtcrime.securesms.database.model.DistributionListPrivacyMode
|
import org.thoughtcrime.securesms.database.model.DistributionListPrivacyMode
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
import org.thoughtcrime.securesms.keyvalue.StorySend
|
import org.thoughtcrime.securesms.keyvalue.StorySend
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
@@ -104,7 +104,7 @@ open class ContactSearchPagedDataSourceRepository(
|
|||||||
}
|
}
|
||||||
|
|
||||||
open fun getGroupStories(): Set<ContactSearchData.Story> {
|
open fun getGroupStories(): Set<ContactSearchData.Story> {
|
||||||
return SignalDatabase.groups.groupsToDisplayAsStories.map {
|
return SignalDatabase.groups.getGroupsToDisplayAsStories().map {
|
||||||
val recipient = Recipient.resolved(SignalDatabase.recipients.getOrInsertFromGroupId(it))
|
val recipient = Recipient.resolved(SignalDatabase.recipients.getOrInsertFromGroupId(it))
|
||||||
ContactSearchData.Story(recipient, recipient.participantIds.size, DistributionListPrivacyMode.ALL)
|
ContactSearchData.Story(recipient, recipient.participantIds.size, DistributionListPrivacyMode.ALL)
|
||||||
}.toSet()
|
}.toSet()
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@ import com.annimon.stream.Stream;
|
|||||||
|
|
||||||
import org.signal.core.util.concurrent.SignalExecutors;
|
import org.signal.core.util.concurrent.SignalExecutors;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
import org.thoughtcrime.securesms.database.GroupTable;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable.GroupRecord;
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
|
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
|
||||||
|
|||||||
+2
-1
@@ -328,7 +328,8 @@ import io.reactivex.rxjava3.core.Flowable;
|
|||||||
import io.reactivex.rxjava3.disposables.Disposable;
|
import io.reactivex.rxjava3.disposables.Disposable;
|
||||||
|
|
||||||
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
|
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
|
||||||
import static org.thoughtcrime.securesms.database.GroupTable.GroupRecord;
|
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fragment for displaying a message thread, as well as
|
* Fragment for displaying a message thread, as well as
|
||||||
|
|||||||
+2
-2
@@ -10,11 +10,11 @@ import org.signal.core.util.concurrent.SignalExecutors;
|
|||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.contacts.sync.ContactDiscovery;
|
import org.thoughtcrime.securesms.contacts.sync.ContactDiscovery;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseObserver;
|
import org.thoughtcrime.securesms.database.DatabaseObserver;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
|
||||||
import org.thoughtcrime.securesms.database.MessageTable;
|
import org.thoughtcrime.securesms.database.MessageTable;
|
||||||
import org.thoughtcrime.securesms.database.RecipientTable;
|
import org.thoughtcrime.securesms.database.RecipientTable;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
import org.thoughtcrime.securesms.database.ThreadTable;
|
import org.thoughtcrime.securesms.database.ThreadTable;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.jobs.MultiDeviceViewedUpdateJob;
|
import org.thoughtcrime.securesms.jobs.MultiDeviceViewedUpdateJob;
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
@@ -84,7 +84,7 @@ class ConversationRepository {
|
|||||||
boolean isGroup = false;
|
boolean isGroup = false;
|
||||||
boolean recipientIsKnownOrHasGroupsInCommon = false;
|
boolean recipientIsKnownOrHasGroupsInCommon = false;
|
||||||
if (conversationRecipient.isGroup()) {
|
if (conversationRecipient.isGroup()) {
|
||||||
Optional<GroupTable.GroupRecord> group = SignalDatabase.groups().getGroup(conversationRecipient.getId());
|
Optional<GroupRecord> group = SignalDatabase.groups().getGroup(conversationRecipient.getId());
|
||||||
if (group.isPresent()) {
|
if (group.isPresent()) {
|
||||||
List<Recipient> recipients = Recipient.resolvedList(group.get().getMembers());
|
List<Recipient> recipients = Recipient.resolvedList(group.get().getMembers());
|
||||||
for (Recipient recipient : recipients) {
|
for (Recipient recipient : recipients) {
|
||||||
|
|||||||
+2
-2
@@ -15,8 +15,8 @@ import androidx.fragment.app.FragmentManager;
|
|||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.groups.ParcelableGroupId;
|
import org.thoughtcrime.securesms.groups.ParcelableGroupId;
|
||||||
import org.thoughtcrime.securesms.groups.ui.GroupMemberListView;
|
import org.thoughtcrime.securesms.groups.ui.GroupMemberListView;
|
||||||
@@ -94,7 +94,7 @@ public final class ShowAdminsBottomSheetDialog extends BottomSheetDialogFragment
|
|||||||
private static @NonNull List<Recipient> getAdmins(@NonNull Context context, @NonNull GroupId groupId) {
|
private static @NonNull List<Recipient> getAdmins(@NonNull Context context, @NonNull GroupId groupId) {
|
||||||
return SignalDatabase.groups()
|
return SignalDatabase.groups()
|
||||||
.getGroup(groupId)
|
.getGroup(groupId)
|
||||||
.map(GroupTable.GroupRecord::getAdmins)
|
.map(GroupRecord::getAdmins)
|
||||||
.orElse(Collections.emptyList());
|
.orElse(Collections.emptyList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -54,6 +54,7 @@ import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
|||||||
import org.thoughtcrime.securesms.database.documents.NetworkFailureSet;
|
import org.thoughtcrime.securesms.database.documents.NetworkFailureSet;
|
||||||
import org.thoughtcrime.securesms.database.model.DisplayRecord;
|
import org.thoughtcrime.securesms.database.model.DisplayRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.GroupCallUpdateDetailsUtil;
|
import org.thoughtcrime.securesms.database.model.GroupCallUpdateDetailsUtil;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.Mention;
|
import org.thoughtcrime.securesms.database.model.Mention;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageExportStatus;
|
import org.thoughtcrime.securesms.database.model.MessageExportStatus;
|
||||||
@@ -941,9 +942,9 @@ public class MessageTable extends DatabaseTable implements MessageTypes, Recipie
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void insertProfileNameChangeMessages(@NonNull Recipient recipient, @NonNull String newProfileName, @NonNull String previousProfileName) {
|
public void insertProfileNameChangeMessages(@NonNull Recipient recipient, @NonNull String newProfileName, @NonNull String previousProfileName) {
|
||||||
ThreadTable threadTable = SignalDatabase.threads();
|
ThreadTable threadTable = SignalDatabase.threads();
|
||||||
List<GroupTable.GroupRecord> groupRecords = SignalDatabase.groups().getGroupsContainingMember(recipient.getId(), false);
|
List<GroupRecord> groupRecords = SignalDatabase.groups().getGroupsContainingMember(recipient.getId(), false);
|
||||||
List<Long> threadIdsToUpdate = new LinkedList<>();
|
List<Long> threadIdsToUpdate = new LinkedList<>();
|
||||||
|
|
||||||
byte[] profileChangeDetails = ProfileChangeDetails.newBuilder()
|
byte[] profileChangeDetails = ProfileChangeDetails.newBuilder()
|
||||||
.setProfileNameChange(ProfileChangeDetails.StringChange.newBuilder()
|
.setProfileNameChange(ProfileChangeDetails.StringChange.newBuilder()
|
||||||
@@ -959,7 +960,7 @@ public class MessageTable extends DatabaseTable implements MessageTypes, Recipie
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
threadIdsToUpdate.add(threadTable.getThreadIdFor(recipient.getId()));
|
threadIdsToUpdate.add(threadTable.getThreadIdFor(recipient.getId()));
|
||||||
for (GroupTable.GroupRecord groupRecord : groupRecords) {
|
for (GroupRecord groupRecord : groupRecords) {
|
||||||
if (groupRecord.isActive()) {
|
if (groupRecord.isActive()) {
|
||||||
threadIdsToUpdate.add(threadTable.getThreadIdFor(groupRecord.getRecipientId()));
|
threadIdsToUpdate.add(threadTable.getThreadIdFor(groupRecord.getRecipientId()));
|
||||||
}
|
}
|
||||||
@@ -1032,16 +1033,16 @@ public class MessageTable extends DatabaseTable implements MessageTypes, Recipie
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void insertNumberChangeMessages(@NonNull RecipientId recipientId) {
|
public void insertNumberChangeMessages(@NonNull RecipientId recipientId) {
|
||||||
ThreadTable threadTable = SignalDatabase.threads();
|
ThreadTable threadTable = SignalDatabase.threads();
|
||||||
List<GroupTable.GroupRecord> groupRecords = SignalDatabase.groups().getGroupsContainingMember(recipientId, false);
|
List<GroupRecord> groupRecords = SignalDatabase.groups().getGroupsContainingMember(recipientId, false);
|
||||||
List<Long> threadIdsToUpdate = new LinkedList<>();
|
List<Long> threadIdsToUpdate = new LinkedList<>();
|
||||||
|
|
||||||
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
|
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
|
||||||
db.beginTransaction();
|
db.beginTransaction();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
threadIdsToUpdate.add(threadTable.getThreadIdFor(recipientId));
|
threadIdsToUpdate.add(threadTable.getThreadIdFor(recipientId));
|
||||||
for (GroupTable.GroupRecord groupRecord : groupRecords) {
|
for (GroupRecord groupRecord : groupRecords) {
|
||||||
if (groupRecord.isActive()) {
|
if (groupRecord.isActive()) {
|
||||||
threadIdsToUpdate.add(threadTable.getThreadIdFor(groupRecord.getRecipientId()));
|
threadIdsToUpdate.add(threadTable.getThreadIdFor(groupRecord.getRecipientId()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1186,7 +1186,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (id in groups.allGroupV2Ids) {
|
for (id in groups.getAllGroupV2Ids()) {
|
||||||
val recipient = Recipient.externalGroupExact(id!!)
|
val recipient = Recipient.externalGroupExact(id!!)
|
||||||
val recipientId = recipient.id
|
val recipientId = recipient.id
|
||||||
val existing: RecipientRecord = getRecordForSync(recipientId) ?: throw AssertionError()
|
val existing: RecipientRecord = getRecordForSync(recipientId) ?: throw AssertionError()
|
||||||
|
|||||||
@@ -1670,7 +1670,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
|||||||
val recipientSettings = recipients.getRecord(context, cursor, RECIPIENT_ID)
|
val recipientSettings = recipients.getRecord(context, cursor, RECIPIENT_ID)
|
||||||
|
|
||||||
val recipient: Recipient = if (recipientSettings.groupId != null) {
|
val recipient: Recipient = if (recipientSettings.groupId != null) {
|
||||||
GroupTable.Reader(cursor).current?.let { group ->
|
GroupTable.Reader(cursor).getCurrent()?.let { group ->
|
||||||
val details = RecipientDetails(
|
val details = RecipientDetails(
|
||||||
group.title,
|
group.title,
|
||||||
null,
|
null,
|
||||||
|
|||||||
@@ -0,0 +1,163 @@
|
|||||||
|
package org.thoughtcrime.securesms.database.model
|
||||||
|
|
||||||
|
import androidx.annotation.WorkerThread
|
||||||
|
import org.signal.libsignal.zkgroup.groups.GroupMasterKey
|
||||||
|
import org.signal.storageservice.protos.groups.AccessControl
|
||||||
|
import org.signal.storageservice.protos.groups.local.EnabledState
|
||||||
|
import org.thoughtcrime.securesms.database.GroupTable
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupAccessControl
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupId
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
|
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||||
|
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil
|
||||||
|
import org.whispersystems.signalservice.api.push.DistributionId
|
||||||
|
import java.lang.AssertionError
|
||||||
|
import java.util.Optional
|
||||||
|
|
||||||
|
class GroupRecord(
|
||||||
|
val id: GroupId,
|
||||||
|
val recipientId: RecipientId,
|
||||||
|
val title: String?,
|
||||||
|
serializedMembers: String?,
|
||||||
|
serializedUnmigratedV1Members: String?,
|
||||||
|
val avatarId: Long,
|
||||||
|
val avatarKey: ByteArray?,
|
||||||
|
val avatarContentType: String?,
|
||||||
|
val relay: String?,
|
||||||
|
val isActive: Boolean,
|
||||||
|
val avatarDigest: ByteArray?,
|
||||||
|
val isMms: Boolean,
|
||||||
|
groupMasterKeyBytes: ByteArray?,
|
||||||
|
groupRevision: Int,
|
||||||
|
decryptedGroupBytes: ByteArray?,
|
||||||
|
val distributionId: DistributionId?,
|
||||||
|
val lastForceUpdateTimestamp: Long
|
||||||
|
) {
|
||||||
|
|
||||||
|
val members: List<RecipientId> by lazy {
|
||||||
|
if (serializedMembers.isNullOrEmpty()) {
|
||||||
|
emptyList()
|
||||||
|
} else {
|
||||||
|
RecipientId.fromSerializedList(serializedMembers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** V1 members that were lost during the V1->V2 migration */
|
||||||
|
val unmigratedV1Members: List<RecipientId> by lazy {
|
||||||
|
if (serializedUnmigratedV1Members.isNullOrEmpty()) {
|
||||||
|
emptyList()
|
||||||
|
} else {
|
||||||
|
RecipientId.fromSerializedList(serializedUnmigratedV1Members)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val v2GroupProperties: GroupTable.V2GroupProperties? by lazy {
|
||||||
|
if (groupMasterKeyBytes != null && decryptedGroupBytes != null) {
|
||||||
|
val groupMasterKey = GroupMasterKey(groupMasterKeyBytes)
|
||||||
|
GroupTable.V2GroupProperties(groupMasterKey, groupRevision, decryptedGroupBytes)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val description: String
|
||||||
|
get() = v2GroupProperties?.decryptedGroup?.description ?: ""
|
||||||
|
|
||||||
|
val isAnnouncementGroup: Boolean
|
||||||
|
get() = v2GroupProperties?.decryptedGroup?.isAnnouncementGroup == EnabledState.ENABLED
|
||||||
|
|
||||||
|
val isV1Group: Boolean
|
||||||
|
get() = !isMms && !isV2Group
|
||||||
|
|
||||||
|
val isV2Group: Boolean
|
||||||
|
get() = v2GroupProperties != null
|
||||||
|
|
||||||
|
@get:WorkerThread
|
||||||
|
val admins: List<Recipient>
|
||||||
|
get() {
|
||||||
|
return if (v2GroupProperties != null) {
|
||||||
|
val resolved = members.map { Recipient.resolved(it) }
|
||||||
|
v2GroupProperties!!.getAdmins(resolved)
|
||||||
|
} else {
|
||||||
|
emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Who is allowed to add to the membership of this group. */
|
||||||
|
val membershipAdditionAccessControl: GroupAccessControl
|
||||||
|
get() {
|
||||||
|
return if (isV2Group) {
|
||||||
|
if (requireV2GroupProperties().decryptedGroup.accessControl.members == AccessControl.AccessRequired.MEMBER) {
|
||||||
|
GroupAccessControl.ALL_MEMBERS
|
||||||
|
} else {
|
||||||
|
GroupAccessControl.ONLY_ADMINS
|
||||||
|
}
|
||||||
|
} else if (isV1Group) {
|
||||||
|
GroupAccessControl.NO_ONE
|
||||||
|
} else if (id.isV1) {
|
||||||
|
GroupAccessControl.ALL_MEMBERS
|
||||||
|
} else {
|
||||||
|
GroupAccessControl.ONLY_ADMINS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Who is allowed to modify the attributes of this group, name/avatar/timer etc. */
|
||||||
|
val attributesAccessControl: GroupAccessControl
|
||||||
|
get() {
|
||||||
|
return if (isV2Group) {
|
||||||
|
if (requireV2GroupProperties().decryptedGroup.accessControl.attributes == AccessControl.AccessRequired.MEMBER) {
|
||||||
|
GroupAccessControl.ALL_MEMBERS
|
||||||
|
} else {
|
||||||
|
GroupAccessControl.ONLY_ADMINS
|
||||||
|
}
|
||||||
|
} else if (isV1Group) {
|
||||||
|
GroupAccessControl.NO_ONE
|
||||||
|
} else {
|
||||||
|
GroupAccessControl.ALL_MEMBERS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hasAvatar(): Boolean {
|
||||||
|
return avatarId != 0L
|
||||||
|
}
|
||||||
|
|
||||||
|
fun requireV2GroupProperties(): GroupTable.V2GroupProperties {
|
||||||
|
return v2GroupProperties ?: throw AssertionError()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isAdmin(recipient: Recipient): Boolean {
|
||||||
|
return isV2Group && requireV2GroupProperties().isAdmin(recipient)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun memberLevel(recipient: Recipient): GroupTable.MemberLevel {
|
||||||
|
return if (isV2Group) {
|
||||||
|
val memberLevel = requireV2GroupProperties().memberLevel(recipient.serviceId)
|
||||||
|
if (recipient.isSelf && memberLevel == GroupTable.MemberLevel.NOT_A_MEMBER) {
|
||||||
|
requireV2GroupProperties().memberLevel(Optional.ofNullable(SignalStore.account().pni))
|
||||||
|
} else {
|
||||||
|
memberLevel
|
||||||
|
}
|
||||||
|
} else if (isMms && recipient.isSelf) {
|
||||||
|
GroupTable.MemberLevel.FULL_MEMBER
|
||||||
|
} else if (members.contains(recipient.id)) {
|
||||||
|
GroupTable.MemberLevel.FULL_MEMBER
|
||||||
|
} else {
|
||||||
|
GroupTable.MemberLevel.NOT_A_MEMBER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the recipient is a pending member.
|
||||||
|
*/
|
||||||
|
fun isPendingMember(recipient: Recipient): Boolean {
|
||||||
|
if (isV2Group) {
|
||||||
|
val serviceId = recipient.serviceId
|
||||||
|
if (serviceId.isPresent) {
|
||||||
|
return DecryptedGroupUtil.findPendingByUuid(requireV2GroupProperties().decryptedGroup.pendingMembersList, serviceId.get().uuid())
|
||||||
|
.isPresent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ import org.signal.core.util.concurrent.SignalExecutors;
|
|||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
import org.thoughtcrime.securesms.database.GroupTable;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.groups.GroupManager;
|
import org.thoughtcrime.securesms.groups.GroupManager;
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
@@ -78,7 +79,7 @@ class DeleteAccountRepository {
|
|||||||
|
|
||||||
int groupsLeft = 0;
|
int groupsLeft = 0;
|
||||||
try (GroupTable.Reader groups = SignalDatabase.groups().getGroups()) {
|
try (GroupTable.Reader groups = SignalDatabase.groups().getGroups()) {
|
||||||
GroupTable.GroupRecord groupRecord = groups.getNext();
|
GroupRecord groupRecord = groups.getNext();
|
||||||
onDeleteAccountEvent.accept(new DeleteAccountEvent.LeaveGroupsProgress(groups.getCount(), 0));
|
onDeleteAccountEvent.accept(new DeleteAccountEvent.LeaveGroupsProgress(groups.getCount(), 0));
|
||||||
Log.i(TAG, "deleteAccount: found " + groups.getCount() + " groups to leave.");
|
Log.i(TAG, "deleteAccount: found " + groups.getCount() + " groups to leave.");
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import org.signal.storageservice.protos.groups.local.DecryptedGroup;
|
|||||||
import org.signal.storageservice.protos.groups.local.DecryptedGroupJoinInfo;
|
import org.signal.storageservice.protos.groups.local.DecryptedGroupJoinInfo;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
import org.thoughtcrime.securesms.database.GroupTable;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.groups.v2.GroupInviteLinkUrl;
|
import org.thoughtcrime.securesms.groups.v2.GroupInviteLinkUrl;
|
||||||
import org.thoughtcrime.securesms.groups.v2.GroupLinkPassword;
|
import org.thoughtcrime.securesms.groups.v2.GroupLinkPassword;
|
||||||
import org.thoughtcrime.securesms.profiles.AvatarHelper;
|
import org.thoughtcrime.securesms.profiles.AvatarHelper;
|
||||||
@@ -402,14 +403,14 @@ public final class GroupManager {
|
|||||||
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException, GroupChangeBusyException, MembershipNotSuitableForV2Exception
|
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException, GroupChangeBusyException, MembershipNotSuitableForV2Exception
|
||||||
{
|
{
|
||||||
if (groupId.isV2()) {
|
if (groupId.isV2()) {
|
||||||
GroupTable.GroupRecord groupRecord = SignalDatabase.groups().requireGroup(groupId);
|
GroupRecord groupRecord = SignalDatabase.groups().requireGroup(groupId);
|
||||||
|
|
||||||
try (GroupManagerV2.GroupEditor editor = new GroupManagerV2(context).edit(groupId.requireV2())) {
|
try (GroupManagerV2.GroupEditor editor = new GroupManagerV2(context).edit(groupId.requireV2())) {
|
||||||
return editor.addMembers(newMembers, groupRecord.requireV2GroupProperties().getBannedMembers());
|
return editor.addMembers(newMembers, groupRecord.requireV2GroupProperties().getBannedMembers());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
GroupTable.GroupRecord groupRecord = SignalDatabase.groups().requireGroup(groupId);
|
GroupRecord groupRecord = SignalDatabase.groups().requireGroup(groupId);
|
||||||
List<RecipientId> members = groupRecord.getMembers();
|
List<RecipientId> members = groupRecord.getMembers();
|
||||||
byte[] avatar = groupRecord.hasAvatar() ? AvatarHelper.getAvatarBytes(context, groupRecord.getRecipientId()) : null;
|
byte[] avatar = groupRecord.hasAvatar() ? AvatarHelper.getAvatarBytes(context, groupRecord.getRecipientId()) : null;
|
||||||
Set<RecipientId> recipientIds = new HashSet<>(members);
|
Set<RecipientId> recipientIds = new HashSet<>(members);
|
||||||
int originalSize = recipientIds.size();
|
int originalSize = recipientIds.size();
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
|
|||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
import org.thoughtcrime.securesms.database.GroupTable;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
import org.thoughtcrime.securesms.database.ThreadTable;
|
import org.thoughtcrime.securesms.database.ThreadTable;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2Context;
|
import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2Context;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.groups.v2.GroupCandidateHelper;
|
import org.thoughtcrime.securesms.groups.v2.GroupCandidateHelper;
|
||||||
@@ -167,8 +168,8 @@ final class GroupManagerV2 {
|
|||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
@NonNull Map<UUID, UuidCiphertext> getUuidCipherTexts(@NonNull GroupId.V2 groupId) {
|
@NonNull Map<UUID, UuidCiphertext> getUuidCipherTexts(@NonNull GroupId.V2 groupId) {
|
||||||
GroupTable.GroupRecord groupRecord = SignalDatabase.groups().requireGroup(groupId);
|
GroupRecord groupRecord = SignalDatabase.groups().requireGroup(groupId);
|
||||||
GroupTable.V2GroupProperties v2GroupProperties = groupRecord.requireV2GroupProperties();
|
GroupTable.V2GroupProperties v2GroupProperties = groupRecord.requireV2GroupProperties();
|
||||||
GroupMasterKey groupMasterKey = v2GroupProperties.getGroupMasterKey();
|
GroupMasterKey groupMasterKey = v2GroupProperties.getGroupMasterKey();
|
||||||
ClientZkGroupCipher clientZkGroupCipher = new ClientZkGroupCipher(GroupSecretParams.deriveFromMasterKey(groupMasterKey));
|
ClientZkGroupCipher clientZkGroupCipher = new ClientZkGroupCipher(GroupSecretParams.deriveFromMasterKey(groupMasterKey));
|
||||||
List<Recipient> recipients = v2GroupProperties.getMemberRecipients(GroupTable.MemberSet.FULL_MEMBERS_INCLUDING_SELF);
|
List<Recipient> recipients = v2GroupProperties.getMemberRecipients(GroupTable.MemberSet.FULL_MEMBERS_INCLUDING_SELF);
|
||||||
@@ -251,9 +252,9 @@ final class GroupManagerV2 {
|
|||||||
throws IOException, MembershipNotSuitableForV2Exception, GroupAlreadyExistsException, GroupChangeFailedException
|
throws IOException, MembershipNotSuitableForV2Exception, GroupAlreadyExistsException, GroupChangeFailedException
|
||||||
{
|
{
|
||||||
GroupMasterKey groupMasterKey = groupIdV1.deriveV2MigrationMasterKey();
|
GroupMasterKey groupMasterKey = groupIdV1.deriveV2MigrationMasterKey();
|
||||||
GroupSecretParams groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupMasterKey);
|
GroupSecretParams groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupMasterKey);
|
||||||
GroupTable.GroupRecord groupRecord = groupDatabase.requireGroup(groupIdV1);
|
GroupRecord groupRecord = groupDatabase.requireGroup(groupIdV1);
|
||||||
String name = Util.emptyIfNull(groupRecord.getTitle());
|
String name = Util.emptyIfNull(groupRecord.getTitle());
|
||||||
byte[] avatar = groupRecord.hasAvatar() ? AvatarHelper.getAvatarBytes(context, groupRecord.getRecipientId()) : null;
|
byte[] avatar = groupRecord.hasAvatar() ? AvatarHelper.getAvatarBytes(context, groupRecord.getRecipientId()) : null;
|
||||||
int messageTimer = Recipient.resolved(groupRecord.getRecipientId()).getExpiresInSeconds();
|
int messageTimer = Recipient.resolved(groupRecord.getRecipientId()).getExpiresInSeconds();
|
||||||
Set<RecipientId> memberIds = Stream.of(members)
|
Set<RecipientId> memberIds = Stream.of(members)
|
||||||
@@ -327,7 +328,7 @@ final class GroupManagerV2 {
|
|||||||
GroupEditor(@NonNull GroupId.V2 groupId, @NonNull Closeable lock) {
|
GroupEditor(@NonNull GroupId.V2 groupId, @NonNull Closeable lock) {
|
||||||
super(lock);
|
super(lock);
|
||||||
|
|
||||||
GroupTable.GroupRecord groupRecord = groupDatabase.requireGroup(groupId);
|
GroupRecord groupRecord = groupDatabase.requireGroup(groupId);
|
||||||
|
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
this.v2GroupProperties = groupRecord.requireV2GroupProperties();
|
this.v2GroupProperties = groupRecord.requireV2GroupProperties();
|
||||||
@@ -455,8 +456,8 @@ final class GroupManagerV2 {
|
|||||||
void leaveGroup()
|
void leaveGroup()
|
||||||
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
|
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
|
||||||
{
|
{
|
||||||
GroupTable.GroupRecord groupRecord = groupDatabase.requireGroup(groupId);
|
GroupRecord groupRecord = groupDatabase.requireGroup(groupId);
|
||||||
DecryptedGroup decryptedGroup = groupRecord.requireV2GroupProperties().getDecryptedGroup();
|
DecryptedGroup decryptedGroup = groupRecord.requireV2GroupProperties().getDecryptedGroup();
|
||||||
Optional<DecryptedMember> selfMember = DecryptedGroupUtil.findMemberByUuid(decryptedGroup.getMembersList(), selfAci.uuid());
|
Optional<DecryptedMember> selfMember = DecryptedGroupUtil.findMemberByUuid(decryptedGroup.getMembersList(), selfAci.uuid());
|
||||||
Optional<DecryptedPendingMember> aciPendingMember = DecryptedGroupUtil.findPendingByUuid(decryptedGroup.getPendingMembersList(), selfAci.uuid());
|
Optional<DecryptedPendingMember> aciPendingMember = DecryptedGroupUtil.findPendingByUuid(decryptedGroup.getPendingMembersList(), selfAci.uuid());
|
||||||
Optional<DecryptedPendingMember> pniPendingMember = DecryptedGroupUtil.findPendingByUuid(decryptedGroup.getPendingMembersList(), selfPni.uuid());
|
Optional<DecryptedPendingMember> pniPendingMember = DecryptedGroupUtil.findPendingByUuid(decryptedGroup.getPendingMembersList(), selfPni.uuid());
|
||||||
@@ -728,7 +729,7 @@ final class GroupManagerV2 {
|
|||||||
private GroupManager.GroupActionResult commitChange(@NonNull GroupChange.Actions.Builder change, boolean allowWhenBlocked, boolean sendToMembers)
|
private GroupManager.GroupActionResult commitChange(@NonNull GroupChange.Actions.Builder change, boolean allowWhenBlocked, boolean sendToMembers)
|
||||||
throws GroupNotAMemberException, GroupChangeFailedException, IOException, GroupInsufficientRightsException
|
throws GroupNotAMemberException, GroupChangeFailedException, IOException, GroupInsufficientRightsException
|
||||||
{
|
{
|
||||||
final GroupTable.GroupRecord groupRecord = groupDatabase.requireGroup(groupId);
|
final GroupRecord groupRecord = groupDatabase.requireGroup(groupId);
|
||||||
final GroupTable.V2GroupProperties v2GroupProperties = groupRecord.requireV2GroupProperties();
|
final GroupTable.V2GroupProperties v2GroupProperties = groupRecord.requireV2GroupProperties();
|
||||||
final int nextRevision = v2GroupProperties.getGroupRevision() + 1;
|
final int nextRevision = v2GroupProperties.getGroupRevision() + 1;
|
||||||
final GroupChange.Actions changeActions = change.setRevision(nextRevision).build();
|
final GroupChange.Actions changeActions = change.setRevision(nextRevision).build();
|
||||||
@@ -923,7 +924,7 @@ final class GroupManagerV2 {
|
|||||||
alreadyAMember = true;
|
alreadyAMember = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<GroupTable.GroupRecord> unmigratedV1Group = groupDatabase.getGroupV1ByExpectedV2(groupId);
|
Optional<GroupRecord> unmigratedV1Group = groupDatabase.getGroupV1ByExpectedV2(groupId);
|
||||||
|
|
||||||
if (unmigratedV1Group.isPresent()) {
|
if (unmigratedV1Group.isPresent()) {
|
||||||
Log.i(TAG, "Group link was for a migrated V1 group we know about! Migrating it and using that as the base.");
|
Log.i(TAG, "Group link was for a migrated V1 group we know about! Migrating it and using that as the base.");
|
||||||
@@ -932,7 +933,7 @@ final class GroupManagerV2 {
|
|||||||
|
|
||||||
DecryptedGroup decryptedGroup = createPlaceholderGroup(joinInfo, requestToJoin);
|
DecryptedGroup decryptedGroup = createPlaceholderGroup(joinInfo, requestToJoin);
|
||||||
|
|
||||||
Optional<GroupTable.GroupRecord> group = groupDatabase.getGroup(groupId);
|
Optional<GroupRecord> group = groupDatabase.getGroup(groupId);
|
||||||
|
|
||||||
if (group.isPresent()) {
|
if (group.isPresent()) {
|
||||||
Log.i(TAG, "Group already present locally");
|
Log.i(TAG, "Group already present locally");
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember;
|
|||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
import org.thoughtcrime.securesms.database.GroupTable;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.groups.ui.GroupMemberEntry;
|
import org.thoughtcrime.securesms.groups.ui.GroupMemberEntry;
|
||||||
import org.thoughtcrime.securesms.groups.v2.GroupInviteLinkUrl;
|
import org.thoughtcrime.securesms.groups.v2.GroupInviteLinkUrl;
|
||||||
@@ -48,7 +49,7 @@ public final class LiveGroup {
|
|||||||
|
|
||||||
private final GroupTable groupDatabase;
|
private final GroupTable groupDatabase;
|
||||||
private final LiveData<Recipient> recipient;
|
private final LiveData<Recipient> recipient;
|
||||||
private final LiveData<GroupTable.GroupRecord> groupRecord;
|
private final LiveData<GroupRecord> groupRecord;
|
||||||
private final LiveData<List<GroupMemberEntry.FullMember>> fullMembers;
|
private final LiveData<List<GroupMemberEntry.FullMember>> fullMembers;
|
||||||
private final LiveData<List<GroupMemberEntry.RequestingMember>> requestingMembers;
|
private final LiveData<List<GroupMemberEntry.RequestingMember>> requestingMembers;
|
||||||
private final LiveData<GroupLinkUrlAndStatus> groupLink;
|
private final LiveData<GroupLinkUrlAndStatus> groupLink;
|
||||||
@@ -64,7 +65,7 @@ public final class LiveGroup {
|
|||||||
this.requestingMembers = mapToRequestingMembers(this.groupRecord);
|
this.requestingMembers = mapToRequestingMembers(this.groupRecord);
|
||||||
|
|
||||||
if (groupId.isV2()) {
|
if (groupId.isV2()) {
|
||||||
LiveData<GroupTable.V2GroupProperties> v2Properties = Transformations.map(this.groupRecord, GroupTable.GroupRecord::requireV2GroupProperties);
|
LiveData<GroupTable.V2GroupProperties> v2Properties = Transformations.map(this.groupRecord, GroupRecord::requireV2GroupProperties);
|
||||||
this.groupLink = Transformations.map(v2Properties, g -> {
|
this.groupLink = Transformations.map(v2Properties, g -> {
|
||||||
DecryptedGroup group = g.getDecryptedGroup();
|
DecryptedGroup group = g.getDecryptedGroup();
|
||||||
AccessControl.AccessRequired addFromInviteLink = group.getAccessControl().getAddFromInviteLink();
|
AccessControl.AccessRequired addFromInviteLink = group.getAccessControl().getAddFromInviteLink();
|
||||||
@@ -87,7 +88,7 @@ public final class LiveGroup {
|
|||||||
SignalExecutors.BOUNDED.execute(() -> liveRecipient.postValue(Recipient.externalGroupExact(groupId).live()));
|
SignalExecutors.BOUNDED.execute(() -> liveRecipient.postValue(Recipient.externalGroupExact(groupId).live()));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static LiveData<List<GroupMemberEntry.FullMember>> mapToFullMembers(@NonNull LiveData<GroupTable.GroupRecord> groupRecord) {
|
protected static LiveData<List<GroupMemberEntry.FullMember>> mapToFullMembers(@NonNull LiveData<GroupRecord> groupRecord) {
|
||||||
return LiveDataUtil.mapAsync(groupRecord,
|
return LiveDataUtil.mapAsync(groupRecord,
|
||||||
g -> Stream.of(g.getMembers())
|
g -> Stream.of(g.getMembers())
|
||||||
.map(m -> {
|
.map(m -> {
|
||||||
@@ -98,7 +99,7 @@ public final class LiveGroup {
|
|||||||
.toList());
|
.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static LiveData<List<GroupMemberEntry.RequestingMember>> mapToRequestingMembers(@NonNull LiveData<GroupTable.GroupRecord> groupRecord) {
|
protected static LiveData<List<GroupMemberEntry.RequestingMember>> mapToRequestingMembers(@NonNull LiveData<GroupRecord> groupRecord) {
|
||||||
return LiveDataUtil.mapAsync(groupRecord,
|
return LiveDataUtil.mapAsync(groupRecord,
|
||||||
g -> {
|
g -> {
|
||||||
if (!g.isV2Group()) {
|
if (!g.isV2Group()) {
|
||||||
@@ -128,11 +129,11 @@ public final class LiveGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public LiveData<String> getDescription() {
|
public LiveData<String> getDescription() {
|
||||||
return Transformations.map(groupRecord, GroupTable.GroupRecord::getDescription);
|
return Transformations.map(groupRecord, GroupRecord::getDescription);
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveData<Boolean> isAnnouncementGroup() {
|
public LiveData<Boolean> isAnnouncementGroup() {
|
||||||
return Transformations.map(groupRecord, GroupTable.GroupRecord::isAnnouncementGroup);
|
return Transformations.map(groupRecord, GroupRecord::isAnnouncementGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveData<Recipient> getGroupRecipient() {
|
public LiveData<Recipient> getGroupRecipient() {
|
||||||
@@ -148,7 +149,7 @@ public final class LiveGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public LiveData<Boolean> isActive() {
|
public LiveData<Boolean> isActive() {
|
||||||
return Transformations.map(groupRecord, GroupTable.GroupRecord::isActive);
|
return Transformations.map(groupRecord, GroupRecord::isActive);
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveData<Boolean> getRecipientIsAdmin(@NonNull RecipientId recipientId) {
|
public LiveData<Boolean> getRecipientIsAdmin(@NonNull RecipientId recipientId) {
|
||||||
@@ -171,11 +172,11 @@ public final class LiveGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public LiveData<GroupAccessControl> getMembershipAdditionAccessControl() {
|
public LiveData<GroupAccessControl> getMembershipAdditionAccessControl() {
|
||||||
return Transformations.map(groupRecord, GroupTable.GroupRecord::getMembershipAdditionAccessControl);
|
return Transformations.map(groupRecord, GroupRecord::getMembershipAdditionAccessControl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveData<GroupAccessControl> getAttributesAccessControl() {
|
public LiveData<GroupAccessControl> getAttributesAccessControl() {
|
||||||
return Transformations.map(groupRecord, GroupTable.GroupRecord::getAttributesAccessControl);
|
return Transformations.map(groupRecord, GroupRecord::getAttributesAccessControl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveData<List<GroupMemberEntry.FullMember>> getNonAdminFullMembers() {
|
public LiveData<List<GroupMemberEntry.FullMember>> getNonAdminFullMembers() {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import org.signal.core.util.logging.Log;
|
|||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
import org.thoughtcrime.securesms.database.GroupTable;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.groups.GroupChangeException;
|
import org.thoughtcrime.securesms.groups.GroupChangeException;
|
||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.groups.GroupManager;
|
import org.thoughtcrime.securesms.groups.GroupManager;
|
||||||
@@ -56,7 +57,7 @@ public final class LeaveGroupDialog {
|
|||||||
SimpleTask.run(activity.getLifecycle(), () -> {
|
SimpleTask.run(activity.getLifecycle(), () -> {
|
||||||
GroupTable.V2GroupProperties groupProperties = SignalDatabase.groups()
|
GroupTable.V2GroupProperties groupProperties = SignalDatabase.groups()
|
||||||
.getGroup(groupId)
|
.getGroup(groupId)
|
||||||
.map(GroupTable.GroupRecord::requireV2GroupProperties)
|
.map(GroupRecord::requireV2GroupProperties)
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
|
|
||||||
if (groupProperties != null && groupProperties.isAdmin(Recipient.self())) {
|
if (groupProperties != null && groupProperties.isAdmin(Recipient.self())) {
|
||||||
|
|||||||
+1
-1
@@ -20,7 +20,7 @@ import org.signal.storageservice.protos.groups.local.DecryptedMember;
|
|||||||
import org.signal.storageservice.protos.groups.local.DecryptedPendingMember;
|
import org.signal.storageservice.protos.groups.local.DecryptedPendingMember;
|
||||||
import org.signal.storageservice.protos.groups.local.DecryptedPendingMemberRemoval;
|
import org.signal.storageservice.protos.groups.local.DecryptedPendingMemberRemoval;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
import org.thoughtcrime.securesms.database.GroupTable;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable.GroupRecord;
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.database.MessageTable;
|
import org.thoughtcrime.securesms.database.MessageTable;
|
||||||
import org.thoughtcrime.securesms.database.RecipientTable;
|
import org.thoughtcrime.securesms.database.RecipientTable;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ import androidx.annotation.VisibleForTesting;
|
|||||||
|
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
import org.thoughtcrime.securesms.database.GroupTable;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable.GroupRecord;
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import androidx.annotation.NonNull;
|
|||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.signal.libsignal.protocol.InvalidMessageException;
|
import org.signal.libsignal.protocol.InvalidMessageException;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
import org.thoughtcrime.securesms.database.GroupTable;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable.GroupRecord;
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import org.signal.core.util.logging.Log;
|
|||||||
import org.signal.libsignal.zkgroup.groups.GroupMasterKey;
|
import org.signal.libsignal.zkgroup.groups.GroupMasterKey;
|
||||||
import org.signal.libsignal.zkgroup.groups.GroupSecretParams;
|
import org.signal.libsignal.zkgroup.groups.GroupSecretParams;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
import org.thoughtcrime.securesms.database.GroupTable;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable.GroupRecord;
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package org.thoughtcrime.securesms.jobs;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.signal.core.util.concurrent.SignalExecutors;
|
import org.signal.core.util.concurrent.SignalExecutors;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
@@ -28,7 +28,7 @@ public final class ForceUpdateGroupV2Job extends BaseJob {
|
|||||||
|
|
||||||
public static void enqueueIfNecessary(@NonNull GroupId.V2 groupId) {
|
public static void enqueueIfNecessary(@NonNull GroupId.V2 groupId) {
|
||||||
SignalExecutors.BOUNDED.execute(() -> {
|
SignalExecutors.BOUNDED.execute(() -> {
|
||||||
Optional<GroupTable.GroupRecord> group = SignalDatabase.groups().getGroup(groupId);
|
Optional<GroupRecord> group = SignalDatabase.groups().getGroup(groupId);
|
||||||
if (group.isPresent() &&
|
if (group.isPresent() &&
|
||||||
group.get().isV2Group() &&
|
group.get().isV2Group() &&
|
||||||
group.get().getLastForceUpdateTimestamp() + FORCE_UPDATE_INTERVAL < System.currentTimeMillis()
|
group.get().getLastForceUpdateTimestamp() + FORCE_UPDATE_INTERVAL < System.currentTimeMillis()
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package org.thoughtcrime.securesms.jobs;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
|
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
|
||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.groups.GroupManager;
|
import org.thoughtcrime.securesms.groups.GroupManager;
|
||||||
@@ -61,7 +61,7 @@ final class ForceUpdateGroupV2WorkerJob extends BaseJob {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRun() throws IOException, GroupNotAMemberException, GroupChangeBusyException {
|
public void onRun() throws IOException, GroupNotAMemberException, GroupChangeBusyException {
|
||||||
Optional<GroupTable.GroupRecord> group = SignalDatabase.groups().getGroup(groupId);
|
Optional<GroupRecord> group = SignalDatabase.groups().getGroup(groupId);
|
||||||
|
|
||||||
if (!group.isPresent()) {
|
if (!group.isPresent()) {
|
||||||
Log.w(TAG, "Group not found");
|
Log.w(TAG, "Group not found");
|
||||||
|
|||||||
+2
-2
@@ -8,8 +8,8 @@ import com.google.protobuf.ByteString;
|
|||||||
import org.signal.core.util.concurrent.SignalExecutors;
|
import org.signal.core.util.concurrent.SignalExecutors;
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.signal.storageservice.protos.groups.local.DecryptedMember;
|
import org.signal.storageservice.protos.groups.local.DecryptedMember;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
|
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
|
||||||
import org.thoughtcrime.securesms.groups.GroupChangeFailedException;
|
import org.thoughtcrime.securesms.groups.GroupChangeFailedException;
|
||||||
@@ -112,7 +112,7 @@ public final class GroupV2UpdateSelfProfileKeyJob extends BaseJob {
|
|||||||
boolean foundMismatch = false;
|
boolean foundMismatch = false;
|
||||||
|
|
||||||
for (GroupId.V2 id : SignalDatabase.groups().getAllGroupV2Ids()) {
|
for (GroupId.V2 id : SignalDatabase.groups().getAllGroupV2Ids()) {
|
||||||
Optional<GroupTable.GroupRecord> group = SignalDatabase.groups().getGroup(id);
|
Optional<GroupRecord> group = SignalDatabase.groups().getGroup(id);
|
||||||
if (!group.isPresent()) {
|
if (!group.isPresent()) {
|
||||||
Log.w(TAG, "Group " + group + " no longer exists?");
|
Log.w(TAG, "Group " + group + " no longer exists?");
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import org.thoughtcrime.securesms.conversation.colors.ChatColorsMapper;
|
|||||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
import org.thoughtcrime.securesms.database.GroupTable;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
@@ -101,7 +102,7 @@ public class MultiDeviceGroupUpdateJob extends BaseJob {
|
|||||||
DeviceGroupsOutputStream out = new DeviceGroupsOutputStream(new ParcelFileDescriptor.AutoCloseOutputStream(pipe[1]));
|
DeviceGroupsOutputStream out = new DeviceGroupsOutputStream(new ParcelFileDescriptor.AutoCloseOutputStream(pipe[1]));
|
||||||
boolean hasData = false;
|
boolean hasData = false;
|
||||||
|
|
||||||
GroupTable.GroupRecord record;
|
GroupRecord record;
|
||||||
|
|
||||||
while ((record = reader.getNext()) != null) {
|
while ((record = reader.getNext()) != null) {
|
||||||
if (record.isV1Group()) {
|
if (record.isV1Group()) {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import org.thoughtcrime.securesms.database.RecipientTable;
|
|||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
||||||
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageId;
|
import org.thoughtcrime.securesms.database.model.MessageId;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
@@ -252,7 +253,7 @@ public final class PushGroupSendJob extends PushSendJob {
|
|||||||
.anyMatch(info -> info.getStatus() > GroupReceiptTable.STATUS_UNDELIVERED);
|
.anyMatch(info -> info.getStatus() > GroupReceiptTable.STATUS_UNDELIVERED);
|
||||||
|
|
||||||
if (message.getStoryType().isStory()) {
|
if (message.getStoryType().isStory()) {
|
||||||
Optional<GroupTable.GroupRecord> groupRecord = SignalDatabase.groups().getGroup(groupId);
|
Optional<GroupRecord> groupRecord = SignalDatabase.groups().getGroup(groupId);
|
||||||
|
|
||||||
if (groupRecord.isPresent() && groupRecord.get().isAnnouncementGroup() && !groupRecord.get().isAdmin(Recipient.self())) {
|
if (groupRecord.isPresent() && groupRecord.get().isAnnouncementGroup() && !groupRecord.get().isAdmin(Recipient.self())) {
|
||||||
throw new UndeliverableMessageException("Non-admins cannot send stories in announcement groups!");
|
throw new UndeliverableMessageException("Non-admins cannot send stories in announcement groups!");
|
||||||
@@ -301,7 +302,7 @@ public final class PushGroupSendJob extends PushSendJob {
|
|||||||
throw new UndeliverableMessageException("Messages can no longer be sent to V1 groups!");
|
throw new UndeliverableMessageException("Messages can no longer be sent to V1 groups!");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Optional<GroupTable.GroupRecord> groupRecord = SignalDatabase.groups().getGroup(groupRecipient.requireGroupId());
|
Optional<GroupRecord> groupRecord = SignalDatabase.groups().getGroup(groupRecipient.requireGroupId());
|
||||||
|
|
||||||
if (groupRecord.isPresent() && groupRecord.get().isAnnouncementGroup() && !groupRecord.get().isAdmin(Recipient.self())) {
|
if (groupRecord.isPresent() && groupRecord.get().isAnnouncementGroup() && !groupRecord.get().isAdmin(Recipient.self())) {
|
||||||
throw new UndeliverableMessageException("Non-admins cannot send messages in announcement groups!");
|
throw new UndeliverableMessageException("Non-admins cannot send messages in announcement groups!");
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.WorkerThread;
|
import androidx.annotation.WorkerThread;
|
||||||
|
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
|
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
|
||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.groups.GroupManager;
|
import org.thoughtcrime.securesms.groups.GroupManager;
|
||||||
@@ -76,7 +76,7 @@ final class RequestGroupV2InfoWorkerJob extends BaseJob {
|
|||||||
Log.i(TAG, "Updating group to revision " + toRevision);
|
Log.i(TAG, "Updating group to revision " + toRevision);
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<GroupTable.GroupRecord> group = SignalDatabase.groups().getGroup(groupId);
|
Optional<GroupRecord> group = SignalDatabase.groups().getGroup(groupId);
|
||||||
|
|
||||||
if (!group.isPresent()) {
|
if (!group.isPresent()) {
|
||||||
Log.w(TAG, "Group not found");
|
Log.w(TAG, "Group not found");
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import org.signal.core.util.logging.Log;
|
|||||||
import org.signal.libsignal.protocol.SignalProtocolAddress;
|
import org.signal.libsignal.protocol.SignalProtocolAddress;
|
||||||
import org.signal.libsignal.protocol.message.SenderKeyDistributionMessage;
|
import org.signal.libsignal.protocol.message.SenderKeyDistributionMessage;
|
||||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable.GroupRecord;
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
import org.thoughtcrime.securesms.database.model.DistributionListRecord;
|
import org.thoughtcrime.securesms.database.model.DistributionListRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ import org.thoughtcrime.securesms.R;
|
|||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||||
import org.thoughtcrime.securesms.attachments.UriAttachment;
|
import org.thoughtcrime.securesms.attachments.UriAttachment;
|
||||||
import org.thoughtcrime.securesms.database.AttachmentTable;
|
import org.thoughtcrime.securesms.database.AttachmentTable;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.groups.GroupManager;
|
import org.thoughtcrime.securesms.groups.GroupManager;
|
||||||
@@ -282,14 +282,14 @@ public class LinkPreviewRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GroupMasterKey groupMasterKey = groupInviteLinkUrl.getGroupMasterKey();
|
GroupMasterKey groupMasterKey = groupInviteLinkUrl.getGroupMasterKey();
|
||||||
GroupId.V2 groupId = GroupId.v2(groupMasterKey);
|
GroupId.V2 groupId = GroupId.v2(groupMasterKey);
|
||||||
Optional<GroupTable.GroupRecord> group = SignalDatabase.groups().getGroup(groupId);
|
Optional<GroupRecord> group = SignalDatabase.groups().getGroup(groupId);
|
||||||
|
|
||||||
if (group.isPresent()) {
|
if (group.isPresent()) {
|
||||||
Log.i(TAG, "Creating preview for locally available group");
|
Log.i(TAG, "Creating preview for locally available group");
|
||||||
|
|
||||||
GroupTable.GroupRecord groupRecord = group.get();
|
GroupRecord groupRecord = group.get();
|
||||||
String title = groupRecord.getTitle();
|
String title = groupRecord.getTitle();
|
||||||
int memberCount = groupRecord.getMembers().size();
|
int memberCount = groupRecord.getMembers().size();
|
||||||
String description = getMemberCountDescription(context, memberCount);
|
String description = getMemberCountDescription(context, memberCount);
|
||||||
Optional<Attachment> thumbnail = Optional.empty();
|
Optional<Attachment> thumbnail = Optional.empty();
|
||||||
|
|||||||
+2
-1
@@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.database.GroupTable;
|
|||||||
import org.thoughtcrime.securesms.database.RecipientTable;
|
import org.thoughtcrime.securesms.database.RecipientTable;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
import org.thoughtcrime.securesms.database.ThreadTable;
|
import org.thoughtcrime.securesms.database.ThreadTable;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
@@ -121,7 +122,7 @@ class CameraContactsRepository {
|
|||||||
List<Recipient> recipients = new ArrayList<>();
|
List<Recipient> recipients = new ArrayList<>();
|
||||||
|
|
||||||
try (GroupTable.Reader reader = groupDatabase.queryGroupsByTitle(query, false, true, true)) {
|
try (GroupTable.Reader reader = groupDatabase.queryGroupsByTitle(query, false, true, true)) {
|
||||||
GroupTable.GroupRecord groupRecord;
|
GroupRecord groupRecord;
|
||||||
while ((groupRecord = reader.getNext()) != null) {
|
while ((groupRecord = reader.getNext()) != null) {
|
||||||
RecipientId recipientId = recipientTable.getOrInsertFromGroupId(groupRecord.getId());
|
RecipientId recipientId = recipientTable.getOrInsertFromGroupId(groupRecord.getId());
|
||||||
recipients.add(Recipient.resolved(recipientId));
|
recipients.add(Recipient.resolved(recipientId));
|
||||||
|
|||||||
+3
-2
@@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.database.MessageTable;
|
|||||||
import org.thoughtcrime.securesms.database.RecipientTable;
|
import org.thoughtcrime.securesms.database.RecipientTable;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
import org.thoughtcrime.securesms.database.ThreadTable;
|
import org.thoughtcrime.securesms.database.ThreadTable;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.groups.GroupChangeException;
|
import org.thoughtcrime.securesms.groups.GroupChangeException;
|
||||||
import org.thoughtcrime.securesms.groups.GroupManager;
|
import org.thoughtcrime.securesms.groups.GroupManager;
|
||||||
@@ -58,8 +59,8 @@ final class MessageRequestRepository {
|
|||||||
|
|
||||||
void getGroupInfo(@NonNull RecipientId recipientId, @NonNull Consumer<GroupInfo> onGroupInfoLoaded) {
|
void getGroupInfo(@NonNull RecipientId recipientId, @NonNull Consumer<GroupInfo> onGroupInfoLoaded) {
|
||||||
executor.execute(() -> {
|
executor.execute(() -> {
|
||||||
GroupTable groupDatabase = SignalDatabase.groups();
|
GroupTable groupDatabase = SignalDatabase.groups();
|
||||||
Optional<GroupTable.GroupRecord> groupRecord = groupDatabase.getGroup(recipientId);
|
Optional<GroupRecord> groupRecord = groupDatabase.getGroup(recipientId);
|
||||||
onGroupInfoLoaded.accept(groupRecord.map(record -> {
|
onGroupInfoLoaded.accept(groupRecord.map(record -> {
|
||||||
if (record.isV2Group()) {
|
if (record.isV2Group()) {
|
||||||
DecryptedGroup decryptedGroup = record.requireV2GroupProperties().getDecryptedGroup();
|
DecryptedGroup decryptedGroup = record.requireV2GroupProperties().getDecryptedGroup();
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import org.signal.libsignal.protocol.InvalidRegistrationIdException;
|
|||||||
import org.signal.libsignal.protocol.NoSessionException;
|
import org.signal.libsignal.protocol.NoSessionException;
|
||||||
import org.thoughtcrime.securesms.crypto.SenderKeyUtil;
|
import org.thoughtcrime.securesms.crypto.SenderKeyUtil;
|
||||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable.GroupRecord;
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.database.MessageSendLogTables;
|
import org.thoughtcrime.securesms.database.MessageSendLogTables;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
import org.thoughtcrime.securesms.database.model.DistributionListId;
|
import org.thoughtcrime.securesms.database.model.DistributionListId;
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ import org.thoughtcrime.securesms.crypto.SecurityEvent;
|
|||||||
import org.thoughtcrime.securesms.database.AttachmentTable;
|
import org.thoughtcrime.securesms.database.AttachmentTable;
|
||||||
import org.thoughtcrime.securesms.database.CallTable;
|
import org.thoughtcrime.securesms.database.CallTable;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
import org.thoughtcrime.securesms.database.GroupTable;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable.GroupRecord;
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.database.GroupReceiptTable;
|
import org.thoughtcrime.securesms.database.GroupReceiptTable;
|
||||||
import org.thoughtcrime.securesms.database.GroupReceiptTable.GroupReceiptInfo;
|
import org.thoughtcrime.securesms.database.GroupReceiptTable.GroupReceiptInfo;
|
||||||
import org.thoughtcrime.securesms.database.MessageTable;
|
import org.thoughtcrime.securesms.database.MessageTable;
|
||||||
|
|||||||
+2
-2
@@ -18,9 +18,9 @@ import androidx.core.graphics.drawable.IconCompat
|
|||||||
import org.signal.core.util.PendingIntentFlags.mutable
|
import org.signal.core.util.PendingIntentFlags.mutable
|
||||||
import org.thoughtcrime.securesms.R
|
import org.thoughtcrime.securesms.R
|
||||||
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
||||||
import org.thoughtcrime.securesms.database.GroupTable
|
|
||||||
import org.thoughtcrime.securesms.database.RecipientTable
|
import org.thoughtcrime.securesms.database.RecipientTable
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
import org.thoughtcrime.securesms.notifications.NotificationChannels
|
import org.thoughtcrime.securesms.notifications.NotificationChannels
|
||||||
import org.thoughtcrime.securesms.notifications.ReplyMethod
|
import org.thoughtcrime.securesms.notifications.ReplyMethod
|
||||||
@@ -117,7 +117,7 @@ sealed class NotificationBuilder(protected val context: Context) {
|
|||||||
fun addReplyActions(conversation: NotificationConversation) {
|
fun addReplyActions(conversation: NotificationConversation) {
|
||||||
if (privacy.isDisplayMessage && isNotLocked && !conversation.recipient.isPushV1Group && RecipientUtil.isMessageRequestAccepted(context, conversation.recipient)) {
|
if (privacy.isDisplayMessage && isNotLocked && !conversation.recipient.isPushV1Group && RecipientUtil.isMessageRequestAccepted(context, conversation.recipient)) {
|
||||||
if (conversation.recipient.isPushV2Group) {
|
if (conversation.recipient.isPushV2Group) {
|
||||||
val group: Optional<GroupTable.GroupRecord> = SignalDatabase.groups.getGroup(conversation.recipient.requireGroupId())
|
val group: Optional<GroupRecord> = SignalDatabase.groups.getGroup(conversation.recipient.requireGroupId())
|
||||||
if (group.isPresent && group.get().isAnnouncementGroup && !group.get().isAdmin(Recipient.self())) {
|
if (group.isPresent && group.get().isAnnouncementGroup && !group.get().isAdmin(Recipient.self())) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -10,8 +10,8 @@ import androidx.core.util.Consumer;
|
|||||||
import org.signal.core.util.StreamUtil;
|
import org.signal.core.util.StreamUtil;
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.conversation.colors.AvatarColor;
|
import org.thoughtcrime.securesms.conversation.colors.AvatarColor;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.groups.GroupChangeException;
|
import org.thoughtcrime.securesms.groups.GroupChangeException;
|
||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.groups.GroupManager;
|
import org.thoughtcrime.securesms.groups.GroupManager;
|
||||||
@@ -92,7 +92,7 @@ class EditGroupProfileRepository implements EditProfileRepository {
|
|||||||
|
|
||||||
return SignalDatabase.groups()
|
return SignalDatabase.groups()
|
||||||
.getGroup(recipientId)
|
.getGroup(recipientId)
|
||||||
.map(GroupTable.GroupRecord::getDescription)
|
.map(GroupRecord::getDescription)
|
||||||
.orElse("");
|
.orElse("");
|
||||||
}, descriptionConsumer::accept);
|
}, descriptionConsumer::accept);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import com.annimon.stream.Stream;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
import org.thoughtcrime.securesms.database.GroupTable;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.ProfileChangeDetails;
|
import org.thoughtcrime.securesms.database.model.databaseprotos.ProfileChangeDetails;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
@@ -105,7 +106,7 @@ public final class ReviewUtil {
|
|||||||
return Stream.of(SignalDatabase.groups()
|
return Stream.of(SignalDatabase.groups()
|
||||||
.getPushGroupsContainingMember(recipientId))
|
.getPushGroupsContainingMember(recipientId))
|
||||||
.filter(g -> g.getMembers().contains(Recipient.self().getId()))
|
.filter(g -> g.getMembers().contains(Recipient.self().getId()))
|
||||||
.map(GroupTable.GroupRecord::getRecipientId)
|
.map(GroupRecord::getRecipientId)
|
||||||
.toList()
|
.toList()
|
||||||
.size();
|
.size();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import org.signal.core.util.ThreadUtil;
|
|||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.database.DistributionListTables;
|
import org.thoughtcrime.securesms.database.DistributionListTables;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
import org.thoughtcrime.securesms.database.GroupTable;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable.GroupRecord;
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.database.RecipientTable;
|
import org.thoughtcrime.securesms.database.RecipientTable;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
import org.thoughtcrime.securesms.database.model.DistributionListRecord;
|
import org.thoughtcrime.securesms.database.model.DistributionListRecord;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import org.whispersystems.signalservice.api.util.UuidUtil;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.database.GroupTable;
|
|||||||
import org.thoughtcrime.securesms.database.RecipientTable.RegisteredState;
|
import org.thoughtcrime.securesms.database.RecipientTable.RegisteredState;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
import org.thoughtcrime.securesms.database.ThreadTable;
|
import org.thoughtcrime.securesms.database.ThreadTable;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
|
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
|
||||||
import org.thoughtcrime.securesms.groups.GroupChangeException;
|
import org.thoughtcrime.securesms.groups.GroupChangeException;
|
||||||
@@ -301,7 +302,7 @@ public class RecipientUtil {
|
|||||||
GroupTable groupDatabase = SignalDatabase.groups();
|
GroupTable groupDatabase = SignalDatabase.groups();
|
||||||
return groupDatabase.getPushGroupsContainingMember(recipient.getId())
|
return groupDatabase.getPushGroupsContainingMember(recipient.getId())
|
||||||
.stream()
|
.stream()
|
||||||
.anyMatch(GroupTable.GroupRecord::isV2Group);
|
.anyMatch(GroupRecord::isV2Group);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-4
@@ -11,6 +11,7 @@ import org.signal.core.util.logging.Log;
|
|||||||
import org.thoughtcrime.securesms.contacts.sync.ContactDiscovery;
|
import org.thoughtcrime.securesms.contacts.sync.ContactDiscovery;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
import org.thoughtcrime.securesms.database.GroupTable;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.IdentityRecord;
|
import org.thoughtcrime.securesms.database.model.IdentityRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.groups.GroupChangeException;
|
import org.thoughtcrime.securesms.groups.GroupChangeException;
|
||||||
@@ -106,11 +107,11 @@ final class RecipientDialogRepository {
|
|||||||
void getGroupMembership(@NonNull Consumer<List<RecipientId>> onComplete) {
|
void getGroupMembership(@NonNull Consumer<List<RecipientId>> onComplete) {
|
||||||
SimpleTask.run(SignalExecutors.UNBOUNDED,
|
SimpleTask.run(SignalExecutors.UNBOUNDED,
|
||||||
() -> {
|
() -> {
|
||||||
GroupTable groupDatabase = SignalDatabase.groups();
|
GroupTable groupDatabase = SignalDatabase.groups();
|
||||||
List<GroupTable.GroupRecord> groupRecords = groupDatabase.getPushGroupsContainingMember(recipientId);
|
List<GroupRecord> groupRecords = groupDatabase.getPushGroupsContainingMember(recipientId);
|
||||||
ArrayList<RecipientId> groupRecipients = new ArrayList<>(groupRecords.size());
|
ArrayList<RecipientId> groupRecipients = new ArrayList<>(groupRecords.size());
|
||||||
|
|
||||||
for (GroupTable.GroupRecord groupRecord : groupRecords) {
|
for (GroupRecord groupRecord : groupRecords) {
|
||||||
groupRecipients.add(groupRecord.getRecipientId());
|
groupRecipients.add(groupRecord.getRecipientId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import org.thoughtcrime.securesms.database.RecipientTable;
|
|||||||
import org.thoughtcrime.securesms.database.SearchTable;
|
import org.thoughtcrime.securesms.database.SearchTable;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
import org.thoughtcrime.securesms.database.ThreadTable;
|
import org.thoughtcrime.securesms.database.ThreadTable;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.Mention;
|
import org.thoughtcrime.securesms.database.model.Mention;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||||
@@ -174,7 +175,7 @@ public class SearchRepository {
|
|||||||
|
|
||||||
Set<RecipientId> groupsByTitleIds = new LinkedHashSet<>();
|
Set<RecipientId> groupsByTitleIds = new LinkedHashSet<>();
|
||||||
|
|
||||||
GroupTable.GroupRecord record;
|
GroupRecord record;
|
||||||
try (GroupTable.Reader reader = SignalDatabase.groups().queryGroupsByTitle(query, true, false, false)) {
|
try (GroupTable.Reader reader = SignalDatabase.groups().queryGroupsByTitle(query, true, false, false)) {
|
||||||
while ((record = reader.getNext()) != null) {
|
while ((record = reader.getNext()) != null) {
|
||||||
groupsByTitleIds.add(record.getRecipientId());
|
groupsByTitleIds.add(record.getRecipientId());
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
|||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
import org.thoughtcrime.securesms.database.GroupTable;
|
||||||
import org.thoughtcrime.securesms.database.CallTable;
|
import org.thoughtcrime.securesms.database.CallTable;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.events.GroupCallPeekEvent;
|
import org.thoughtcrime.securesms.events.GroupCallPeekEvent;
|
||||||
import org.thoughtcrime.securesms.events.WebRtcViewModel;
|
import org.thoughtcrime.securesms.events.WebRtcViewModel;
|
||||||
@@ -748,9 +749,9 @@ private void processStateless(@NonNull Function1<WebRtcEphemeralState, WebRtcEph
|
|||||||
@Override
|
@Override
|
||||||
public void onGroupCallRingUpdate(@NonNull byte[] groupIdBytes, long ringId, @NonNull UUID sender, @NonNull CallManager.RingUpdate ringUpdate) {
|
public void onGroupCallRingUpdate(@NonNull byte[] groupIdBytes, long ringId, @NonNull UUID sender, @NonNull CallManager.RingUpdate ringUpdate) {
|
||||||
try {
|
try {
|
||||||
GroupId.V2 groupId = GroupId.v2(new GroupIdentifier(groupIdBytes));
|
GroupId.V2 groupId = GroupId.v2(new GroupIdentifier(groupIdBytes));
|
||||||
GroupTable.GroupRecord group = SignalDatabase.groups().getGroup(groupId).orElse(null);
|
GroupRecord group = SignalDatabase.groups().getGroup(groupId).orElse(null);
|
||||||
Recipient senderRecipient = Recipient.externalPush(ServiceId.from(sender));
|
Recipient senderRecipient = Recipient.externalPush(ServiceId.from(sender));
|
||||||
|
|
||||||
if (group != null &&
|
if (group != null &&
|
||||||
group.isActive() &&
|
group.isActive() &&
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import org.signal.core.util.logging.Log;
|
|||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
import org.thoughtcrime.securesms.database.GroupTable;
|
||||||
import org.thoughtcrime.securesms.database.RecipientTable;
|
import org.thoughtcrime.securesms.database.RecipientTable;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.groups.BadGroupIdException;
|
import org.thoughtcrime.securesms.groups.BadGroupIdException;
|
||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
@@ -46,8 +47,8 @@ public final class GroupV1RecordProcessor extends DefaultStorageRecordProcessor<
|
|||||||
@Override
|
@Override
|
||||||
boolean isInvalid(@NonNull SignalGroupV1Record remote) {
|
boolean isInvalid(@NonNull SignalGroupV1Record remote) {
|
||||||
try {
|
try {
|
||||||
GroupId.V1 id = GroupId.v1(remote.getGroupId());
|
GroupId.V1 id = GroupId.v1(remote.getGroupId());
|
||||||
Optional<GroupTable.GroupRecord> v2Record = groupDatabase.getGroup(id.deriveV2MigrationGroupId());
|
Optional<GroupRecord> v2Record = groupDatabase.getGroup(id.deriveV2MigrationGroupId());
|
||||||
|
|
||||||
if (v2Record.isPresent()) {
|
if (v2Record.isPresent()) {
|
||||||
Log.w(TAG, "We already have an upgraded V2 group for this V1 group -- marking as invalid.");
|
Log.w(TAG, "We already have an upgraded V2 group for this V1 group -- marking as invalid.");
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ import org.thoughtcrime.securesms.R;
|
|||||||
import org.thoughtcrime.securesms.WebRtcCallActivity;
|
import org.thoughtcrime.securesms.WebRtcCallActivity;
|
||||||
import org.thoughtcrime.securesms.contacts.sync.ContactDiscovery;
|
import org.thoughtcrime.securesms.contacts.sync.ContactDiscovery;
|
||||||
import org.thoughtcrime.securesms.conversation.ConversationIntents;
|
import org.thoughtcrime.securesms.conversation.ConversationIntents;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.groups.ui.invitesandrequests.joining.GroupJoinBottomSheetDialogFragment;
|
import org.thoughtcrime.securesms.groups.ui.invitesandrequests.joining.GroupJoinBottomSheetDialogFragment;
|
||||||
@@ -237,7 +237,7 @@ public class CommunicationActions {
|
|||||||
GroupId.V2 groupId = GroupId.v2(groupInviteLinkUrl.getGroupMasterKey());
|
GroupId.V2 groupId = GroupId.v2(groupInviteLinkUrl.getGroupMasterKey());
|
||||||
|
|
||||||
SimpleTask.run(SignalExecutors.BOUNDED, () -> {
|
SimpleTask.run(SignalExecutors.BOUNDED, () -> {
|
||||||
GroupTable.GroupRecord group = SignalDatabase.groups().getGroup(groupId).orElse(null);
|
GroupRecord group = SignalDatabase.groups().getGroup(groupId).orElse(null);
|
||||||
|
|
||||||
return group != null && group.isActive() ? Recipient.resolved(group.getRecipientId())
|
return group != null && group.isActive() ? Recipient.resolved(group.getRecipientId())
|
||||||
: null;
|
: null;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import org.signal.libsignal.zkgroup.groups.GroupMasterKey;
|
|||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
import org.thoughtcrime.securesms.database.GroupTable;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.mms.MessageGroupContext;
|
import org.thoughtcrime.securesms.mms.MessageGroupContext;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
@@ -94,7 +95,7 @@ public final class GroupUtil {
|
|||||||
{
|
{
|
||||||
if (groupId.isV2()) {
|
if (groupId.isV2()) {
|
||||||
GroupTable groupDatabase = SignalDatabase.groups();
|
GroupTable groupDatabase = SignalDatabase.groups();
|
||||||
GroupTable.GroupRecord groupRecord = groupDatabase.requireGroup(groupId);
|
GroupRecord groupRecord = groupDatabase.requireGroup(groupId);
|
||||||
GroupTable.V2GroupProperties v2GroupProperties = groupRecord.requireV2GroupProperties();
|
GroupTable.V2GroupProperties v2GroupProperties = groupRecord.requireV2GroupProperties();
|
||||||
SignalServiceGroupV2 group = SignalServiceGroupV2.newBuilder(v2GroupProperties.getGroupMasterKey())
|
SignalServiceGroupV2 group = SignalServiceGroupV2.newBuilder(v2GroupProperties.getGroupMasterKey())
|
||||||
.withRevision(v2GroupProperties.getGroupRevision())
|
.withRevision(v2GroupProperties.getGroupRevision())
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import org.thoughtcrime.securesms.database.IdentityTable;
|
|||||||
import org.thoughtcrime.securesms.database.MessageTable;
|
import org.thoughtcrime.securesms.database.MessageTable;
|
||||||
import org.thoughtcrime.securesms.database.MessageTable.InsertResult;
|
import org.thoughtcrime.securesms.database.MessageTable.InsertResult;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.IdentityRecord;
|
import org.thoughtcrime.securesms.database.model.IdentityRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
@@ -67,7 +68,7 @@ public final class IdentityUtil {
|
|||||||
|
|
||||||
try (GroupTable.Reader reader = groupDatabase.getGroups()) {
|
try (GroupTable.Reader reader = groupDatabase.getGroups()) {
|
||||||
|
|
||||||
GroupTable.GroupRecord groupRecord;
|
GroupRecord groupRecord;
|
||||||
|
|
||||||
while ((groupRecord = reader.getNext()) != null) {
|
while ((groupRecord = reader.getNext()) != null) {
|
||||||
if (groupRecord.getMembers().contains(recipient.getId()) && groupRecord.isActive() && !groupRecord.isMms()) {
|
if (groupRecord.getMembers().contains(recipient.getId()) && groupRecord.isActive() && !groupRecord.isMms()) {
|
||||||
@@ -138,7 +139,7 @@ public final class IdentityUtil {
|
|||||||
GroupTable groupDatabase = SignalDatabase.groups();
|
GroupTable groupDatabase = SignalDatabase.groups();
|
||||||
|
|
||||||
try (GroupTable.Reader reader = groupDatabase.getGroups()) {
|
try (GroupTable.Reader reader = groupDatabase.getGroups()) {
|
||||||
GroupTable.GroupRecord groupRecord;
|
GroupRecord groupRecord;
|
||||||
|
|
||||||
while ((groupRecord = reader.getNext()) != null) {
|
while ((groupRecord = reader.getNext()) != null) {
|
||||||
if (groupRecord.getMembers().contains(recipientId) && groupRecord.isActive()) {
|
if (groupRecord.getMembers().contains(recipientId) && groupRecord.isActive()) {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember
|
|||||||
import org.signal.storageservice.protos.groups.local.DecryptedString
|
import org.signal.storageservice.protos.groups.local.DecryptedString
|
||||||
import org.signal.storageservice.protos.groups.local.DecryptedTimer
|
import org.signal.storageservice.protos.groups.local.DecryptedTimer
|
||||||
import org.signal.storageservice.protos.groups.local.EnabledState
|
import org.signal.storageservice.protos.groups.local.EnabledState
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord
|
||||||
import org.thoughtcrime.securesms.groups.GroupId
|
import org.thoughtcrime.securesms.groups.GroupId
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||||
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupHistoryEntry
|
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupHistoryEntry
|
||||||
@@ -99,7 +100,7 @@ class GroupChangeData(private val revision: Int, private val groupOperations: Gr
|
|||||||
class GroupStateTestData(private val masterKey: GroupMasterKey, private val groupOperations: GroupsV2Operations.GroupOperations? = null) {
|
class GroupStateTestData(private val masterKey: GroupMasterKey, private val groupOperations: GroupsV2Operations.GroupOperations? = null) {
|
||||||
|
|
||||||
var localState: DecryptedGroup? = null
|
var localState: DecryptedGroup? = null
|
||||||
var groupRecord: Optional<GroupTable.GroupRecord> = Optional.empty()
|
var groupRecord: Optional<GroupRecord> = Optional.empty()
|
||||||
var serverState: DecryptedGroup? = null
|
var serverState: DecryptedGroup? = null
|
||||||
var changeSet: ChangeSet? = null
|
var changeSet: ChangeSet? = null
|
||||||
var groupChange: GroupChange? = null
|
var groupChange: GroupChange? = null
|
||||||
@@ -172,9 +173,9 @@ fun groupRecord(
|
|||||||
avatarDigest: ByteArray = ByteArray(0),
|
avatarDigest: ByteArray = ByteArray(0),
|
||||||
mms: Boolean = false,
|
mms: Boolean = false,
|
||||||
distributionId: DistributionId? = null
|
distributionId: DistributionId? = null
|
||||||
): Optional<GroupTable.GroupRecord> {
|
): Optional<GroupRecord> {
|
||||||
return Optional.of(
|
return Optional.of(
|
||||||
GroupTable.GroupRecord(
|
GroupRecord(
|
||||||
id,
|
id,
|
||||||
recipientId,
|
recipientId,
|
||||||
decryptedGroup.title,
|
decryptedGroup.title,
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ package org.thoughtcrime.securesms.groups
|
|||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.slot
|
||||||
|
import io.mockk.verify
|
||||||
import org.hamcrest.MatcherAssert.assertThat
|
import org.hamcrest.MatcherAssert.assertThat
|
||||||
import org.hamcrest.Matchers
|
import org.hamcrest.Matchers
|
||||||
import org.hamcrest.Matchers.`is`
|
import org.hamcrest.Matchers.`is`
|
||||||
@@ -11,9 +15,6 @@ import org.junit.Before
|
|||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mockito.ArgumentCaptor
|
|
||||||
import org.mockito.Mockito
|
|
||||||
import org.mockito.Mockito.mock
|
|
||||||
import org.robolectric.RobolectricTestRunner
|
import org.robolectric.RobolectricTestRunner
|
||||||
import org.robolectric.annotation.Config
|
import org.robolectric.annotation.Config
|
||||||
import org.signal.core.util.Hex
|
import org.signal.core.util.Hex
|
||||||
@@ -71,8 +72,6 @@ class GroupManagerV2Test_edit {
|
|||||||
private lateinit var sendGroupUpdateHelper: GroupManagerV2.SendGroupUpdateHelper
|
private lateinit var sendGroupUpdateHelper: GroupManagerV2.SendGroupUpdateHelper
|
||||||
private lateinit var groupOperations: GroupsV2Operations.GroupOperations
|
private lateinit var groupOperations: GroupsV2Operations.GroupOperations
|
||||||
|
|
||||||
private lateinit var patchedDecryptedGroup: ArgumentCaptor<DecryptedGroup>
|
|
||||||
|
|
||||||
private lateinit var manager: GroupManagerV2
|
private lateinit var manager: GroupManagerV2
|
||||||
|
|
||||||
@get:Rule
|
@get:Rule
|
||||||
@@ -87,17 +86,15 @@ class GroupManagerV2Test_edit {
|
|||||||
|
|
||||||
val clientZkOperations = ClientZkOperations(server.getServerPublicParams())
|
val clientZkOperations = ClientZkOperations(server.getServerPublicParams())
|
||||||
|
|
||||||
groupTable = mock(GroupTable::class.java)
|
groupTable = mockk()
|
||||||
groupsV2API = mock(GroupsV2Api::class.java)
|
groupsV2API = mockk()
|
||||||
groupsV2Operations = GroupsV2Operations(clientZkOperations, 1000)
|
groupsV2Operations = GroupsV2Operations(clientZkOperations, 1000)
|
||||||
groupsV2Authorization = mock(GroupsV2Authorization::class.java)
|
groupsV2Authorization = mockk(relaxed = true)
|
||||||
groupsV2StateProcessor = mock(GroupsV2StateProcessor::class.java)
|
groupsV2StateProcessor = mockk()
|
||||||
groupCandidateHelper = mock(GroupCandidateHelper::class.java)
|
groupCandidateHelper = mockk()
|
||||||
sendGroupUpdateHelper = mock(GroupManagerV2.SendGroupUpdateHelper::class.java)
|
sendGroupUpdateHelper = mockk()
|
||||||
groupOperations = groupsV2Operations.forGroup(groupSecretParams)
|
groupOperations = groupsV2Operations.forGroup(groupSecretParams)
|
||||||
|
|
||||||
patchedDecryptedGroup = ArgumentCaptor.forClass(DecryptedGroup::class.java)
|
|
||||||
|
|
||||||
manager = GroupManagerV2(
|
manager = GroupManagerV2(
|
||||||
ApplicationProvider.getApplicationContext(),
|
ApplicationProvider.getApplicationContext(),
|
||||||
groupTable,
|
groupTable,
|
||||||
@@ -115,12 +112,11 @@ class GroupManagerV2Test_edit {
|
|||||||
val data = GroupStateTestData(masterKey, groupOperations)
|
val data = GroupStateTestData(masterKey, groupOperations)
|
||||||
data.init()
|
data.init()
|
||||||
|
|
||||||
Mockito.doReturn(data.groupRecord).`when`(groupTable).getGroup(groupId)
|
every { groupTable.getGroup(groupId) } returns data.groupRecord
|
||||||
Mockito.doReturn(data.groupRecord.get()).`when`(groupTable).requireGroup(groupId)
|
every { groupTable.requireGroup(groupId) } returns data.groupRecord.get()
|
||||||
|
every { groupTable.update(any<GroupId.V2>(), any()) } returns Unit
|
||||||
Mockito.doReturn(GroupManagerV2.RecipientAndThread(Recipient.UNKNOWN, 1)).`when`(sendGroupUpdateHelper).sendGroupUpdate(Mockito.eq(masterKey), Mockito.any(), Mockito.any(), Mockito.anyBoolean())
|
every { sendGroupUpdateHelper.sendGroupUpdate(masterKey, any(), any(), any()) } returns GroupManagerV2.RecipientAndThread(Recipient.UNKNOWN, 1)
|
||||||
|
every { groupsV2API.patchGroup(any(), any(), any()) } returns data.groupChange!!
|
||||||
Mockito.doReturn(data.groupChange!!).`when`(groupsV2API).patchGroup(Mockito.any(), Mockito.any(), Mockito.any())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun editGroup(perform: GroupManagerV2.GroupEditor.() -> Unit) {
|
private fun editGroup(perform: GroupManagerV2.GroupEditor.() -> Unit) {
|
||||||
@@ -128,8 +124,9 @@ class GroupManagerV2Test_edit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun then(then: (DecryptedGroup) -> Unit) {
|
private fun then(then: (DecryptedGroup) -> Unit) {
|
||||||
Mockito.verify(groupTable).update(Mockito.eq(groupId), patchedDecryptedGroup.capture())
|
val decryptedGroupArg = slot<DecryptedGroup>()
|
||||||
then(patchedDecryptedGroup.value)
|
verify { groupTable.update(groupId, capture(decryptedGroupArg)) }
|
||||||
|
then(decryptedGroupArg.captured)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
+37
-39
@@ -2,6 +2,10 @@ package org.thoughtcrime.securesms.groups.v2.processing
|
|||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.mockkStatic
|
||||||
|
import io.mockk.verify
|
||||||
import org.hamcrest.MatcherAssert.assertThat
|
import org.hamcrest.MatcherAssert.assertThat
|
||||||
import org.hamcrest.Matchers.both
|
import org.hamcrest.Matchers.both
|
||||||
import org.hamcrest.Matchers.hasItem
|
import org.hamcrest.Matchers.hasItem
|
||||||
@@ -13,18 +17,6 @@ import org.junit.Before
|
|||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mockito.ArgumentCaptor
|
|
||||||
import org.mockito.ArgumentMatchers.anyLong
|
|
||||||
import org.mockito.ArgumentMatchers.eq
|
|
||||||
import org.mockito.Mockito.any
|
|
||||||
import org.mockito.Mockito.doCallRealMethod
|
|
||||||
import org.mockito.Mockito.doReturn
|
|
||||||
import org.mockito.Mockito.isA
|
|
||||||
import org.mockito.Mockito.mock
|
|
||||||
import org.mockito.Mockito.reset
|
|
||||||
import org.mockito.Mockito.verify
|
|
||||||
import org.mockito.kotlin.anyOrNull
|
|
||||||
import org.mockito.kotlin.doNothing
|
|
||||||
import org.robolectric.RobolectricTestRunner
|
import org.robolectric.RobolectricTestRunner
|
||||||
import org.robolectric.annotation.Config
|
import org.robolectric.annotation.Config
|
||||||
import org.signal.core.util.Hex.fromStringCondensed
|
import org.signal.core.util.Hex.fromStringCondensed
|
||||||
@@ -48,6 +40,7 @@ import org.thoughtcrime.securesms.database.setNewTitle
|
|||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||||
import org.thoughtcrime.securesms.groups.GroupId
|
import org.thoughtcrime.securesms.groups.GroupId
|
||||||
import org.thoughtcrime.securesms.groups.GroupsV2Authorization
|
import org.thoughtcrime.securesms.groups.GroupsV2Authorization
|
||||||
|
import org.thoughtcrime.securesms.jobmanager.JobManager
|
||||||
import org.thoughtcrime.securesms.jobs.RequestGroupV2InfoJob
|
import org.thoughtcrime.securesms.jobs.RequestGroupV2InfoJob
|
||||||
import org.thoughtcrime.securesms.logging.CustomSignalProtocolLogger
|
import org.thoughtcrime.securesms.logging.CustomSignalProtocolLogger
|
||||||
import org.thoughtcrime.securesms.testutil.SystemOutLogger
|
import org.thoughtcrime.securesms.testutil.SystemOutLogger
|
||||||
@@ -77,6 +70,7 @@ class GroupsV2StateProcessorTest {
|
|||||||
private lateinit var groupsV2API: GroupsV2Api
|
private lateinit var groupsV2API: GroupsV2Api
|
||||||
private lateinit var groupsV2Authorization: GroupsV2Authorization
|
private lateinit var groupsV2Authorization: GroupsV2Authorization
|
||||||
private lateinit var profileAndMessageHelper: GroupsV2StateProcessor.ProfileAndMessageHelper
|
private lateinit var profileAndMessageHelper: GroupsV2StateProcessor.ProfileAndMessageHelper
|
||||||
|
private lateinit var jobManager: JobManager
|
||||||
|
|
||||||
private lateinit var processor: GroupsV2StateProcessor.StateProcessorForGroup
|
private lateinit var processor: GroupsV2StateProcessor.StateProcessorForGroup
|
||||||
|
|
||||||
@@ -88,25 +82,29 @@ class GroupsV2StateProcessorTest {
|
|||||||
Log.initialize(SystemOutLogger())
|
Log.initialize(SystemOutLogger())
|
||||||
SignalProtocolLoggerProvider.setProvider(CustomSignalProtocolLogger())
|
SignalProtocolLoggerProvider.setProvider(CustomSignalProtocolLogger())
|
||||||
|
|
||||||
groupTable = mock(GroupTable::class.java)
|
groupTable = mockk(relaxed = true)
|
||||||
recipientTable = mock(RecipientTable::class.java)
|
recipientTable = mockk()
|
||||||
groupsV2API = mock(GroupsV2Api::class.java)
|
groupsV2API = mockk()
|
||||||
groupsV2Authorization = mock(GroupsV2Authorization::class.java)
|
groupsV2Authorization = mockk(relaxed = true)
|
||||||
profileAndMessageHelper = mock(GroupsV2StateProcessor.ProfileAndMessageHelper::class.java)
|
profileAndMessageHelper = mockk(relaxed = true)
|
||||||
|
jobManager = mockk(relaxed = true)
|
||||||
|
|
||||||
|
mockkStatic(ApplicationDependencies::class)
|
||||||
|
every { ApplicationDependencies.getJobManager() } returns jobManager
|
||||||
|
|
||||||
processor = GroupsV2StateProcessor.StateProcessorForGroup(serviceIds, ApplicationProvider.getApplicationContext(), groupTable, groupsV2API, groupsV2Authorization, masterKey, profileAndMessageHelper)
|
processor = GroupsV2StateProcessor.StateProcessorForGroup(serviceIds, ApplicationProvider.getApplicationContext(), groupTable, groupsV2API, groupsV2Authorization, masterKey, profileAndMessageHelper)
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
fun tearDown() {
|
fun tearDown() {
|
||||||
reset(ApplicationDependencies.getJobManager())
|
// reset(ApplicationDependencies.getJobManager())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun given(init: GroupStateTestData.() -> Unit) {
|
private fun given(init: GroupStateTestData.() -> Unit) {
|
||||||
val data = givenData(init)
|
val data = givenData(init)
|
||||||
|
|
||||||
doReturn(data.groupRecord).`when`(groupTable).getGroup(any(GroupId.V2::class.java))
|
every { groupTable.getGroup(any<GroupId.V2>()) } returns data.groupRecord
|
||||||
doReturn(!data.groupRecord.isPresent).`when`(groupTable).isUnknownGroup(any())
|
every { groupTable.isUnknownGroup(any()) } returns !data.groupRecord.isPresent
|
||||||
|
|
||||||
data.serverState?.let { serverState ->
|
data.serverState?.let { serverState ->
|
||||||
val testPartial = object : PartialDecryptedGroup(null, serverState, null, null) {
|
val testPartial = object : PartialDecryptedGroup(null, serverState, null, null) {
|
||||||
@@ -114,12 +112,13 @@ class GroupsV2StateProcessorTest {
|
|||||||
return serverState
|
return serverState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
doReturn(testPartial).`when`(groupsV2API).getPartialDecryptedGroup(any(), any())
|
|
||||||
doReturn(serverState).`when`(groupsV2API).getGroup(any(), any())
|
every { groupsV2API.getPartialDecryptedGroup(any(), any()) } returns testPartial
|
||||||
|
every { groupsV2API.getGroup(any(), any()) } returns serverState
|
||||||
}
|
}
|
||||||
|
|
||||||
data.changeSet?.let { changeSet ->
|
data.changeSet?.let { changeSet ->
|
||||||
doReturn(changeSet.toApiResponse()).`when`(groupsV2API).getGroupHistoryPage(any(), eq(data.requestedRevision), any(), eq(data.includeFirst))
|
every { groupsV2API.getGroupHistoryPage(any(), data.requestedRevision, any(), data.includeFirst) } returns changeSet.toApiResponse()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,15 +305,14 @@ class GroupsV2StateProcessorTest {
|
|||||||
apiCallParameters(2, true)
|
apiCallParameters(2, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
doReturn(true).`when`(groupTable).isUnknownGroup(any())
|
every { groupTable.isUnknownGroup(any()) } returns true
|
||||||
|
|
||||||
val result = processor.updateLocalGroupToRevision(2, 0, DecryptedGroupChange.getDefaultInstance())
|
val result = processor.updateLocalGroupToRevision(2, 0, DecryptedGroupChange.getDefaultInstance())
|
||||||
|
|
||||||
assertThat("local should update to revision added", result.groupState, `is`(GroupsV2StateProcessor.GroupState.GROUP_UPDATED))
|
assertThat("local should update to revision added", result.groupState, `is`(GroupsV2StateProcessor.GroupState.GROUP_UPDATED))
|
||||||
assertThat("revision matches peer revision added", result.latestServer!!.revision, `is`(2))
|
assertThat("revision matches peer revision added", result.latestServer!!.revision, `is`(2))
|
||||||
assertThat("title matches that as it was in revision added", result.latestServer!!.title, `is`("Baking Signal for Science"))
|
assertThat("title matches that as it was in revision added", result.latestServer!!.title, `is`("Baking Signal for Science"))
|
||||||
|
verify { jobManager.add(ofType(RequestGroupV2InfoJob::class)) }
|
||||||
verify(ApplicationDependencies.getJobManager()).add(isA(RequestGroupV2InfoJob::class.java))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -406,7 +404,7 @@ class GroupsV2StateProcessorTest {
|
|||||||
assertThat("local should update to server", result.groupState, `is`(GroupsV2StateProcessor.GroupState.GROUP_UPDATED))
|
assertThat("local should update to server", result.groupState, `is`(GroupsV2StateProcessor.GroupState.GROUP_UPDATED))
|
||||||
assertThat("revision matches revision approved at", result.latestServer!!.revision, `is`(3))
|
assertThat("revision matches revision approved at", result.latestServer!!.revision, `is`(3))
|
||||||
assertThat("title matches revision approved at", result.latestServer!!.title, `is`("Beam me up"))
|
assertThat("title matches revision approved at", result.latestServer!!.title, `is`("Beam me up"))
|
||||||
verify(ApplicationDependencies.getJobManager()).add(isA(RequestGroupV2InfoJob::class.java))
|
verify { jobManager.add(ofType(RequestGroupV2InfoJob::class)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -458,7 +456,7 @@ class GroupsV2StateProcessorTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
doReturn(secondApiCallChangeSet.changeSet!!.toApiResponse()).`when`(groupsV2API).getGroupHistoryPage(any(), eq(100), any(), eq(true))
|
every { groupsV2API.getGroupHistoryPage(any(), 100, any(), true) } returns secondApiCallChangeSet.changeSet!!.toApiResponse()
|
||||||
|
|
||||||
val result = processor.updateLocalGroupToRevision(GroupsV2StateProcessor.LATEST, 0, null)
|
val result = processor.updateLocalGroupToRevision(GroupsV2StateProcessor.LATEST, 0, null)
|
||||||
|
|
||||||
@@ -474,10 +472,11 @@ class GroupsV2StateProcessorTest {
|
|||||||
fun missedMemberAddResolvesWithMultipleRevisionUpdate() {
|
fun missedMemberAddResolvesWithMultipleRevisionUpdate() {
|
||||||
val secondOther = member(ServiceId.from(UUID.randomUUID()))
|
val secondOther = member(ServiceId.from(UUID.randomUUID()))
|
||||||
|
|
||||||
val updateMessageContextCapture = ArgumentCaptor.forClass(DecryptedGroupV2Context::class.java)
|
|
||||||
profileAndMessageHelper.masterKey = masterKey
|
profileAndMessageHelper.masterKey = masterKey
|
||||||
doCallRealMethod().`when`(profileAndMessageHelper).insertUpdateMessages(anyLong(), anyOrNull(), any())
|
|
||||||
doNothing().`when`(profileAndMessageHelper).storeMessage(updateMessageContextCapture.capture(), anyLong())
|
val updateMessageContextArgs = mutableListOf<DecryptedGroupV2Context>()
|
||||||
|
every { profileAndMessageHelper.insertUpdateMessages(any(), any(), any()) } answers { callOriginal() }
|
||||||
|
every { profileAndMessageHelper.storeMessage(capture(updateMessageContextArgs), any()) } returns Unit
|
||||||
|
|
||||||
given {
|
given {
|
||||||
localState(
|
localState(
|
||||||
@@ -513,8 +512,7 @@ class GroupsV2StateProcessorTest {
|
|||||||
assertThat("local should update to server", result.groupState, `is`(GroupsV2StateProcessor.GroupState.GROUP_UPDATED))
|
assertThat("local should update to server", result.groupState, `is`(GroupsV2StateProcessor.GroupState.GROUP_UPDATED))
|
||||||
assertThat("members contains second other", result.latestServer!!.membersList, hasItem(secondOther))
|
assertThat("members contains second other", result.latestServer!!.membersList, hasItem(secondOther))
|
||||||
|
|
||||||
val allUpdateMessageContexts = updateMessageContextCapture.allValues
|
assertThat("group update messages contains new member add", updateMessageContextArgs.map { it.change.newMembersList }, hasItem(hasItem(secondOther)))
|
||||||
assertThat("group update messages contains new member add", allUpdateMessageContexts.map { it.change.newMembersList }, hasItem(hasItem(secondOther)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -525,10 +523,11 @@ class GroupsV2StateProcessorTest {
|
|||||||
fun missedMemberAddResolvesWithForcedUpdate() {
|
fun missedMemberAddResolvesWithForcedUpdate() {
|
||||||
val secondOther = member(ServiceId.from(UUID.randomUUID()))
|
val secondOther = member(ServiceId.from(UUID.randomUUID()))
|
||||||
|
|
||||||
val updateMessageContextCapture = ArgumentCaptor.forClass(DecryptedGroupV2Context::class.java)
|
|
||||||
profileAndMessageHelper.masterKey = masterKey
|
profileAndMessageHelper.masterKey = masterKey
|
||||||
doCallRealMethod().`when`(profileAndMessageHelper).insertUpdateMessages(anyLong(), anyOrNull(), any())
|
|
||||||
doNothing().`when`(profileAndMessageHelper).storeMessage(updateMessageContextCapture.capture(), anyLong())
|
val updateMessageContextArgs = mutableListOf<DecryptedGroupV2Context>()
|
||||||
|
every { profileAndMessageHelper.insertUpdateMessages(any(), any(), any()) } answers { callOriginal() }
|
||||||
|
every { profileAndMessageHelper.storeMessage(capture(updateMessageContextArgs), any()) } returns Unit
|
||||||
|
|
||||||
given {
|
given {
|
||||||
localState(
|
localState(
|
||||||
@@ -548,12 +547,11 @@ class GroupsV2StateProcessorTest {
|
|||||||
assertThat("members contains second other", result.latestServer!!.membersList, hasItem(secondOther))
|
assertThat("members contains second other", result.latestServer!!.membersList, hasItem(secondOther))
|
||||||
assertThat("title should be updated", result.latestServer!!.title, `is`("Changed"))
|
assertThat("title should be updated", result.latestServer!!.title, `is`("Changed"))
|
||||||
|
|
||||||
val allUpdateMessageContexts = updateMessageContextCapture.allValues
|
assertThat("group update messages contains new member add", updateMessageContextArgs.map { it.change.newMembersList }, hasItem(hasItem(secondOther)))
|
||||||
assertThat("group update messages contains new member add", allUpdateMessageContexts.map { it.change.newMembersList }, hasItem(hasItem(secondOther)))
|
|
||||||
|
|
||||||
assertThat(
|
assertThat(
|
||||||
"group update messages contains title change",
|
"group update messages contains title change",
|
||||||
allUpdateMessageContexts.map { it.change.newTitle },
|
updateMessageContextArgs.map { it.change.newTitle },
|
||||||
hasItem(both<DecryptedString>(notNullValue()).and(hasProperty("value", `is`("Changed"))))
|
hasItem(both<DecryptedString>(notNullValue()).and(hasProperty("value", `is`("Changed"))))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.jobmanager.migrations;
|
|||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.thoughtcrime.securesms.database.GroupTable;
|
import org.thoughtcrime.securesms.database.GroupTable;
|
||||||
|
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
import org.thoughtcrime.securesms.jobmanager.JobMigration;
|
import org.thoughtcrime.securesms.jobmanager.JobMigration;
|
||||||
@@ -34,7 +35,7 @@ public class SenderKeyDistributionSendJobRecipientMigrationTest {
|
|||||||
.putBlobAsString("group_id", GROUP_ID.getDecodedId())
|
.putBlobAsString("group_id", GROUP_ID.getDecodedId())
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
GroupTable.GroupRecord mockGroup = mock(GroupTable.GroupRecord.class);
|
GroupRecord mockGroup = mock(GroupRecord.class);
|
||||||
when(mockGroup.getRecipientId()).thenReturn(RecipientId.from(2));
|
when(mockGroup.getRecipientId()).thenReturn(RecipientId.from(2));
|
||||||
when(mockDatabase.getGroup(GROUP_ID)).thenReturn(Optional.of(mockGroup));
|
when(mockDatabase.getGroup(GROUP_ID)).thenReturn(Optional.of(mockGroup));
|
||||||
|
|
||||||
|
|||||||
@@ -92,6 +92,16 @@ fun <T> Cursor.readToSingleObject(serializer: Serializer<T, Cursor>): T? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T> Cursor.readToSingleObject(mapper: (Cursor) -> T): T? {
|
||||||
|
return use {
|
||||||
|
if (it.moveToFirst()) {
|
||||||
|
mapper(it)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun Cursor.readToSingleInt(defaultValue: Int = 0): Int {
|
fun Cursor.readToSingleInt(defaultValue: Int = 0): Int {
|
||||||
return use {
|
return use {
|
||||||
|
|||||||
Reference in New Issue
Block a user