From 3eed0bfe8151173914798bca75be643ad6d83d5d Mon Sep 17 00:00:00 2001
From: Torsten Grote <t@grobox.de>
Date: Wed, 9 Nov 2016 16:26:32 -0200
Subject: [PATCH] Add visibility of contact relationship to JoinMessageHeader

---
 .../briarproject/PrivateGroupManagerTest.java | 75 +++++++++++++++++++
 .../api/privategroup/JoinMessageHeader.java   | 18 +++--
 .../privategroup/PrivateGroupManagerImpl.java | 51 +++++++++----
 3 files changed, 121 insertions(+), 23 deletions(-)

diff --git a/briar-android-tests/src/test/java/org/briarproject/PrivateGroupManagerTest.java b/briar-android-tests/src/test/java/org/briarproject/PrivateGroupManagerTest.java
index 6b149c13fa..0d79b1b027 100644
--- a/briar-android-tests/src/test/java/org/briarproject/PrivateGroupManagerTest.java
+++ b/briar-android-tests/src/test/java/org/briarproject/PrivateGroupManagerTest.java
@@ -212,6 +212,7 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
 		defaultInit();
 
 		// create and add test message with no previousMsgId
+		@SuppressWarnings("ConstantConditions")
 		GroupMessage msg = groupMessageFactory
 				.createGroupMessage(groupId0, clock.currentTimeMillis(), null,
 						author0, "test", null);
@@ -484,6 +485,35 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
 		}
 	}
 
+	@Test
+	public void testJoinMessages() throws Exception {
+		defaultInit();
+
+		Collection<GroupMessageHeader> headers0 =
+				groupManager0.getHeaders(groupId0);
+		for (GroupMessageHeader h : headers0) {
+			if (h instanceof JoinMessageHeader) {
+				JoinMessageHeader j = (JoinMessageHeader) h;
+				// all relationships of the creator are visible
+				assertEquals(VISIBLE, j.getVisibility());
+			}
+		}
+
+		Collection<GroupMessageHeader> headers1 =
+				groupManager1.getHeaders(groupId0);
+		for (GroupMessageHeader h : headers1) {
+			if (h instanceof JoinMessageHeader) {
+				JoinMessageHeader j = (JoinMessageHeader) h;
+				if (h.getAuthor().equals(author1))
+					// we are visible to ourselves
+					assertEquals(VISIBLE, j.getVisibility());
+				else
+					// our relationship to the creator is visible
+					assertEquals(VISIBLE, j.getVisibility());
+			}
+		}
+	}
+
 	@Test
 	public void testRevealingRelationships() throws Exception {
 		defaultInit();
@@ -568,6 +598,51 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
 				assertEquals(REVEALED_BY_CONTACT, m.getVisibility());
 			}
 		}
+
+		// assert that join messages reflect revealed relationship
+		Collection<GroupMessageHeader> headers1 =
+				groupManager1.getHeaders(groupId0);
+		for (GroupMessageHeader h : headers1) {
+			if (h instanceof JoinMessageHeader) {
+				JoinMessageHeader j = (JoinMessageHeader) h;
+				if (h.getAuthor().equals(author2))
+					// 1 revealed the relationship to 2
+					assertEquals(REVEALED_BY_YOU, j.getVisibility());
+				else
+					// 1's other relationship (to 1 and creator) are visible
+					assertEquals(VISIBLE, j.getVisibility());
+			}
+		}
+		Collection<GroupMessageHeader> headers2 =
+				groupManager2.getHeaders(groupId0);
+		for (GroupMessageHeader h : headers2) {
+			if (h instanceof JoinMessageHeader) {
+				JoinMessageHeader j = (JoinMessageHeader) h;
+				if (h.getAuthor().equals(author1))
+					// 2's relationship was revealed by 1
+					assertEquals(REVEALED_BY_CONTACT, j.getVisibility());
+				else
+					// 2's other relationship (to 2 and creator) are visible
+					assertEquals(VISIBLE, j.getVisibility());
+			}
+		}
+	}
+
+	@Test
+	public void testDissolveGroup() throws Exception {
+		defaultInit();
+
+		// group is not dissolved initially
+		assertFalse(groupManager0.isDissolved(groupId0));
+
+		// creator dissolves group
+		Transaction txn0 = db0.startTransaction(false);
+		groupManager0.markGroupDissolved(txn0, groupId0);
+		db0.commitTransaction(txn0);
+		db0.endTransaction(txn0);
+
+		// group is dissolved now
+		assertTrue(groupManager0.isDissolved(groupId0));
 	}
 
 	@After
diff --git a/briar-api/src/org/briarproject/api/privategroup/JoinMessageHeader.java b/briar-api/src/org/briarproject/api/privategroup/JoinMessageHeader.java
index ef8c3b337d..8b14717a6e 100644
--- a/briar-api/src/org/briarproject/api/privategroup/JoinMessageHeader.java
+++ b/briar-api/src/org/briarproject/api/privategroup/JoinMessageHeader.java
@@ -1,10 +1,6 @@
 package org.briarproject.api.privategroup;
 
-import org.briarproject.api.identity.Author;
 import org.briarproject.api.nullsafety.NotNullByDefault;
-import org.briarproject.api.sync.GroupId;
-import org.briarproject.api.sync.MessageId;
-import org.jetbrains.annotations.Nullable;
 
 import javax.annotation.concurrent.Immutable;
 
@@ -12,10 +8,16 @@ import javax.annotation.concurrent.Immutable;
 @NotNullByDefault
 public class JoinMessageHeader extends GroupMessageHeader {
 
-	public JoinMessageHeader(GroupId groupId, MessageId id,
-			@Nullable MessageId parentId, long timestamp, Author author,
-			Author.Status authorStatus, boolean read) {
-		super(groupId, id, parentId, timestamp, author, authorStatus, read);
+	private final Visibility visibility;
+
+	public JoinMessageHeader(GroupMessageHeader h, Visibility visibility) {
+		super(h.getGroupId(), h.getId(), h.getParentId(), h.getTimestamp(),
+				h.getAuthor(), h.getAuthorStatus(), h.isRead());
+		this.visibility = visibility;
+	}
+
+	public Visibility getVisibility() {
+		return visibility;
 	}
 
 }
diff --git a/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java b/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java
index a407f1fcf3..42ba0d9b01 100644
--- a/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java
+++ b/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java
@@ -110,7 +110,7 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
 			GroupMessage joinMsg, boolean creator) throws DbException {
 		try {
 			db.addGroup(txn, group.getGroup());
-			AuthorId creatorId = joinMsg.getMember().getId();
+			AuthorId creatorId = group.getCreator().getId();
 			BdfDictionary meta = BdfDictionary.of(
 					new BdfEntry(GROUP_KEY_MEMBERS, new BdfList()),
 					new BdfEntry(GROUP_KEY_CREATOR_ID, creatorId),
@@ -134,6 +134,7 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
 		addMember(txn, m.getMessage().getGroupId(), m.getMember(), VISIBLE);
 		setPreviousMsgId(txn, m.getMessage().getGroupId(),
 				m.getMessage().getId());
+		attachJoinMessageAddedEvent(txn, m.getMessage(), meta, true, VISIBLE);
 	}
 
 	@Override
@@ -335,11 +336,22 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
 			for (AuthorId id : authors) {
 				statuses.put(id, identityManager.getAuthorStatus(txn, id));
 			}
-			// Parse the metadata
+			// get current visibilities for join messages
+			Map<Author, Visibility> visibilities = getMembers(txn, g);
+			// parse the metadata
 			for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) {
 				BdfDictionary meta = entry.getValue();
-				headers.add(getGroupMessageHeader(txn, g, entry.getKey(), meta,
-						statuses));
+				if (meta.getLong(KEY_TYPE) == JOIN.getInt()) {
+					Author member = getAuthor(meta);
+					Visibility v = visibilities.get(member);
+					headers.add(
+							getJoinMessageHeader(txn, g, entry.getKey(), meta,
+									statuses, v));
+				} else {
+					headers.add(
+							getGroupMessageHeader(txn, g, entry.getKey(), meta,
+									statuses));
+				}
 			}
 			db.commitTransaction(txn);
 			return headers;
@@ -369,19 +381,17 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
 		}
 		boolean read = meta.getBoolean(KEY_READ);
 
-		if (meta.getLong(KEY_TYPE) == JOIN.getInt()) {
-			return new JoinMessageHeader(g, id, parentId, timestamp, author,
-					status, read);
-		}
 		return new GroupMessageHeader(g, id, parentId, timestamp, author,
 				status, read);
 	}
 
-	private GroupMessageHeader getGroupMessageHeader(Transaction txn, GroupId g,
-			MessageId id, BdfDictionary meta)
-			throws DbException, FormatException {
-		return getGroupMessageHeader(txn, g, id, meta,
-				Collections.<AuthorId, Status>emptyMap());
+	private JoinMessageHeader getJoinMessageHeader(Transaction txn, GroupId g,
+			MessageId id, BdfDictionary meta, Map<AuthorId, Status> statuses,
+			Visibility v) throws DbException, FormatException {
+
+		GroupMessageHeader header =
+				getGroupMessageHeader(txn, g, id, meta, statuses);
+		return new JoinMessageHeader(header, v);
 	}
 
 	@Override
@@ -494,7 +504,7 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
 		addMember(txn, m.getGroupId(), member, v);
 		// track message and broadcast event
 		trackIncomingMessage(txn, m);
-		attachGroupMessageAddedEvent(txn, m, meta, false);
+		attachJoinMessageAddedEvent(txn, m, meta, false, v);
 	}
 
 	private void handleGroupMessage(Transaction txn, Message m,
@@ -538,7 +548,18 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
 			BdfDictionary meta, boolean local)
 			throws DbException, FormatException {
 		GroupMessageHeader h =
-				getGroupMessageHeader(txn, m.getGroupId(), m.getId(), meta);
+				getGroupMessageHeader(txn, m.getGroupId(), m.getId(), meta,
+						Collections.<AuthorId, Status>emptyMap());
+		Event e = new GroupMessageAddedEvent(m.getGroupId(), h, local);
+		txn.attach(e);
+	}
+
+	private void attachJoinMessageAddedEvent(Transaction txn, Message m,
+			BdfDictionary meta, boolean local, Visibility v)
+			throws DbException, FormatException {
+		JoinMessageHeader h =
+				getJoinMessageHeader(txn, m.getGroupId(), m.getId(), meta,
+						Collections.<AuthorId, Status>emptyMap(), v);
 		Event e = new GroupMessageAddedEvent(m.getGroupId(), h, local);
 		txn.attach(e);
 	}
-- 
GitLab