signal-desktop/ts/util/groupMembershipUtils.ts
2023-08-21 09:30:33 -07:00

186 lines
4.6 KiB
TypeScript

// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import isNumber from 'lodash/isNumber';
import type { ConversationAttributesType } from '../model-types.d';
import type { ServiceIdString, AciString } from '../types/ServiceId';
import { SignalService as Proto } from '../protobuf';
import { isDirectConversation, isGroupV2 } from './whatTypeOfConversation';
export function isMemberPending(
conversationAttrs: Pick<
ConversationAttributesType,
'groupId' | 'groupVersion' | 'pendingMembersV2'
>,
serviceId: ServiceIdString
): boolean {
if (!isGroupV2(conversationAttrs)) {
return false;
}
const { pendingMembersV2 } = conversationAttrs;
if (!pendingMembersV2 || !pendingMembersV2.length) {
return false;
}
return pendingMembersV2.some(item => item.serviceId === serviceId);
}
export function isMemberBanned(
conversationAttrs: Pick<
ConversationAttributesType,
'groupId' | 'groupVersion' | 'bannedMembersV2'
>,
serviceId: ServiceIdString
): boolean {
if (!isGroupV2(conversationAttrs)) {
return false;
}
const { bannedMembersV2 } = conversationAttrs;
if (!bannedMembersV2 || !bannedMembersV2.length) {
return false;
}
return bannedMembersV2.some(member => member.serviceId === serviceId);
}
export function isMemberAwaitingApproval(
conversationAttrs: Pick<
ConversationAttributesType,
'groupId' | 'groupVersion' | 'pendingAdminApprovalV2'
>,
serviceId: ServiceIdString
): boolean {
if (!isGroupV2(conversationAttrs)) {
return false;
}
const { pendingAdminApprovalV2 } = conversationAttrs;
if (!pendingAdminApprovalV2 || !pendingAdminApprovalV2.length) {
return false;
}
return pendingAdminApprovalV2.some(member => member.aci === serviceId);
}
export function isMember(
conversationAttrs: Pick<
ConversationAttributesType,
'groupId' | 'groupVersion' | 'membersV2'
>,
serviceId: ServiceIdString
): boolean {
if (!isGroupV2(conversationAttrs)) {
return false;
}
const { membersV2 } = conversationAttrs;
if (!membersV2 || !membersV2.length) {
return false;
}
return membersV2.some(item => item.aci === serviceId);
}
export function isMemberRequestingToJoin(
conversationAttrs: Pick<
ConversationAttributesType,
'groupId' | 'groupVersion' | 'pendingAdminApprovalV2'
>,
serviceId: ServiceIdString
): boolean {
if (!isGroupV2(conversationAttrs)) {
return false;
}
const { pendingAdminApprovalV2 } = conversationAttrs;
if (!pendingAdminApprovalV2 || !pendingAdminApprovalV2.length) {
return false;
}
return pendingAdminApprovalV2.some(item => item.aci === serviceId);
}
const EMPTY_ARRAY: Readonly<[]> = [];
export function getBannedMemberships(
conversationAttrs: ConversationAttributesType
): ReadonlyArray<ServiceIdString> {
if (!isGroupV2(conversationAttrs)) {
return EMPTY_ARRAY;
}
const { bannedMembersV2 } = conversationAttrs;
return (bannedMembersV2 || []).map(member => member.serviceId);
}
export function getPendingMemberships(
conversationAttrs: ConversationAttributesType
): ReadonlyArray<{
addedByUserId?: AciString;
serviceId: ServiceIdString;
}> {
if (!isGroupV2(conversationAttrs)) {
return EMPTY_ARRAY;
}
const members = conversationAttrs.pendingMembersV2 || [];
return members.map(member => ({
addedByUserId: member.addedByUserId,
serviceId: member.serviceId,
}));
}
export function getPendingApprovalMemberships(
conversationAttrs: ConversationAttributesType
): ReadonlyArray<{ aci: AciString }> {
if (!isGroupV2(conversationAttrs)) {
return EMPTY_ARRAY;
}
const members = conversationAttrs.pendingAdminApprovalV2 || [];
return members.map(member => ({
aci: member.aci,
}));
}
export function getMembersCount(
conversationAttrs: ConversationAttributesType
): number | undefined {
if (isDirectConversation(conversationAttrs)) {
return undefined;
}
const memberList = conversationAttrs.membersV2 || conversationAttrs.members;
// We'll fail over if the member list is empty
if (memberList && memberList.length) {
return memberList.length;
}
const { temporaryMemberCount } = conversationAttrs;
if (isNumber(temporaryMemberCount)) {
return temporaryMemberCount;
}
return undefined;
}
export function getMemberships(
conversationAttrs: ConversationAttributesType
): ReadonlyArray<{
aci: AciString;
isAdmin: boolean;
}> {
if (!isGroupV2(conversationAttrs)) {
return EMPTY_ARRAY;
}
const members = conversationAttrs.membersV2 || [];
return members.map(member => ({
isAdmin: member.role === Proto.Member.Role.ADMINISTRATOR,
aci: member.aci,
}));
}