Support for announcement-only groups

This commit is contained in:
Josh Perez 2021-07-20 16:18:35 -04:00 committed by GitHub
parent 863ae9ed83
commit 56d5d283bd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
43 changed files with 1057 additions and 455 deletions

View file

@ -541,6 +541,16 @@ export class ConversationModel extends window.Backbone
);
}
if (
this.get('announcementsOnly') &&
!toRequest.get('capabilities')?.announcementGroup
) {
window.log.warn(
`addPendingApprovalRequest/${idLog}: member needs to upgrade.`
);
return undefined;
}
// We need the user's profileKeyCredential, which requires a roundtrip with the
// server, and most definitely their profileKey. A getProfiles() call will
// ensure that we have as much as we can get with the data we have.
@ -585,6 +595,16 @@ export class ConversationModel extends window.Backbone
);
}
if (
this.get('announcementsOnly') &&
!toRequest.get('capabilities')?.announcementGroup
) {
window.log.warn(
`addMember/${idLog}: ${conversationId} needs to upgrade.`
);
return undefined;
}
// We need the user's profileKeyCredential, which requires a roundtrip with the
// server, and most definitely their profileKey. A getProfiles() call will
// ensure that we have as much as we can get with the data we have.
@ -1436,6 +1456,8 @@ export class ConversationModel extends window.Backbone
?.addFromInviteLink,
accessControlAttributes: this.get('accessControl')?.attributes,
accessControlMembers: this.get('accessControl')?.members,
announcementsOnly: Boolean(this.get('announcementsOnly')),
announcementsOnlyReady: this.canBeAnnouncementGroup(),
expireTimer: this.get('expireTimer'),
muteExpiresAt: this.get('muteExpiresAt')!,
name: this.get('name')!,
@ -1830,6 +1852,20 @@ export class ConversationModel extends window.Backbone
}
async addMembersV2(conversationIds: ReadonlyArray<string>): Promise<void> {
if (this.get('announcementsOnly')) {
const isEveryMemberCapable = conversationIds.every(conversationId => {
const model = window.ConversationController.get(conversationId);
return Boolean(model?.get('capabilities')?.announcementGroup);
});
if (!isEveryMemberCapable) {
const error = new Error(
'addMembersV2: some or all members need to upgrade.'
);
error.code = 'E_NO_CAPABILITY';
throw error;
}
}
await this.modifyGroupV2({
name: 'addMembersV2',
createGroupChange: () =>
@ -2975,6 +3011,17 @@ export class ConversationModel extends window.Backbone
);
}
canBeAnnouncementGroup(): boolean {
if (!isGroupV2(this.attributes)) {
return false;
}
const members = getConversationMembers(this.attributes);
return members.every(conversationAttrs =>
Boolean(conversationAttrs.capabilities?.announcementGroup)
);
}
getMemberIds(): Array<string> {
const members = this.getMembers();
return members.map(member => member.id);
@ -4004,6 +4051,23 @@ export class ConversationModel extends window.Backbone
});
}
async updateAnnouncementsOnly(value: boolean): Promise<void> {
if (!isGroupV2(this.attributes) || !this.canBeAnnouncementGroup()) {
return;
}
await this.modifyGroupV2({
name: 'updateAnnouncementsOnly',
createGroupChange: async () =>
window.Signal.Groups.buildAnnouncementsOnlyChange(
this.attributes,
value
),
});
this.set({ announcementsOnly: value });
}
async updateExpirationTimer(
providedExpireTimer: number | undefined,
providedSource?: unknown,
@ -5150,6 +5214,12 @@ export class ConversationModel extends window.Backbone
return;
}
// Drop typing indicators for announcement only groups where the sender
// is not an admin
if (this.get('announcementsOnly') && !this.isAdmin(senderId)) {
return;
}
const typingToken = `${senderId}.${senderDevice}`;
this.contactTypingTimers = this.contactTypingTimers || {};