Merge pull request #1229 from Bilb/fix-open-groups-ui

* fix sync of closed groups
* fix showing of contacts and closed groups after sync
* create closed group: only show direct conversations 
* handle message sending events for open groups
This commit is contained in:
Audric Ackermann 2020-07-09 17:23:51 +10:00 committed by GitHub
commit d92bf6febf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 112 additions and 44 deletions

View file

@ -1359,6 +1359,7 @@
attachments: uploads.attachments,
preview: uploads.preview,
quote: uploads.quote,
identifier: id,
};
const openGroupMessage = new libsession.Messages.Outgoing.OpenGroupMessage(
openGroupParams

View file

@ -1209,15 +1209,37 @@
return errors[0][0];
},
/**
* This function is called by inbox_view.js when a message was successfully sent for one device.
* So it might be called several times for the same message
*/
async handleMessageSentSuccess(sentMessage) {
const sentTo = this.get('sent_to') || [];
let sentTo = this.get('sent_to') || [];
const isOurDevice = await window.libsession.Protocols.MultiDeviceProtocol.isOurDevice(
sentMessage.device
);
const isOpenGroupMessage =
sentMessage.group &&
sentMessage.group instanceof libsession.Types.OpenGroup;
// We trigger a sync message only when the message is not to one of our devices, AND
// the message is not for an open group (there is no sync for opengroups, each device pulls all messages), AND
// if we did not sync or trigger a sync message for this specific message already
const shouldTriggerSyncMessage =
!isOurDevice &&
!isOpenGroupMessage &&
!this.get('synced') &&
!this.get('sentSync');
// A message is synced if we triggered a sync message (sentSync)
// and the current message was sent to our device (so a sync message)
const shouldMarkMessageAsSynced =
isOurDevice && !isOpenGroupMessage && this.get('sentSync');
// Handle the sync logic here
if (!isOurDevice && !this.get('synced') && !this.get('sentSync')) {
if (shouldTriggerSyncMessage) {
const contentDecoded = textsecure.protobuf.Content.decode(
sentMessage.plainTextBuffer
);
@ -1225,14 +1247,18 @@
if (dataMessage) {
this.sendSyncMessage(dataMessage);
}
} else if (isOurDevice && this.get('sentSync')) {
} else if (shouldMarkMessageAsSynced) {
this.set({ synced: true });
}
if (!isOpenGroupMessage) {
const primaryPubKey = await libsession.Protocols.MultiDeviceProtocol.getPrimaryDevice(
sentMessage.device
);
sentTo = _.union(sentTo, [primaryPubKey.key]);
}
this.set({
sent_to: _.union(sentTo, [primaryPubKey.key]),
sent_to: sentTo,
sent: true,
expirationStartTimestamp: Date.now(),
// unidentifiedDeliveries: result.unidentifiedDeliveries,

View file

@ -15,7 +15,12 @@
const convos = window.getConversations().models;
this.contacts = convos.filter(
d => !!d && !d.isBlocked() && d.isPrivate() && !d.isMe()
d =>
!!d &&
!d.isBlocked() &&
d.isPrivate() &&
!d.isMe() &&
!!d.get('active_at')
);
if (!convo.isPublic()) {
const members = convo.get('members') || [];

View file

@ -55,5 +55,7 @@ GroupBuffer.prototype.constructor = GroupBuffer;
const ContactBuffer = function Constructor(arrayBuffer) {
ProtoParser.call(this, arrayBuffer, textsecure.protobuf.ContactDetails);
};
window.GroupBuffer = GroupBuffer;
ContactBuffer.prototype = Object.create(ProtoParser.prototype);
ContactBuffer.prototype.constructor = ContactBuffer;

View file

@ -98,6 +98,7 @@ export class DevicePairingDialog extends React.Component<Props, State> {
text={window.i18n('ok')}
onClick={this.validateSecondaryDevice}
disabled={!deviceAlias}
buttonColor={SessionButtonColor.Green}
/>
</div>
<SessionSpinner loading={this.state.loading} />

View file

@ -31,7 +31,9 @@ export class InviteContactsDialog extends React.Component<Props, State> {
contacts = contacts.map(d => {
const lokiProfile = d.getLokiProfile();
const name = lokiProfile ? lokiProfile.displayName : 'Anonymous';
const name = lokiProfile
? lokiProfile.displayName
: window.i18n('anonymous');
// TODO: should take existing members into account
const existingMember = false;

View file

@ -456,7 +456,7 @@ export class LeftPaneMessageSection extends React.Component<Props, State> {
if (!OpenGroup.validate(serverUrl)) {
window.pushToast({
title: window.i18n('noServerURL'),
id: 'connectToServerFail',
id: 'connectToServer',
type: 'error',
});
@ -480,7 +480,7 @@ export class LeftPaneMessageSection extends React.Component<Props, State> {
if (await OpenGroup.serverExists(serverUrl)) {
window.pushToast({
title: window.i18n('connectingToServer'),
id: 'connectToServerSuccess',
id: 'connectToServer',
type: 'success',
});
@ -488,9 +488,10 @@ export class LeftPaneMessageSection extends React.Component<Props, State> {
}
});
} catch (e) {
window.console.error('Failed to connect to server:', e);
window.pushToast({
title: window.i18n('connectToServerFail'),
id: 'connectToServerFail',
id: 'connectToServer',
type: 'error',
});
} finally {

View file

@ -66,18 +66,34 @@ export class SessionClosableOverlay extends React.Component<Props, State> {
}
public getContacts() {
const { overlayMode } = this.props;
const contactsList = this.props.contacts ?? [];
// Depending on the rendered overlay type we have to filter the contact list.
let filteredContactsList = contactsList;
const isClosedGroupView =
overlayMode === SessionClosableOverlayType.ClosedGroup;
if (isClosedGroupView) {
filteredContactsList = filteredContactsList.filter(
c => c.type === 'direct'
);
}
return contactsList.map((d: any) => {
const name = d.name ?? window.i18n('anonymous');
return filteredContactsList.map((d: any) => {
// TODO: should take existing members into account
const existingMember = false;
// if it has a profilename, use it and the shortened pubkey will be added automatically
// if no profile name, Anonymous and the shortened pubkey will be added automatically
let title;
if (d.profileName) {
title = `${d.profileName}`;
} else {
title = `${window.i18n('anonymous')}`;
}
return {
id: d.id,
authorPhoneNumber: d.id,
authorProfileName: name,
authorProfileName: title,
selected: false,
authorName: name,
authorColor: d.color,

View file

@ -599,7 +599,27 @@ export async function handleMessageEvent(event: MessageEvent): Promise<void> {
sendDeliveryReceipt(source, data.timestamp);
}
await window.ConversationController.getOrCreateAndWait(id, type);
// Conversation Id is:
// - primarySource if it is an incoming DM message,
// - destination if it is an outgoing message,
// - group.id if it is a group message
let conversationId = id;
if (isGroupMessage) {
/* handle one part of the group logic here:
handle requesting info of a new group,
dropping an admin only update from a non admin, ...
*/
conversationId = message.group.id;
}
if (!conversationId) {
window.console.warn(
'Invalid conversation id for incoming message',
conversationId
);
}
await window.ConversationController.getOrCreateAndWait(conversationId, type);
// =========== Process flags =============
@ -613,20 +633,12 @@ export async function handleMessageEvent(event: MessageEvent): Promise<void> {
// =========================================
// Conversation Id is:
// - primarySource if it is an incoming DM message,
// - destination if it is an outgoing message,
// - group.id if it is a group message
let conversationId = id;
const primarySource = await MultiDeviceProtocol.getPrimaryDevice(source);
if (isGroupMessage) {
/* handle one part of the group logic here:
handle requesting info of a new group,
dropping an admin only update from a non admin, ...
*/
conversationId = message.group.id;
const shouldReturn = await preprocessGroupMessage(
source,
message.group,

View file

@ -334,6 +334,7 @@ async function onContactReceived(details: any) {
// activeAt is null, then this contact has been purposefully hidden.
if (activeAt !== null) {
activeAt = activeAt || Date.now();
conversation.set('active_at', activeAt);
}
const ourPrimaryKey = window.storage.get('primaryDevicePubKey');
if (ourPrimaryKey) {
@ -375,7 +376,6 @@ async function onContactReceived(details: any) {
conversation.set({
// name: details.name,
color: details.color,
active_at: activeAt,
});
await conversation.setLokiProfile({ displayName: details.name });
@ -427,6 +427,7 @@ async function onContactReceived(details: any) {
verifiedEvent.viaContactSync = true;
await onVerified(verifiedEvent);
}
await conversation.trigger('change');
} catch (error) {
window.log.error('onContactReceived error:', Errors.toLogFormat(error));
}

View file

@ -98,7 +98,9 @@ export class MultiDeviceProtocol {
primaryDevicePubKey,
secondaryDevicePubKey,
requestSignature: StringUtils.encode(requestSignature, 'base64'),
grantSignature: StringUtils.encode(grantSignature, 'base64'),
grantSignature: grantSignature
? StringUtils.encode(grantSignature, 'base64')
: undefined,
})
);

View file

@ -152,17 +152,14 @@ export class OpenGroup {
if (!OpenGroup.validate(server)) {
return;
}
const rawServerURL = server
.replace(/^https?:\/\//i, '')
.replace(/[/\\]+$/i, '');
const channelId = 1;
const conversationId = `publicChat:${channelId}@${rawServerURL}`;
const prefixedServer = this.prefixify(server);
const serverInfo = (await window.lokiPublicChatAPI.findOrCreateServer(
prefixedServer
)) as any;
if (!serverInfo?.channels?.length) {
return;
}
return serverInfo.channels[0].conversation;
// Quickly peak to make sure we don't already have it
return window.ConversationController.get(conversationId);
}
/**

View file

@ -50,7 +50,8 @@ export async function getSyncContacts(): Promise<Array<any> | undefined> {
c.isPrivate() &&
!c.isOurLocalDevice() &&
!c.isBlocked() &&
!c.attributes.secondaryStatus
!c.attributes.secondaryStatus &&
!!c.get('active_at')
) || [];
const secondaryContactsPartial = conversations.filter(
@ -58,7 +59,8 @@ export async function getSyncContacts(): Promise<Array<any> | undefined> {
c.isPrivate() &&
!c.isOurLocalDevice() &&
!c.isBlocked() &&
c.attributes.secondaryStatus
c.attributes.secondaryStatus &&
!!c.get('active_at')
);
const secondaryContactsPromise = secondaryContactsPartial.map(async c =>

View file

@ -139,7 +139,7 @@ export const _getLeftPaneLists = (
// Remove all invalid conversations and conversatons of devices associated
// with cancelled attempted links
if (!conversation.isPublic && !conversation.timestamp) {
if (!conversation.isPublic && !conversation.activeAt) {
continue;
}
@ -151,10 +151,6 @@ export const _getLeftPaneLists = (
unreadCount += conversation.unreadCount;
}
if (!conversation.isPublic && !conversation.activeAt) {
continue;
}
if (conversation.isArchived) {
archivedConversations.push(conversation);
} else {

View file

@ -111,4 +111,8 @@ export class MockConversation {
return this.isPrimary ? this.id : generateFakePubKey().key;
}
public get(obj: string) {
return (this.attributes as any)[obj];
}
}