mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-11 18:29:05 +01:00
Recreate plausible private group sharing sessions when re-adding contact from group
This commit is contained in:
@@ -110,9 +110,9 @@ public interface PrivateGroupManager {
|
|||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the private group with the given ID was created by us.
|
* Returns true if the given private group was created by us.
|
||||||
*/
|
*/
|
||||||
boolean isOurPrivateGroup(Transaction txn, GroupId g) throws DbException;
|
boolean isOurPrivateGroup(Transaction txn, PrivateGroup g) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text of the private group message with the given ID.
|
* Returns the text of the private group message with the given ID.
|
||||||
|
|||||||
@@ -287,11 +287,10 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isOurPrivateGroup(Transaction txn, GroupId g)
|
public boolean isOurPrivateGroup(Transaction txn, PrivateGroup g)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
PrivateGroup group = getPrivateGroup(txn, g);
|
|
||||||
LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
|
LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
|
||||||
return localAuthor.getId().equals(group.getCreator().getId());
|
return localAuthor.getId().equals(g.getCreator().getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -126,20 +126,60 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
|
|||||||
db.setGroupVisibility(txn, c.getId(), g.getId(), client);
|
db.setGroupVisibility(txn, c.getId(), g.getId(), client);
|
||||||
// Attach the contact ID to the group
|
// Attach the contact ID to the group
|
||||||
clientHelper.setContactId(txn, g.getId(), c.getId());
|
clientHelper.setContactId(txn, g.getId(), c.getId());
|
||||||
// If the contact belongs to any private groups (we didn't create),
|
// If the contact belongs to any private groups, create a peer session
|
||||||
// create a peer session
|
// or sessions in LEFT state for creator/invitee.
|
||||||
for (Group pg : db.getGroups(txn, PrivateGroupManager.CLIENT_ID,
|
for (Group group : db.getGroups(txn, PrivateGroupManager.CLIENT_ID,
|
||||||
PrivateGroupManager.MAJOR_VERSION)) {
|
PrivateGroupManager.MAJOR_VERSION)) {
|
||||||
if (privateGroupManager.isMember(txn, pg.getId(), c.getAuthor())) {
|
if (privateGroupManager
|
||||||
if (!privateGroupManager.isOurPrivateGroup(txn, pg.getId())) {
|
.isMember(txn, group.getId(), c.getAuthor())) {
|
||||||
addingMember(txn, pg.getId(), c);
|
PrivateGroup pg =
|
||||||
}
|
privateGroupManager.getPrivateGroup(txn, group.getId());
|
||||||
|
recreateSession(txn, c, pg, g.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void recreateSession(Transaction txn, Contact c,
|
||||||
|
PrivateGroup pg, GroupId contactGroupId) throws DbException {
|
||||||
|
boolean isOur = privateGroupManager.isOurPrivateGroup(txn, pg);
|
||||||
|
boolean isTheirs =
|
||||||
|
c.getAuthor().getId().equals(pg.getCreator().getId());
|
||||||
|
if (isOur || isTheirs) {
|
||||||
|
// we are creator or invitee, create a left session for each role
|
||||||
|
MessageId storageId = createStorageId(txn, contactGroupId);
|
||||||
|
Session<?> session;
|
||||||
|
if (isOur) {
|
||||||
|
session = new CreatorSession(contactGroupId, pg.getId(), null,
|
||||||
|
null, 0, 0, CreatorState.LEFT);
|
||||||
|
} else {
|
||||||
|
session = new InviteeSession(contactGroupId, pg.getId(), null,
|
||||||
|
null, 0, 0, InviteeState.LEFT);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
storeSession(txn, storageId, session);
|
||||||
|
} catch (FormatException e) {
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// we are neither creator nor invitee, create peer session
|
||||||
|
addingMember(txn, pg.getId(), c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removingContact(Transaction txn, Contact c) throws DbException {
|
public void removingContact(Transaction txn, Contact c) throws DbException {
|
||||||
|
// mark private groups created by that contact as dissolved
|
||||||
|
for (Group g : db.getGroups(txn, PrivateGroupManager.CLIENT_ID,
|
||||||
|
PrivateGroupManager.MAJOR_VERSION)) {
|
||||||
|
if (privateGroupManager.isMember(txn, g.getId(), c.getAuthor())) {
|
||||||
|
PrivateGroup pg =
|
||||||
|
privateGroupManager.getPrivateGroup(txn, g.getId());
|
||||||
|
// check if contact to be removed is creator of the group
|
||||||
|
if (c.getAuthor().getId().equals(pg.getCreator().getId())) {
|
||||||
|
privateGroupManager.markGroupDissolved(txn, g.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// Remove the contact group (all messages will be removed with it)
|
// Remove the contact group (all messages will be removed with it)
|
||||||
db.removeGroup(txn, getContactGroup(c));
|
db.removeGroup(txn, getContactGroup(c));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -722,15 +722,26 @@ public class GroupInvitationIntegrationTest
|
|||||||
sync0To1(2, true); // + one invitation protocol join message
|
sync0To1(2, true); // + one invitation protocol join message
|
||||||
sync1To0(1, true);
|
sync1To0(1, true);
|
||||||
|
|
||||||
|
// inviting again is not possible
|
||||||
assertFalse(groupInvitationManager0
|
assertFalse(groupInvitationManager0
|
||||||
.isInvitationAllowed(contact1From0, privateGroup.getId()));
|
.isInvitationAllowed(contact1From0, privateGroup.getId()));
|
||||||
|
|
||||||
// re-add contacts
|
// contacts remove each other
|
||||||
removeAllContacts();
|
removeAllContacts();
|
||||||
|
|
||||||
|
// group gets dissolved for invitee automatically, but not creator
|
||||||
|
assertFalse(groupManager0.isDissolved(privateGroup.getId()));
|
||||||
|
assertTrue(groupManager1.isDissolved(privateGroup.getId()));
|
||||||
|
|
||||||
|
// contacts re-add each other
|
||||||
addDefaultContacts();
|
addDefaultContacts();
|
||||||
|
|
||||||
assertTrue(groupInvitationManager0
|
// creator can still not invite again
|
||||||
|
assertFalse(groupInvitationManager0
|
||||||
.isInvitationAllowed(contact1From0, privateGroup.getId()));
|
.isInvitationAllowed(contact1From0, privateGroup.getId()));
|
||||||
|
|
||||||
|
// finally invitee can remove group without issues
|
||||||
|
groupManager1.removePrivateGroup(privateGroup.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Collection<ConversationMessageHeader> getMessages1From0()
|
private Collection<ConversationMessageHeader> getMessages1From0()
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ import java.util.Map;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
import static junit.framework.TestCase.fail;
|
import static junit.framework.TestCase.fail;
|
||||||
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getAuthor;
|
import static org.briarproject.bramble.test.TestUtils.getAuthor;
|
||||||
@@ -105,7 +107,9 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
|||||||
private final ContactId contactId = contact.getId();
|
private final ContactId contactId = contact.getId();
|
||||||
private final Group localGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
|
private final Group localGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
|
||||||
private final Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
|
private final Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
|
||||||
private final Group privateGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
|
private final Group group = getGroup(CLIENT_ID, MAJOR_VERSION);
|
||||||
|
private final PrivateGroup privateGroup = new PrivateGroup(group,
|
||||||
|
getRandomString(5), getAuthor(), getRandomBytes(32));
|
||||||
private final BdfDictionary meta = BdfDictionary.of(new BdfEntry("m", "e"));
|
private final BdfDictionary meta = BdfDictionary.of(new BdfEntry("m", "e"));
|
||||||
private final Message message = getMessage(contactGroup.getId());
|
private final Message message = getMessage(contactGroup.getId());
|
||||||
private final BdfList body = BdfList.of("body");
|
private final BdfList body = BdfList.of("body");
|
||||||
@@ -159,9 +163,9 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
oneOf(db).addGroup(txn, localGroup);
|
oneOf(db).addGroup(txn, localGroup);
|
||||||
oneOf(db).getContacts(txn);
|
oneOf(db).getContacts(txn);
|
||||||
will(returnValue(Collections.singletonList(contact)));
|
will(returnValue(singletonList(contact)));
|
||||||
}});
|
}});
|
||||||
expectAddingContact(contact);
|
expectAddingContact(contact, emptyList());
|
||||||
groupInvitationManager.onDatabaseOpened(txn);
|
groupInvitationManager.onDatabaseOpened(txn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,7 +181,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
|||||||
groupInvitationManager.onDatabaseOpened(txn);
|
groupInvitationManager.onDatabaseOpened(txn);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void expectAddingContact(Contact c) throws Exception {
|
private void expectAddingContact(Contact c, Collection<Group> groups)
|
||||||
|
throws Exception {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||||
MAJOR_VERSION, c);
|
MAJOR_VERSION, c);
|
||||||
@@ -192,15 +197,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
|||||||
.setContactId(txn, contactGroup.getId(), contactId);
|
.setContactId(txn, contactGroup.getId(), contactId);
|
||||||
oneOf(db).getGroups(txn, PrivateGroupManager.CLIENT_ID,
|
oneOf(db).getGroups(txn, PrivateGroupManager.CLIENT_ID,
|
||||||
PrivateGroupManager.MAJOR_VERSION);
|
PrivateGroupManager.MAJOR_VERSION);
|
||||||
will(returnValue(Collections.singletonList(privateGroup)));
|
will(returnValue(groups));
|
||||||
oneOf(privateGroupManager).isMember(txn, privateGroup.getId(),
|
|
||||||
c.getAuthor());
|
|
||||||
will(returnValue(true));
|
|
||||||
oneOf(privateGroupManager)
|
|
||||||
.isOurPrivateGroup(txn, privateGroup.getId());
|
|
||||||
will(returnValue(false));
|
|
||||||
}});
|
}});
|
||||||
expectAddingMember(privateGroup.getId(), c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void expectAddingMember(GroupId g, Contact c) throws Exception {
|
private void expectAddingMember(GroupId g, Contact c) throws Exception {
|
||||||
@@ -254,13 +252,99 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddingContact() throws Exception {
|
public void testAddingContact() throws Exception {
|
||||||
expectAddingContact(contact);
|
expectAddingContact(contact, singletonList(group));
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(privateGroupManager)
|
||||||
|
.isMember(txn, privateGroup.getId(), contact.getAuthor());
|
||||||
|
will(returnValue(true));
|
||||||
|
oneOf(privateGroupManager)
|
||||||
|
.getPrivateGroup(txn, privateGroup.getId());
|
||||||
|
will(returnValue(privateGroup));
|
||||||
|
oneOf(privateGroupManager).isOurPrivateGroup(txn, privateGroup);
|
||||||
|
will(returnValue(false));
|
||||||
|
}});
|
||||||
|
// creates PEER session
|
||||||
|
expectAddingMember(privateGroup.getId(), contact);
|
||||||
|
|
||||||
groupInvitationManager.addingContact(txn, contact);
|
groupInvitationManager.addingContact(txn, contact);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemovingContact() throws Exception {
|
public void testAddingContactWhoCreatedGroup() throws Exception {
|
||||||
|
PrivateGroup privateGroup = new PrivateGroup(group,
|
||||||
|
getRandomString(5), contact.getAuthor(), getRandomBytes(32));
|
||||||
|
|
||||||
|
expectAddingContact(contact, singletonList(group));
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(privateGroupManager)
|
||||||
|
.isMember(txn, privateGroup.getId(), contact.getAuthor());
|
||||||
|
will(returnValue(true));
|
||||||
|
oneOf(privateGroupManager)
|
||||||
|
.getPrivateGroup(txn, privateGroup.getId());
|
||||||
|
will(returnValue(privateGroup));
|
||||||
|
oneOf(privateGroupManager).isOurPrivateGroup(txn, privateGroup);
|
||||||
|
will(returnValue(false));
|
||||||
|
}});
|
||||||
|
expectCreateStorageId();
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(sessionEncoder)
|
||||||
|
.encodeSession(with(any(InviteeSession.class)));
|
||||||
|
will(returnValue(meta));
|
||||||
|
oneOf(clientHelper)
|
||||||
|
.mergeMessageMetadata(txn, storageMessage.getId(), meta);
|
||||||
|
}});
|
||||||
|
|
||||||
|
groupInvitationManager.addingContact(txn, contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemovingContactWithoutCommonGroups() throws Exception {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(db).getGroups(txn, PrivateGroupManager.CLIENT_ID,
|
||||||
|
PrivateGroupManager.MAJOR_VERSION);
|
||||||
|
will(returnValue(emptyList()));
|
||||||
|
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||||
|
MAJOR_VERSION, contact);
|
||||||
|
will(returnValue(contactGroup));
|
||||||
|
oneOf(db).removeGroup(txn, contactGroup);
|
||||||
|
}});
|
||||||
|
groupInvitationManager.removingContact(txn, contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemovingContactWithCommonGroups() throws Exception {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(db).getGroups(txn, PrivateGroupManager.CLIENT_ID,
|
||||||
|
PrivateGroupManager.MAJOR_VERSION);
|
||||||
|
will(returnValue(singletonList(group)));
|
||||||
|
oneOf(privateGroupManager).isMember(txn, group.getId(), author);
|
||||||
|
will(returnValue(true));
|
||||||
|
oneOf(privateGroupManager).getPrivateGroup(txn, group.getId());
|
||||||
|
will(returnValue(privateGroup));
|
||||||
|
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||||
|
MAJOR_VERSION, contact);
|
||||||
|
will(returnValue(contactGroup));
|
||||||
|
oneOf(db).removeGroup(txn, contactGroup);
|
||||||
|
}});
|
||||||
|
groupInvitationManager.removingContact(txn, contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemovingContactWhoIsCreatorOfCommonGroup()
|
||||||
|
throws Exception {
|
||||||
|
PrivateGroup privateGroup = new PrivateGroup(group,
|
||||||
|
getRandomString(5), contact.getAuthor(), getRandomBytes(32));
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(db).getGroups(txn, PrivateGroupManager.CLIENT_ID,
|
||||||
|
PrivateGroupManager.MAJOR_VERSION);
|
||||||
|
will(returnValue(singletonList(group)));
|
||||||
|
oneOf(privateGroupManager).isMember(txn, group.getId(), author);
|
||||||
|
will(returnValue(true));
|
||||||
|
oneOf(privateGroupManager).getPrivateGroup(txn, group.getId());
|
||||||
|
will(returnValue(privateGroup));
|
||||||
|
oneOf(privateGroupManager).markGroupDissolved(txn, group.getId());
|
||||||
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||||
MAJOR_VERSION, contact);
|
MAJOR_VERSION, contact);
|
||||||
will(returnValue(contactGroup));
|
will(returnValue(contactGroup));
|
||||||
@@ -350,8 +434,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
|||||||
BdfDictionary bdfSession) throws Exception {
|
BdfDictionary bdfSession) throws Exception {
|
||||||
expectParseMessageMetadata();
|
expectParseMessageMetadata();
|
||||||
expectGetSession(oneResult, sessionId, contactGroup.getId());
|
expectGetSession(oneResult, sessionId, contactGroup.getId());
|
||||||
Session<?> session =
|
Session<?> session = expectHandleMessage(role, messageMetadata,
|
||||||
expectHandleMessage(role, messageMetadata, bdfSession, type);
|
bdfSession, type);
|
||||||
expectStoreSession(session, storageMessage.getId());
|
expectStoreSession(session, storageMessage.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -564,7 +648,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAcceptInvitationWithGroupId() throws Exception {
|
public void testAcceptInvitationWithGroupId() throws Exception {
|
||||||
PrivateGroup pg = new PrivateGroup(privateGroup,
|
PrivateGroup pg = new PrivateGroup(group,
|
||||||
getRandomString(MAX_GROUP_NAME_LENGTH), author,
|
getRandomString(MAX_GROUP_NAME_LENGTH), author,
|
||||||
getRandomBytes(GROUP_SALT_LENGTH));
|
getRandomBytes(GROUP_SALT_LENGTH));
|
||||||
|
|
||||||
@@ -574,7 +658,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeclineInvitationWithGroupId() throws Exception {
|
public void testDeclineInvitationWithGroupId() throws Exception {
|
||||||
PrivateGroup pg = new PrivateGroup(privateGroup,
|
PrivateGroup pg = new PrivateGroup(group,
|
||||||
getRandomString(MAX_GROUP_NAME_LENGTH), author,
|
getRandomString(MAX_GROUP_NAME_LENGTH), author,
|
||||||
getRandomBytes(GROUP_SALT_LENGTH));
|
getRandomBytes(GROUP_SALT_LENGTH));
|
||||||
|
|
||||||
@@ -665,7 +749,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
|||||||
privateGroup.getId(), time1, "name", author,
|
privateGroup.getId(), time1, "name", author,
|
||||||
new byte[0], null, new byte[0], NO_AUTO_DELETE_TIMER);
|
new byte[0], null, new byte[0], NO_AUTO_DELETE_TIMER);
|
||||||
PrivateGroup pg =
|
PrivateGroup pg =
|
||||||
new PrivateGroup(privateGroup, invite.getGroupName(),
|
new PrivateGroup(group, invite.getGroupName(),
|
||||||
invite.getCreator(), invite.getSalt());
|
invite.getCreator(), invite.getSalt());
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
@@ -733,7 +817,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
|||||||
new InviteMessage(message2.getId(), contactGroup.getId(),
|
new InviteMessage(message2.getId(), contactGroup.getId(),
|
||||||
privateGroup.getId(), time2, groupName, author, salt,
|
privateGroup.getId(), time2, groupName, author, salt,
|
||||||
null, getRandomBytes(5), NO_AUTO_DELETE_TIMER);
|
null, getRandomBytes(5), NO_AUTO_DELETE_TIMER);
|
||||||
PrivateGroup pg = new PrivateGroup(privateGroup, groupName,
|
PrivateGroup pg = new PrivateGroup(group, groupName,
|
||||||
author, salt);
|
author, salt);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
@@ -742,7 +826,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(db).startTransaction(true);
|
oneOf(db).startTransaction(true);
|
||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
oneOf(db).getContacts(txn);
|
oneOf(db).getContacts(txn);
|
||||||
will(returnValue(Collections.singletonList(contact)));
|
will(returnValue(singletonList(contact)));
|
||||||
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||||
MAJOR_VERSION, contact);
|
MAJOR_VERSION, contact);
|
||||||
will(returnValue(contactGroup));
|
will(returnValue(contactGroup));
|
||||||
@@ -834,7 +918,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
|||||||
expectAddingMember(privateGroup.getId(), contact);
|
expectAddingMember(privateGroup.getId(), contact);
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(db).getContactsByAuthorId(txn, author.getId());
|
oneOf(db).getContactsByAuthorId(txn, author.getId());
|
||||||
will(returnValue(Collections.singletonList(contact)));
|
will(returnValue(singletonList(contact)));
|
||||||
}});
|
}});
|
||||||
groupInvitationManager.addingMember(txn, privateGroup.getId(), author);
|
groupInvitationManager.addingMember(txn, privateGroup.getId(), author);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user