Merge branch '877-save-invitation-outcome-to-invitation-message-and-make-available-to-ui' into 'master'

Store invitation outcome in metadata and make it available to the UI

This MR is based on !479 and should only be merged after that one has been merged as well.

It stores the invitation outcome in the message metadata  and includes it in the `canBeOpened()` calculation for private groups and sharables.

Closes #877

See merge request !480
This commit is contained in:
akwizgran
2017-01-06 16:06:19 +00:00
24 changed files with 122 additions and 39 deletions

View File

@@ -174,6 +174,17 @@ abstract class AbstractProtocolEngine<S extends Session>
markMessageAvailableToAnswer(txn, m, false); markMessageAvailableToAnswer(txn, m, false);
} }
void markInviteAccepted(Transaction txn, MessageId m, boolean accepted)
throws DbException {
BdfDictionary meta = new BdfDictionary();
messageEncoder.setInvitationAccepted(meta, accepted);
try {
clientHelper.mergeMessageMetadata(txn, m, meta);
} catch (FormatException e) {
throw new AssertionError(e);
}
}
void subscribeToPrivateGroup(Transaction txn, MessageId inviteId) void subscribeToPrivateGroup(Transaction txn, MessageId inviteId)
throws DbException, FormatException { throws DbException, FormatException {
InviteMessage invite = messageParser.getInviteMessage(txn, inviteId); InviteMessage invite = messageParser.getInviteMessage(txn, inviteId);
@@ -199,8 +210,9 @@ abstract class AbstractProtocolEngine<S extends Session>
private void sendMessage(Transaction txn, Message m, MessageType type, private void sendMessage(Transaction txn, Message m, MessageType type,
GroupId privateGroupId, boolean visibleInConversation) GroupId privateGroupId, boolean visibleInConversation)
throws DbException { throws DbException {
BdfDictionary meta = messageEncoder.encodeMetadata(type, privateGroupId, BdfDictionary meta = messageEncoder
m.getTimestamp(), true, true, visibleInConversation, false); .encodeMetadata(type, privateGroupId, m.getTimestamp(), true,
true, visibleInConversation, false, false);
try { try {
clientHelper.addLocalMessage(txn, m, meta, true); clientHelper.addLocalMessage(txn, m, meta, true);
} catch (FormatException e) { } catch (FormatException e) {

View File

@@ -12,6 +12,7 @@ interface GroupInvitationConstants {
String MSG_KEY_LOCAL = "local"; String MSG_KEY_LOCAL = "local";
String MSG_KEY_VISIBLE_IN_UI = "visibleInUi"; String MSG_KEY_VISIBLE_IN_UI = "visibleInUi";
String MSG_KEY_AVAILABLE_TO_ANSWER = "availableToAnswer"; String MSG_KEY_AVAILABLE_TO_ANSWER = "availableToAnswer";
String MSG_KEY_INVITATION_ACCEPTED = "invitationAccepted";
// Session keys // Session keys
String SESSION_KEY_SESSION_ID = "sessionId"; String SESSION_KEY_SESSION_ID = "sessionId";

View File

@@ -405,7 +405,9 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
PrivateGroup pg = privateGroupFactory PrivateGroup pg = privateGroupFactory
.createPrivateGroup(invite.getGroupName(), invite.getCreator(), .createPrivateGroup(invite.getGroupName(), invite.getCreator(),
invite.getSalt()); invite.getSalt());
boolean canBeOpened = db.containsGroup(txn, invite.getPrivateGroupId()); // Find out whether the private group can be opened
boolean canBeOpened = meta.wasAccepted() &&
db.containsGroup(txn, invite.getPrivateGroupId());
return new GroupInvitationRequest(m, contactGroupId, return new GroupInvitationRequest(m, contactGroupId,
meta.getTimestamp(), meta.isLocal(), status.isSent(), meta.getTimestamp(), meta.isLocal(), status.isSent(),
status.isSeen(), meta.isRead(), sessionId, pg, c, status.isSeen(), meta.isRead(), sessionId, pg, c,

View File

@@ -112,7 +112,7 @@ class GroupInvitationValidator extends BdfMessageValidator {
// Create the metadata // Create the metadata
BdfDictionary meta = messageEncoder.encodeMetadata(INVITE, BdfDictionary meta = messageEncoder.encodeMetadata(INVITE,
privateGroup.getId(), m.getTimestamp(), false, false, false, privateGroup.getId(), m.getTimestamp(), false, false, false,
false); false, false);
return new BdfMessageContext(meta); return new BdfMessageContext(meta);
} }
@@ -125,7 +125,7 @@ class GroupInvitationValidator extends BdfMessageValidator {
checkLength(previousMessageId, UniqueId.LENGTH); checkLength(previousMessageId, UniqueId.LENGTH);
BdfDictionary meta = messageEncoder.encodeMetadata(JOIN, BdfDictionary meta = messageEncoder.encodeMetadata(JOIN,
new GroupId(privateGroupId), m.getTimestamp(), false, false, new GroupId(privateGroupId), m.getTimestamp(), false, false,
false, false); false, false, false);
if (previousMessageId == null) { if (previousMessageId == null) {
return new BdfMessageContext(meta); return new BdfMessageContext(meta);
} else { } else {
@@ -144,7 +144,7 @@ class GroupInvitationValidator extends BdfMessageValidator {
checkLength(previousMessageId, UniqueId.LENGTH); checkLength(previousMessageId, UniqueId.LENGTH);
BdfDictionary meta = messageEncoder.encodeMetadata(LEAVE, BdfDictionary meta = messageEncoder.encodeMetadata(LEAVE,
new GroupId(privateGroupId), m.getTimestamp(), false, false, new GroupId(privateGroupId), m.getTimestamp(), false, false,
false, false); false, false, false);
if (previousMessageId == null) { if (previousMessageId == null) {
return new BdfMessageContext(meta); return new BdfMessageContext(meta);
} else { } else {
@@ -161,7 +161,7 @@ class GroupInvitationValidator extends BdfMessageValidator {
checkLength(privateGroupId, UniqueId.LENGTH); checkLength(privateGroupId, UniqueId.LENGTH);
BdfDictionary meta = messageEncoder.encodeMetadata(ABORT, BdfDictionary meta = messageEncoder.encodeMetadata(ABORT,
new GroupId(privateGroupId), m.getTimestamp(), false, false, new GroupId(privateGroupId), m.getTimestamp(), false, false,
false, false); false, false, false);
return new BdfMessageContext(meta); return new BdfMessageContext(meta);
} }
} }

View File

@@ -172,6 +172,8 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> {
MessageId inviteId = s.getLastRemoteMessageId(); MessageId inviteId = s.getLastRemoteMessageId();
if (inviteId == null) throw new IllegalStateException(); if (inviteId == null) throw new IllegalStateException();
markMessageAvailableToAnswer(txn, inviteId, false); markMessageAvailableToAnswer(txn, inviteId, false);
// Record the response
markInviteAccepted(txn, inviteId, true);
// Send a JOIN message // Send a JOIN message
Message sent = sendJoinMessage(txn, s, true); Message sent = sendJoinMessage(txn, s, true);
// Track the message // Track the message

View File

@@ -14,12 +14,14 @@ interface MessageEncoder {
BdfDictionary encodeMetadata(MessageType type, GroupId privateGroupId, BdfDictionary encodeMetadata(MessageType type, GroupId privateGroupId,
long timestamp, boolean local, boolean read, boolean visible, long timestamp, boolean local, boolean read, boolean visible,
boolean available); boolean available, boolean accepted);
void setVisibleInUi(BdfDictionary meta, boolean visible); void setVisibleInUi(BdfDictionary meta, boolean visible);
void setAvailableToAnswer(BdfDictionary meta, boolean available); void setAvailableToAnswer(BdfDictionary meta, boolean available);
void setInvitationAccepted(BdfDictionary meta, boolean accepted);
Message encodeInviteMessage(GroupId contactGroupId, GroupId privateGroupId, Message encodeInviteMessage(GroupId contactGroupId, GroupId privateGroupId,
long timestamp, String groupName, Author creator, byte[] salt, long timestamp, String groupName, Author creator, byte[] salt,
@Nullable String message, byte[] signature); @Nullable String message, byte[] signature);

View File

@@ -17,6 +17,7 @@ import javax.inject.Inject;
import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ;
import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_AVAILABLE_TO_ANSWER; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_AVAILABLE_TO_ANSWER;
import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_INVITATION_ACCEPTED;
import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_LOCAL; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_LOCAL;
import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_MESSAGE_TYPE; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_MESSAGE_TYPE;
import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_PRIVATE_GROUP_ID; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_PRIVATE_GROUP_ID;
@@ -44,7 +45,7 @@ class MessageEncoderImpl implements MessageEncoder {
@Override @Override
public BdfDictionary encodeMetadata(MessageType type, public BdfDictionary encodeMetadata(MessageType type,
GroupId privateGroupId, long timestamp, boolean local, boolean read, GroupId privateGroupId, long timestamp, boolean local, boolean read,
boolean visible, boolean available) { boolean visible, boolean available, boolean accepted) {
BdfDictionary meta = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();
meta.put(MSG_KEY_MESSAGE_TYPE, type.getValue()); meta.put(MSG_KEY_MESSAGE_TYPE, type.getValue());
meta.put(MSG_KEY_PRIVATE_GROUP_ID, privateGroupId); meta.put(MSG_KEY_PRIVATE_GROUP_ID, privateGroupId);
@@ -53,6 +54,7 @@ class MessageEncoderImpl implements MessageEncoder {
meta.put(MSG_KEY_READ, read); meta.put(MSG_KEY_READ, read);
meta.put(MSG_KEY_VISIBLE_IN_UI, visible); meta.put(MSG_KEY_VISIBLE_IN_UI, visible);
meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, available); meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, available);
meta.put(MSG_KEY_INVITATION_ACCEPTED, accepted);
return meta; return meta;
} }
@@ -66,6 +68,11 @@ class MessageEncoderImpl implements MessageEncoder {
meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, available); meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, available);
} }
@Override
public void setInvitationAccepted(BdfDictionary meta, boolean accepted) {
meta.put(MSG_KEY_INVITATION_ACCEPTED, accepted);
}
@Override @Override
public Message encodeInviteMessage(GroupId contactGroupId, public Message encodeInviteMessage(GroupId contactGroupId,
GroupId privateGroupId, long timestamp, String groupName, GroupId privateGroupId, long timestamp, String groupName,

View File

@@ -12,11 +12,11 @@ class MessageMetadata {
private final MessageType type; private final MessageType type;
private final GroupId privateGroupId; private final GroupId privateGroupId;
private final long timestamp; private final long timestamp;
private final boolean local, read, visible, available; private final boolean local, read, visible, available, accepted;
MessageMetadata(MessageType type, GroupId privateGroupId, MessageMetadata(MessageType type, GroupId privateGroupId,
long timestamp, boolean local, boolean read, boolean visible, long timestamp, boolean local, boolean read, boolean visible,
boolean available) { boolean available, boolean accepted) {
this.privateGroupId = privateGroupId; this.privateGroupId = privateGroupId;
this.type = type; this.type = type;
this.timestamp = timestamp; this.timestamp = timestamp;
@@ -24,6 +24,7 @@ class MessageMetadata {
this.read = read; this.read = read;
this.visible = visible; this.visible = visible;
this.available = available; this.available = available;
this.accepted = accepted;
} }
MessageType getMessageType() { MessageType getMessageType() {
@@ -53,4 +54,14 @@ class MessageMetadata {
boolean isAvailableToAnswer() { boolean isAvailableToAnswer() {
return available; return available;
} }
/**
* Returns true if the invitation was accepted.
*
* Only applies to messages of type INVITE.
*/
public boolean wasAccepted() {
return accepted;
}
} }

View File

@@ -21,6 +21,7 @@ import javax.inject.Inject;
import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ;
import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_AVAILABLE_TO_ANSWER; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_AVAILABLE_TO_ANSWER;
import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_INVITATION_ACCEPTED;
import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_LOCAL; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_LOCAL;
import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_MESSAGE_TYPE; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_MESSAGE_TYPE;
import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_PRIVATE_GROUP_ID; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.MSG_KEY_PRIVATE_GROUP_ID;
@@ -79,8 +80,9 @@ class MessageParserImpl implements MessageParser {
boolean read = meta.getBoolean(MSG_KEY_READ, false); boolean read = meta.getBoolean(MSG_KEY_READ, false);
boolean visible = meta.getBoolean(MSG_KEY_VISIBLE_IN_UI, false); boolean visible = meta.getBoolean(MSG_KEY_VISIBLE_IN_UI, false);
boolean available = meta.getBoolean(MSG_KEY_AVAILABLE_TO_ANSWER, false); boolean available = meta.getBoolean(MSG_KEY_AVAILABLE_TO_ANSWER, false);
boolean accepted = meta.getBoolean(MSG_KEY_INVITATION_ACCEPTED, false);
return new MessageMetadata(type, privateGroupId, timestamp, local, read, return new MessageMetadata(type, privateGroupId, timestamp, local, read,
visible, available); visible, available, accepted);
} }
@Override @Override

View File

@@ -14,12 +14,14 @@ interface MessageEncoder {
BdfDictionary encodeMetadata(MessageType type, GroupId shareableId, BdfDictionary encodeMetadata(MessageType type, GroupId shareableId,
long timestamp, boolean local, boolean read, boolean visible, long timestamp, boolean local, boolean read, boolean visible,
boolean available); boolean available, boolean accepted);
void setVisibleInUi(BdfDictionary meta, boolean visible); void setVisibleInUi(BdfDictionary meta, boolean visible);
void setAvailableToAnswer(BdfDictionary meta, boolean available); void setAvailableToAnswer(BdfDictionary meta, boolean available);
void setInvitationAccepted(BdfDictionary meta, boolean accepted);
Message encodeInviteMessage(GroupId contactGroupId, long timestamp, Message encodeInviteMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, BdfList descriptor, @Nullable MessageId previousMessageId, BdfList descriptor,
@Nullable String message); @Nullable String message);

View File

@@ -20,10 +20,11 @@ import static org.briarproject.briar.sharing.MessageType.DECLINE;
import static org.briarproject.briar.sharing.MessageType.INVITE; import static org.briarproject.briar.sharing.MessageType.INVITE;
import static org.briarproject.briar.sharing.MessageType.LEAVE; import static org.briarproject.briar.sharing.MessageType.LEAVE;
import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_AVAILABLE_TO_ANSWER; import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_AVAILABLE_TO_ANSWER;
import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_INVITATION_ACCEPTED;
import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_LOCAL; import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_LOCAL;
import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_MESSAGE_TYPE; import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_MESSAGE_TYPE;
import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_SHAREABLE_ID;
import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_READ; import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_READ;
import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_SHAREABLE_ID;
import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_TIMESTAMP; import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_TIMESTAMP;
import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_VISIBLE_IN_UI; import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_VISIBLE_IN_UI;
@@ -44,7 +45,7 @@ class MessageEncoderImpl implements MessageEncoder {
@Override @Override
public BdfDictionary encodeMetadata(MessageType type, public BdfDictionary encodeMetadata(MessageType type,
GroupId shareableId, long timestamp, boolean local, boolean read, GroupId shareableId, long timestamp, boolean local, boolean read,
boolean visible, boolean available) { boolean visible, boolean available, boolean accepted) {
BdfDictionary meta = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();
meta.put(MSG_KEY_MESSAGE_TYPE, type.getValue()); meta.put(MSG_KEY_MESSAGE_TYPE, type.getValue());
meta.put(MSG_KEY_SHAREABLE_ID, shareableId); meta.put(MSG_KEY_SHAREABLE_ID, shareableId);
@@ -53,6 +54,7 @@ class MessageEncoderImpl implements MessageEncoder {
meta.put(MSG_KEY_READ, read); meta.put(MSG_KEY_READ, read);
meta.put(MSG_KEY_VISIBLE_IN_UI, visible); meta.put(MSG_KEY_VISIBLE_IN_UI, visible);
meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, available); meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, available);
meta.put(MSG_KEY_INVITATION_ACCEPTED, accepted);
return meta; return meta;
} }
@@ -66,6 +68,11 @@ class MessageEncoderImpl implements MessageEncoder {
meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, available); meta.put(MSG_KEY_AVAILABLE_TO_ANSWER, available);
} }
@Override
public void setInvitationAccepted(BdfDictionary meta, boolean accepted) {
meta.put(MSG_KEY_INVITATION_ACCEPTED, accepted);
}
@Override @Override
public Message encodeInviteMessage(GroupId contactGroupId, long timestamp, public Message encodeInviteMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, BdfList descriptor, @Nullable MessageId previousMessageId, BdfList descriptor,

View File

@@ -12,10 +12,11 @@ class MessageMetadata {
private final MessageType type; private final MessageType type;
private final GroupId shareableId; private final GroupId shareableId;
private final long timestamp; private final long timestamp;
private final boolean local, read, visible, available; private final boolean local, read, visible, available, accepted;
MessageMetadata(MessageType type, GroupId shareableId, long timestamp, MessageMetadata(MessageType type, GroupId shareableId, long timestamp,
boolean local, boolean read, boolean visible, boolean available) { boolean local, boolean read, boolean visible, boolean available,
boolean accepted) {
this.shareableId = shareableId; this.shareableId = shareableId;
this.type = type; this.type = type;
this.timestamp = timestamp; this.timestamp = timestamp;
@@ -23,6 +24,7 @@ class MessageMetadata {
this.read = read; this.read = read;
this.visible = visible; this.visible = visible;
this.available = available; this.available = available;
this.accepted = accepted;
} }
MessageType getMessageType() { MessageType getMessageType() {
@@ -53,4 +55,13 @@ class MessageMetadata {
return available; return available;
} }
/**
* Returns true if the invitation was accepted.
*
* Only applies to messages of type INVITE.
*/
public boolean wasAccepted() {
return accepted;
}
} }

View File

@@ -20,6 +20,7 @@ import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_AVAILABLE_
import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_LOCAL; import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_LOCAL;
import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_MESSAGE_TYPE; import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_MESSAGE_TYPE;
import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_READ; import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_READ;
import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_INVITATION_ACCEPTED;
import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_SHAREABLE_ID; import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_SHAREABLE_ID;
import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_TIMESTAMP; import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_TIMESTAMP;
import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_VISIBLE_IN_UI; import static org.briarproject.briar.sharing.SharingConstants.MSG_KEY_VISIBLE_IN_UI;
@@ -68,8 +69,9 @@ abstract class MessageParserImpl<S extends Shareable>
boolean read = meta.getBoolean(MSG_KEY_READ, false); boolean read = meta.getBoolean(MSG_KEY_READ, false);
boolean visible = meta.getBoolean(MSG_KEY_VISIBLE_IN_UI, false); boolean visible = meta.getBoolean(MSG_KEY_VISIBLE_IN_UI, false);
boolean available = meta.getBoolean(MSG_KEY_AVAILABLE_TO_ANSWER, false); boolean available = meta.getBoolean(MSG_KEY_AVAILABLE_TO_ANSWER, false);
boolean accepted = meta.getBoolean(MSG_KEY_INVITATION_ACCEPTED, false);
return new MessageMetadata(type, shareableId, timestamp, local, read, return new MessageMetadata(type, shareableId, timestamp, local, read,
visible, available); visible, available, accepted);
} }
@Override @Override

View File

@@ -148,6 +148,8 @@ abstract class ProtocolEngineImpl<S extends Shareable>
MessageId inviteId = s.getLastRemoteMessageId(); MessageId inviteId = s.getLastRemoteMessageId();
if (inviteId == null) throw new IllegalStateException(); if (inviteId == null) throw new IllegalStateException();
markMessageAvailableToAnswer(txn, inviteId, false); markMessageAvailableToAnswer(txn, inviteId, false);
// Mark the invite message as accepted
markInvitationAccepted(txn, inviteId, true);
// Send a ACCEPT message // Send a ACCEPT message
Message sent = sendAcceptMessage(txn, s); Message sent = sendAcceptMessage(txn, s);
// Track the message // Track the message
@@ -568,8 +570,9 @@ abstract class ProtocolEngineImpl<S extends Shareable>
private void sendMessage(Transaction txn, Message m, MessageType type, private void sendMessage(Transaction txn, Message m, MessageType type,
GroupId shareableId, boolean visibleInConversation) GroupId shareableId, boolean visibleInConversation)
throws DbException { throws DbException {
BdfDictionary meta = messageEncoder.encodeMetadata(type, shareableId, BdfDictionary meta = messageEncoder
m.getTimestamp(), true, true, visibleInConversation, false); .encodeMetadata(type, shareableId, m.getTimestamp(), true, true,
visibleInConversation, false, false);
try { try {
clientHelper.addLocalMessage(txn, m, meta, true); clientHelper.addLocalMessage(txn, m, meta, true);
} catch (FormatException e) { } catch (FormatException e) {
@@ -599,6 +602,17 @@ abstract class ProtocolEngineImpl<S extends Shareable>
} }
} }
private void markInvitationAccepted(Transaction txn, MessageId m,
boolean accepted) throws DbException {
BdfDictionary meta = new BdfDictionary();
messageEncoder.setInvitationAccepted(meta, accepted);
try {
clientHelper.mergeMessageMetadata(txn, m, meta);
} catch (FormatException e) {
throw new AssertionError(e);
}
}
private void setShareableVisibility(Transaction txn, Session session, private void setShareableVisibility(Transaction txn, Session session,
Visibility v) throws DbException, FormatException { Visibility v) throws DbException, FormatException {
ContactId contactId = getContactId(txn, session.getContactGroupId()); ContactId contactId = getContactId(txn, session.getContactGroupId());

View File

@@ -15,6 +15,7 @@ interface SharingConstants {
String MSG_KEY_LOCAL = "local"; String MSG_KEY_LOCAL = "local";
String MSG_KEY_VISIBLE_IN_UI = "visibleInUi"; String MSG_KEY_VISIBLE_IN_UI = "visibleInUi";
String MSG_KEY_AVAILABLE_TO_ANSWER = "availableToAnswer"; String MSG_KEY_AVAILABLE_TO_ANSWER = "availableToAnswer";
String MSG_KEY_INVITATION_ACCEPTED = "invitationAccepted";
// Session keys // Session keys
String SESSION_KEY_STATE = "state"; String SESSION_KEY_STATE = "state";

View File

@@ -319,7 +319,9 @@ abstract class SharingManagerImpl<S extends Shareable>
MessageStatus status) throws DbException, FormatException { MessageStatus status) throws DbException, FormatException {
// Look up the invite message to get the details of the private group // Look up the invite message to get the details of the private group
InviteMessage<S> invite = messageParser.getInviteMessage(txn, m); InviteMessage<S> invite = messageParser.getInviteMessage(txn, m);
boolean canBeOpened = db.containsGroup(txn, invite.getShareableId()); // Find out whether the shareable can be opened
boolean canBeOpened = meta.wasAccepted() &&
db.containsGroup(txn, invite.getShareableId());
return invitationFactory return invitationFactory
.createInvitationRequest(meta.isLocal(), status.isSent(), .createInvitationRequest(meta.isLocal(), status.isSent(),
status.isSeen(), meta.isRead(), invite, c, status.isSeen(), meta.isRead(), invite, c,

View File

@@ -65,7 +65,7 @@ abstract class SharingValidator extends BdfMessageValidator {
BdfDictionary meta = messageEncoder BdfDictionary meta = messageEncoder
.encodeMetadata(INVITE, shareableId, m.getTimestamp(), false, .encodeMetadata(INVITE, shareableId, m.getTimestamp(), false,
false, false, false); false, false, false, false);
if (previousMessageId == null) { if (previousMessageId == null) {
return new BdfMessageContext(meta); return new BdfMessageContext(meta);
} else { } else {
@@ -88,7 +88,7 @@ abstract class SharingValidator extends BdfMessageValidator {
BdfDictionary meta = messageEncoder BdfDictionary meta = messageEncoder
.encodeMetadata(type, new GroupId(shareableId), .encodeMetadata(type, new GroupId(shareableId),
m.getTimestamp(), false, false, false, false); m.getTimestamp(), false, false, false, false, false);
if (previousMessageId == null) { if (previousMessageId == null) {
return new BdfMessageContext(meta); return new BdfMessageContext(meta);
} else { } else {

View File

@@ -169,7 +169,7 @@ public abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
final boolean visible) throws Exception { final boolean visible) throws Exception {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(messageEncoder).encodeMetadata(type, privateGroupId, oneOf(messageEncoder).encodeMetadata(type, privateGroupId,
message.getTimestamp(), true, true, visible, false); message.getTimestamp(), true, true, visible, false, false);
will(returnValue(meta)); will(returnValue(meta));
oneOf(clientHelper).addLocalMessage(txn, message, meta, true); oneOf(clientHelper).addLocalMessage(txn, message, meta, true);
}}); }});

View File

@@ -104,6 +104,7 @@ public class GroupInvitationIntegrationTest
assertEquals(privateGroup0.getName(), request.getShareable().getName()); assertEquals(privateGroup0.getName(), request.getShareable().getName());
assertFalse(request.isLocal()); assertFalse(request.isLocal());
assertFalse(request.isRead()); assertFalse(request.isRead());
assertFalse(request.canBeOpened());
} }
@Test @Test
@@ -175,6 +176,8 @@ public class GroupInvitationIntegrationTest
foundResponse = true; foundResponse = true;
InvitationResponse response = (GroupInvitationResponse) m; InvitationResponse response = (GroupInvitationResponse) m;
assertTrue(response.wasAccepted()); assertTrue(response.wasAccepted());
} else {
assertTrue(((GroupInvitationRequest) m).canBeOpened());
} }
} }
assertTrue(foundResponse); assertTrue(foundResponse);

View File

@@ -638,10 +638,10 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
final long time1 = 1L, time2 = 2L; final long time1 = 1L, time2 = 2L;
final MessageMetadata messageMetadata1 = final MessageMetadata messageMetadata1 =
new MessageMetadata(INVITE, privateGroup.getId(), time1, true, new MessageMetadata(INVITE, privateGroup.getId(), time1, true,
true, true, false); true, true, false, true);
final MessageMetadata messageMetadata2 = final MessageMetadata messageMetadata2 =
new MessageMetadata(JOIN, privateGroup.getId(), time2, true, new MessageMetadata(JOIN, privateGroup.getId(), time2, true,
true, true, true); true, true, true, false);
final InviteMessage invite = final InviteMessage invite =
new InviteMessage(message.getId(), contactGroup.getId(), new InviteMessage(message.getId(), contactGroup.getId(),
privateGroup.getId(), time1, "name", author, privateGroup.getId(), time1, "name", author,

View File

@@ -311,7 +311,7 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
} else { } else {
oneOf(messageEncoder).encodeMetadata(INVITE, oneOf(messageEncoder).encodeMetadata(INVITE,
message.getGroupId(), message.getTimestamp(), false, message.getGroupId(), message.getTimestamp(), false,
false, false, false); false, false, false, false);
will(returnValue(meta)); will(returnValue(meta));
} }
}}); }});
@@ -389,7 +389,7 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(), null); BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(), null);
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(messageEncoder).encodeMetadata(JOIN, message.getGroupId(), oneOf(messageEncoder).encodeMetadata(JOIN, message.getGroupId(),
message.getTimestamp(), false, false, false, false); message.getTimestamp(), false, false, false, false, false);
will(returnValue(meta)); will(returnValue(meta));
}}); }});
BdfMessageContext messageContext = BdfMessageContext messageContext =
@@ -404,7 +404,7 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
previousMessageId); previousMessageId);
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(messageEncoder).encodeMetadata(JOIN, message.getGroupId(), oneOf(messageEncoder).encodeMetadata(JOIN, message.getGroupId(),
message.getTimestamp(), false, false, false, false); message.getTimestamp(), false, false, false, false, false);
will(returnValue(meta)); will(returnValue(meta));
}}); }});
BdfMessageContext messageContext = BdfMessageContext messageContext =
@@ -487,7 +487,7 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(), null); BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(), null);
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(messageEncoder).encodeMetadata(LEAVE, message.getGroupId(), oneOf(messageEncoder).encodeMetadata(LEAVE, message.getGroupId(),
message.getTimestamp(), false, false, false, false); message.getTimestamp(), false, false, false, false, false);
will(returnValue(meta)); will(returnValue(meta));
}}); }});
BdfMessageContext messageContext = BdfMessageContext messageContext =
@@ -500,7 +500,7 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
public void testAcceptsValidLeaveMessage() throws Exception { public void testAcceptsValidLeaveMessage() throws Exception {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(messageEncoder).encodeMetadata(LEAVE, message.getGroupId(), oneOf(messageEncoder).encodeMetadata(LEAVE, message.getGroupId(),
message.getTimestamp(), false, false, false, false); message.getTimestamp(), false, false, false, false, false);
will(returnValue(meta)); will(returnValue(meta));
}}); }});
BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(), BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(),
@@ -557,7 +557,7 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase {
public void testAcceptsValidAbortMessage() throws Exception { public void testAcceptsValidAbortMessage() throws Exception {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(messageEncoder).encodeMetadata(ABORT, message.getGroupId(), oneOf(messageEncoder).encodeMetadata(ABORT, message.getGroupId(),
message.getTimestamp(), false, false, false, false); message.getTimestamp(), false, false, false, false, false);
will(returnValue(meta)); will(returnValue(meta));
}}); }});
BdfList body = BdfList.of(ABORT.getValue(), privateGroup.getId()); BdfList body = BdfList.of(ABORT.getValue(), privateGroup.getId());

View File

@@ -3,11 +3,9 @@ package org.briarproject.briar.privategroup.invitation;
import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfEntry; import org.briarproject.bramble.api.data.BdfEntry;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.privategroup.GroupMessage; import org.briarproject.briar.api.privategroup.GroupMessage;
@@ -132,15 +130,17 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest {
final JoinMessage properJoinMessage = final JoinMessage properJoinMessage =
new JoinMessage(messageId, contactGroupId, privateGroupId, new JoinMessage(messageId, contactGroupId, privateGroupId,
messageTimestamp, lastRemoteMessageId); messageTimestamp, lastRemoteMessageId);
final Message inviteMsg =
new Message(lastRemoteMessageId, contactGroupId, 1337L,
getRandomBytes(42));
final BdfList inviteList = BdfList.of("inviteMessage");
final long timestamp = 0L; final long timestamp = 0L;
final GroupMessage joinGroupMessage = final GroupMessage joinGroupMessage =
new GroupMessage(message, null, localAuthor); new GroupMessage(message, null, localAuthor);
final BdfDictionary meta = new BdfDictionary();
expectMarkMessageAvailableToAnswer(lastRemoteMessageId, false); expectMarkMessageAvailableToAnswer(lastRemoteMessageId, false);
context.checking(new Expectations() {{
oneOf(messageEncoder).setInvitationAccepted(meta, true);
oneOf(clientHelper)
.mergeMessageMetadata(txn, lastRemoteMessageId, meta);
}});
expectSendJoinMessage(properJoinMessage, true); expectSendJoinMessage(properJoinMessage, true);
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(messageTracker).trackOutgoingMessage(txn, message); oneOf(messageTracker).trackOutgoingMessage(txn, message);

View File

@@ -136,6 +136,7 @@ public class ForumSharingIntegrationTest
assertEquals(forum0.getName(), invitation.getForumName()); assertEquals(forum0.getName(), invitation.getForumName());
assertEquals(contactId1From0, invitation.getContactId()); assertEquals(contactId1From0, invitation.getContactId());
assertEquals("Hi!", invitation.getMessage()); assertEquals("Hi!", invitation.getMessage());
assertTrue(invitation.canBeOpened());
} else { } else {
ForumInvitationResponse response = ForumInvitationResponse response =
(ForumInvitationResponse) m; (ForumInvitationResponse) m;
@@ -195,6 +196,7 @@ public class ForumSharingIntegrationTest
assertEquals(forum0.getName(), invitation.getForumName()); assertEquals(forum0.getName(), invitation.getForumName());
assertEquals(contactId1From0, invitation.getContactId()); assertEquals(contactId1From0, invitation.getContactId());
assertEquals(null, invitation.getMessage()); assertEquals(null, invitation.getMessage());
assertFalse(invitation.canBeOpened());
} else { } else {
ForumInvitationResponse response = ForumInvitationResponse response =
(ForumInvitationResponse) m; (ForumInvitationResponse) m;

View File

@@ -147,7 +147,7 @@ public abstract class SharingValidatorTest extends ValidatorTestCase {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(messageEncoder) oneOf(messageEncoder)
.encodeMetadata(type, groupId, timestamp, false, false, .encodeMetadata(type, groupId, timestamp, false, false,
false, false); false, false, false);
will(returnValue(meta)); will(returnValue(meta));
}}); }});
} }