Group V2 invite links: in-conversation messages
This commit is contained in:
parent
8e7379a591
commit
272e6cc614
10 changed files with 1775 additions and 206 deletions
|
@ -3405,6 +3405,42 @@
|
||||||
"message": "An admin changed who can edit group membership to \"All members.\"",
|
"message": "An admin changed who can edit group membership to \"All members.\"",
|
||||||
"description": "Shown in timeline or conversation preview when v2 group changes"
|
"description": "Shown in timeline or conversation preview when v2 group changes"
|
||||||
},
|
},
|
||||||
|
"GroupV2--access-invite-link--disabled--you": {
|
||||||
|
"message": "You disabled admin approval for the group link.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes"
|
||||||
|
},
|
||||||
|
"GroupV2--access-invite-link--disabled--other": {
|
||||||
|
"message": "$adminName$ disabled admin approval for the group link.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes",
|
||||||
|
"placeholders": {
|
||||||
|
"adminName": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "Alice"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"GroupV2--access-invite-link--disabled--unknown": {
|
||||||
|
"message": "Admin approval for the group link has been disabled.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes"
|
||||||
|
},
|
||||||
|
"GroupV2--access-invite-link--enabled--you": {
|
||||||
|
"message": "You enabled admin approval for the group link.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes"
|
||||||
|
},
|
||||||
|
"GroupV2--access-invite-link--enabled--other": {
|
||||||
|
"message": "$adminName$ enabled admin approval for the group link.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes",
|
||||||
|
"placeholders": {
|
||||||
|
"adminName": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "Alice"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"GroupV2--access-invite-link--enabled--unknown": {
|
||||||
|
"message": "Admin approval for the group link has been disabled.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes"
|
||||||
|
},
|
||||||
"GroupV2--member-add--invited--you": {
|
"GroupV2--member-add--invited--you": {
|
||||||
"message": "You added invited member $inviteeName$.",
|
"message": "You added invited member $inviteeName$.",
|
||||||
"description": "Shown in timeline or conversation preview when v2 group changes",
|
"description": "Shown in timeline or conversation preview when v2 group changes",
|
||||||
|
@ -3539,6 +3575,72 @@
|
||||||
"message": "You were added to the group.",
|
"message": "You were added to the group.",
|
||||||
"description": "Shown in timeline or conversation preview when v2 group changes"
|
"description": "Shown in timeline or conversation preview when v2 group changes"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"GroupV2--member-add-from-link--you--you": {
|
||||||
|
"message": "You joined the group via the group link.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes"
|
||||||
|
},
|
||||||
|
"GroupV2--member-add-from-link--other": {
|
||||||
|
"message": "$memberName$ joined the group via the group link.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes",
|
||||||
|
"placeholders": {
|
||||||
|
"memberName": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "Alice"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"GroupV2--member-add-from-admin-approval--you--other": {
|
||||||
|
"message": "$adminName$ approved your request to join the group.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes",
|
||||||
|
"placeholders": {
|
||||||
|
"adminName": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "Alice"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"GroupV2--member-add-from-admin-approval--you--unknown": {
|
||||||
|
"message": "Your request to join the group has been approved.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes"
|
||||||
|
},
|
||||||
|
|
||||||
|
"GroupV2--member-add-from-admin-approval--other--you": {
|
||||||
|
"message": "You approved a request to join the group from $joinerName$.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes",
|
||||||
|
"placeholders": {
|
||||||
|
"joinerName": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "Alice"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"GroupV2--member-add-from-admin-approval--other--other": {
|
||||||
|
"message": "$adminName$ approved a request to join the group from $joinerName$.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes",
|
||||||
|
"placeholders": {
|
||||||
|
"adminName": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "Bob"
|
||||||
|
},
|
||||||
|
"joinerName": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "Alice"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"GroupV2--member-add-from-admin-approval--other--unknown": {
|
||||||
|
"message": "A request to join the group from $joinerName$ has been approved.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes",
|
||||||
|
"placeholders": {
|
||||||
|
"joinerName": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "Alice"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
"GroupV2--member-remove--other--other": {
|
"GroupV2--member-remove--other--other": {
|
||||||
"message": "$adminName$ removed $memberName$.",
|
"message": "$adminName$ removed $memberName$.",
|
||||||
"description": "Shown in timeline or conversation preview when v2 group changes",
|
"description": "Shown in timeline or conversation preview when v2 group changes",
|
||||||
|
@ -4030,6 +4132,138 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"GroupV2--admin-approval-add-one--you": {
|
||||||
|
"message": "You sent a request to join the group.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes"
|
||||||
|
},
|
||||||
|
"GroupV2--admin-approval-add-one--other": {
|
||||||
|
"message": "$joinerName$ requested to join via the group link.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes",
|
||||||
|
"placeholders": {
|
||||||
|
"joinerName": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "Alice"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"GroupV2--admin-approval-remove-one--you--you": {
|
||||||
|
"message": "You canceled your request to join the group.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes"
|
||||||
|
},
|
||||||
|
"GroupV2--admin-approval-remove-one--you--unknown": {
|
||||||
|
"message": "Your request to join the group has been denied by an admin.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes"
|
||||||
|
},
|
||||||
|
|
||||||
|
"GroupV2--admin-approval-remove-one--other--you": {
|
||||||
|
"message": "You denied a request to join the group from $joinerName$.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes",
|
||||||
|
"placeholders": {
|
||||||
|
"joinerName": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "Alice"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"GroupV2--admin-approval-remove-one--other--own": {
|
||||||
|
"message": "$joinerName$ canceled their request to join the group.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes",
|
||||||
|
"placeholders": {
|
||||||
|
"joinerName": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "Alice"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"GroupV2--admin-approval-remove-one--other--other": {
|
||||||
|
"message": "$adminName$ denied a request to join the group from $joinerName$.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes",
|
||||||
|
"placeholders": {
|
||||||
|
"adminName": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "Bob"
|
||||||
|
},
|
||||||
|
"joinerName": {
|
||||||
|
"content": "$2",
|
||||||
|
"example": "Alice"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"GroupV2--group-link-add--disabled--you": {
|
||||||
|
"message": "You turned on the group link with admin approval disabled.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes"
|
||||||
|
},
|
||||||
|
"GroupV2--group-link-add--disabled--other": {
|
||||||
|
"message": "$adminName$ turned on the group link with admin approval disabled.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes",
|
||||||
|
"placeholders": {
|
||||||
|
"adminName": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "Alice"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"GroupV2--group-link-add--disabled--unknown": {
|
||||||
|
"message": "The group link has been turned on with admin approval disabled.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes"
|
||||||
|
},
|
||||||
|
"GroupV2--group-link-add--enabled--you": {
|
||||||
|
"message": "You turned on the group link with admin approval enabled.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes"
|
||||||
|
},
|
||||||
|
"GroupV2--group-link-add--enabled--other": {
|
||||||
|
"message": "$adminName$ turned on the group link with admin approval enabled.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes",
|
||||||
|
"placeholders": {
|
||||||
|
"adminName": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "Alice"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"GroupV2--group-link-add--enabled--unknown": {
|
||||||
|
"message": "The group link has been turned on with admin approval enabled.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes"
|
||||||
|
},
|
||||||
|
"GroupV2--group-link-remove--you": {
|
||||||
|
"message": "You turned off the group link.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes"
|
||||||
|
},
|
||||||
|
"GroupV2--group-link-remove--other": {
|
||||||
|
"message": "$adminName$ turned off the group link.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes",
|
||||||
|
"placeholders": {
|
||||||
|
"adminName": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "Alice"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"GroupV2--group-link-remove--unknown": {
|
||||||
|
"message": "The group link has been turned off.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes"
|
||||||
|
},
|
||||||
|
"GroupV2--group-link-reset--you": {
|
||||||
|
"message": "You reset the group link.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes"
|
||||||
|
},
|
||||||
|
"GroupV2--group-link-reset--other": {
|
||||||
|
"message": "$adminName$ reset the group link.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes",
|
||||||
|
"placeholders": {
|
||||||
|
"adminName": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "Alice"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"GroupV2--group-link-reset--unknown": {
|
||||||
|
"message": "The group link has been reset.",
|
||||||
|
"description": "Shown in timeline or conversation preview when v2 group changes"
|
||||||
|
},
|
||||||
|
|
||||||
"GroupV1--Migration--disabled": {
|
"GroupV1--Migration--disabled": {
|
||||||
"message": "Upgrade this group to activate new features like @mentions and admins. Members who have not shared their name or photo in this group will be invited to join. $learnMore$",
|
"message": "Upgrade this group to activate new features like @mentions and admins. Members who have not shared their name or photo in this group will be invited to join. $learnMore$",
|
||||||
"description": "Shown instead of composition area when user is forced to migrate a legacy group (GV1).",
|
"description": "Shown instead of composition area when user is forced to migrate a legacy group (GV1).",
|
||||||
|
|
|
@ -27,6 +27,11 @@ try {
|
||||||
title += ` - ${config.appInstance}`;
|
title += ` - ${config.appInstance}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flags for testing
|
||||||
|
window.GV2_ENABLE_SINGLE_CHANGE_PROCESSING = true;
|
||||||
|
window.GV2_ENABLE_CHANGE_PROCESSING = true;
|
||||||
|
window.GV2_ENABLE_STATE_PROCESSING = true;
|
||||||
|
|
||||||
window.platform = process.platform;
|
window.platform = process.platform;
|
||||||
window.getTitle = () => title;
|
window.getTitle = () => title;
|
||||||
window.getEnvironment = () => config.environment;
|
window.getEnvironment = () => config.environment;
|
||||||
|
|
|
@ -29,32 +29,44 @@ message Member {
|
||||||
uint32 joinedAtVersion = 5; // The Group.version this member joined at
|
uint32 joinedAtVersion = 5; // The Group.version this member joined at
|
||||||
}
|
}
|
||||||
|
|
||||||
message PendingMember {
|
message MemberPendingProfileKey {
|
||||||
Member member = 1; // The “invited” member
|
Member member = 1; // The “invited” member
|
||||||
bytes addedByUserId = 2; // The UID who invited this member
|
bytes addedByUserId = 2; // The UID who invited this member
|
||||||
uint64 timestamp = 3; // The time the invitation occurred
|
uint64 timestamp = 3; // The time the invitation occurred
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message MemberPendingAdminApproval {
|
||||||
|
bytes userId = 1;
|
||||||
|
bytes profileKey = 2;
|
||||||
|
bytes presentation = 3;
|
||||||
|
uint64 timestamp = 4;
|
||||||
|
}
|
||||||
|
|
||||||
message AccessControl {
|
message AccessControl {
|
||||||
enum AccessRequired {
|
enum AccessRequired {
|
||||||
UNKNOWN = 0;
|
UNKNOWN = 0;
|
||||||
|
ANY = 1;
|
||||||
MEMBER = 2; // Any group member can make the modification
|
MEMBER = 2; // Any group member can make the modification
|
||||||
ADMINISTRATOR = 3; // Only administrators can make the modification
|
ADMINISTRATOR = 3; // Only administrators can make the modification
|
||||||
|
UNSATISFIABLE = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
AccessRequired attributes = 1; // Who can modify the group title, avatar, disappearing messages timer
|
AccessRequired attributes = 1; // Who can modify the group title, avatar, disappearing messages timer
|
||||||
AccessRequired members = 2; // Who can add people to the group
|
AccessRequired members = 2; // Who can add people to the group
|
||||||
|
AccessRequired addFromInviteLink = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Group {
|
message Group {
|
||||||
bytes publicKey = 1; // GroupPublicParams
|
bytes publicKey = 1; // GroupPublicParams
|
||||||
bytes title = 2; // Encrypted title
|
bytes title = 2; // Encrypted title
|
||||||
string avatar = 3; // Pointer to encrypted avatar (‘key’ from AvatarUploadAttributes)
|
string avatar = 3; // Pointer to encrypted avatar (‘key’ from AvatarUploadAttributes)
|
||||||
bytes disappearingMessagesTimer = 4; // Encrypted timer
|
bytes disappearingMessagesTimer = 4; // Encrypted timer
|
||||||
AccessControl accessControl = 5;
|
AccessControl accessControl = 5;
|
||||||
uint32 version = 6; // Current group version number
|
uint32 version = 6; // Current group version number
|
||||||
repeated Member members = 7;
|
repeated Member members = 7;
|
||||||
repeated PendingMember pendingMembers = 8;
|
repeated MemberPendingProfileKey membersPendingProfileKey = 8;
|
||||||
|
repeated MemberPendingAdminApproval membersPendingAdminApproval = 9;
|
||||||
|
bytes inviteLinkPassword = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GroupChange {
|
message GroupChange {
|
||||||
|
@ -62,7 +74,8 @@ message GroupChange {
|
||||||
message Actions {
|
message Actions {
|
||||||
|
|
||||||
message AddMemberAction {
|
message AddMemberAction {
|
||||||
Member added = 1;
|
Member added = 1;
|
||||||
|
bool joinFromInviteLink = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeleteMemberAction {
|
message DeleteMemberAction {
|
||||||
|
@ -78,18 +91,32 @@ message GroupChange {
|
||||||
bytes presentation = 1;
|
bytes presentation = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AddPendingMemberAction {
|
message AddMemberPendingProfileKeyAction {
|
||||||
PendingMember added = 1;
|
MemberPendingProfileKey added = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeletePendingMemberAction {
|
message DeleteMemberPendingProfileKeyAction {
|
||||||
bytes deletedUserId = 1;
|
bytes deletedUserId = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message PromotePendingMemberAction {
|
message PromoteMemberPendingProfileKeyAction {
|
||||||
bytes presentation = 1;
|
bytes presentation = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message AddMemberPendingAdminApprovalAction {
|
||||||
|
MemberPendingAdminApproval added = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DeleteMemberPendingAdminApprovalAction {
|
||||||
|
bytes deletedUserId = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message PromoteMemberPendingAdminApprovalAction {
|
||||||
|
bytes userId = 1;
|
||||||
|
Member.Role role = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
message ModifyTitleAction {
|
message ModifyTitleAction {
|
||||||
bytes title = 1;
|
bytes title = 1;
|
||||||
}
|
}
|
||||||
|
@ -114,20 +141,34 @@ message GroupChange {
|
||||||
AccessControl.AccessRequired membersAccess = 1;
|
AccessControl.AccessRequired membersAccess = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes sourceUuid = 1; // Who made the change
|
message ModifyAddFromInviteLinkAccessControlAction {
|
||||||
uint32 version = 2; // The change version number
|
AccessControl.AccessRequired addFromInviteLinkAccess = 1;
|
||||||
repeated AddMemberAction addMembers = 3; // Members added
|
}
|
||||||
repeated DeleteMemberAction deleteMembers = 4; // Members deleted
|
|
||||||
repeated ModifyMemberRoleAction modifyMemberRoles = 5; // Modified member roles
|
message ModifyInviteLinkPasswordAction {
|
||||||
repeated ModifyMemberProfileKeyAction modifyMemberProfileKeys = 6; // Modified member profile keys
|
bytes inviteLinkPassword = 1;
|
||||||
repeated AddPendingMemberAction addPendingMembers = 7; // Pending members added
|
}
|
||||||
repeated DeletePendingMemberAction deletePendingMembers = 8; // Pending members deleted
|
|
||||||
repeated PromotePendingMemberAction promotePendingMembers = 9; // Pending invitations accepted
|
|
||||||
ModifyTitleAction modifyTitle = 10; // Changed title
|
bytes sourceUuid = 1; // Who made the change
|
||||||
ModifyAvatarAction modifyAvatar = 11; // Changed avatar
|
uint32 version = 2; // The change version number
|
||||||
ModifyDisappearingMessagesTimerAction modifyDisappearingMessagesTimer = 12; // Changed timer
|
repeated AddMemberAction addMembers = 3; // Members added
|
||||||
ModifyAttributesAccessControlAction modifyAttributesAccess = 13; // Changed attributes access control
|
repeated DeleteMemberAction deleteMembers = 4; // Members deleted
|
||||||
ModifyMembersAccessControlAction modifyMemberAccess = 14; // Changed membership access control
|
repeated ModifyMemberRoleAction modifyMemberRoles = 5; // Modified member roles
|
||||||
|
repeated ModifyMemberProfileKeyAction modifyMemberProfileKeys = 6; // Modified member profile keys
|
||||||
|
repeated AddMemberPendingProfileKeyAction addPendingMembers = 7; // Pending members added
|
||||||
|
repeated DeleteMemberPendingProfileKeyAction deletePendingMembers = 8; // Pending members deleted
|
||||||
|
repeated PromoteMemberPendingProfileKeyAction promotePendingMembers = 9; // Pending invitations accepted
|
||||||
|
ModifyTitleAction modifyTitle = 10; // Changed title
|
||||||
|
ModifyAvatarAction modifyAvatar = 11; // Changed avatar
|
||||||
|
ModifyDisappearingMessagesTimerAction modifyDisappearingMessagesTimer = 12; // Changed timer
|
||||||
|
ModifyAttributesAccessControlAction modifyAttributesAccess = 13; // Changed attributes access control
|
||||||
|
ModifyMembersAccessControlAction modifyMemberAccess = 14; // Changed membership access control
|
||||||
|
ModifyAddFromInviteLinkAccessControlAction modifyAddFromInviteLinkAccess = 15;
|
||||||
|
repeated AddMemberPendingAdminApprovalAction addMemberPendingAdminApprovals = 16;
|
||||||
|
repeated DeleteMemberPendingAdminApprovalAction deleteMemberPendingAdminApprovals = 17;
|
||||||
|
repeated PromoteMemberPendingAdminApprovalAction promoteMemberPendingAdminApprovals = 18;
|
||||||
|
ModifyInviteLinkPasswordAction modifyInviteLinkPassword = 19;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes actions = 1; // The serialized actions
|
bytes actions = 1; // The serialized actions
|
||||||
|
@ -155,3 +196,14 @@ message GroupAttributeBlob {
|
||||||
message GroupExternalCredential {
|
message GroupExternalCredential {
|
||||||
string token = 1;
|
string token = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message GroupInviteLink {
|
||||||
|
message GroupInviteLinkContentsV1 {
|
||||||
|
bytes groupMasterKey = 1;
|
||||||
|
bytes inviteLinkPassword = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
oneof contents {
|
||||||
|
GroupInviteLinkContentsV1 v1Contents = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -23,11 +23,13 @@ const INVITEE_A = 'INVITEE_A';
|
||||||
class AccessControlEnum {
|
class AccessControlEnum {
|
||||||
static UNKNOWN = 0;
|
static UNKNOWN = 0;
|
||||||
|
|
||||||
static ADMINISTRATOR = 1;
|
static ANY = 1;
|
||||||
|
|
||||||
static ANY = 2;
|
static MEMBER = 2;
|
||||||
|
|
||||||
static MEMBER = 3;
|
static ADMINISTRATOR = 3;
|
||||||
|
|
||||||
|
static UNSATISFIABLE = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
class RoleEnum {
|
class RoleEnum {
|
||||||
|
@ -342,6 +344,64 @@ storiesOf('Components/Conversation/GroupV2Change', module)
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
.add('Access (Invite Link)', () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{renderChange({
|
||||||
|
from: OUR_ID,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'access-invite-link',
|
||||||
|
newPrivilege: AccessControlEnum.ANY,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
from: ADMIN_A,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'access-invite-link',
|
||||||
|
newPrivilege: AccessControlEnum.ANY,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'access-invite-link',
|
||||||
|
newPrivilege: AccessControlEnum.ANY,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
from: OUR_ID,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'access-invite-link',
|
||||||
|
newPrivilege: AccessControlEnum.ADMINISTRATOR,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
from: ADMIN_A,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'access-invite-link',
|
||||||
|
newPrivilege: AccessControlEnum.ADMINISTRATOR,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'access-invite-link',
|
||||||
|
newPrivilege: AccessControlEnum.ADMINISTRATOR,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})
|
||||||
.add('Member Add', () => {
|
.add('Member Add', () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -400,7 +460,7 @@ storiesOf('Components/Conversation/GroupV2Change', module)
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.add('Member Add - add invited', () => {
|
.add('Member Add (from invited)', () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* the strings where someone added you - shown like a normal add */}
|
{/* the strings where someone added you - shown like a normal add */}
|
||||||
|
@ -505,6 +565,87 @@ storiesOf('Components/Conversation/GroupV2Change', module)
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
.add('Member Add (from link)', () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{renderChange({
|
||||||
|
from: OUR_ID,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'member-add-from-link',
|
||||||
|
conversationId: OUR_ID,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
from: CONTACT_A,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'member-add-from-link',
|
||||||
|
conversationId: CONTACT_A,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'member-add-from-link',
|
||||||
|
conversationId: CONTACT_A,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.add('Member Add (from admin approval)', () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{renderChange({
|
||||||
|
from: ADMIN_A,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'member-add-from-admin-approval',
|
||||||
|
conversationId: OUR_ID,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'member-add-from-admin-approval',
|
||||||
|
conversationId: OUR_ID,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
from: OUR_ID,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'member-add-from-admin-approval',
|
||||||
|
conversationId: CONTACT_A,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
from: ADMIN_A,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'member-add-from-admin-approval',
|
||||||
|
conversationId: CONTACT_A,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'member-add-from-admin-approval',
|
||||||
|
conversationId: CONTACT_A,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})
|
||||||
.add('Member Remove', () => {
|
.add('Member Remove', () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -987,4 +1128,200 @@ storiesOf('Components/Conversation/GroupV2Change', module)
|
||||||
})}
|
})}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
})
|
||||||
|
.add('Admin Approval (Add)', () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{renderChange({
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'admin-approval-add-one',
|
||||||
|
conversationId: OUR_ID,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'admin-approval-add-one',
|
||||||
|
conversationId: CONTACT_A,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.add('Admin Approval (Remove)', () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{renderChange({
|
||||||
|
from: OUR_ID,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'admin-approval-remove-one',
|
||||||
|
conversationId: OUR_ID,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'admin-approval-remove-one',
|
||||||
|
conversationId: OUR_ID,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
from: OUR_ID,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'admin-approval-remove-one',
|
||||||
|
conversationId: CONTACT_A,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
from: CONTACT_A,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'admin-approval-remove-one',
|
||||||
|
conversationId: CONTACT_A,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
from: ADMIN_A,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'admin-approval-remove-one',
|
||||||
|
conversationId: CONTACT_A,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'admin-approval-remove-one',
|
||||||
|
conversationId: CONTACT_A,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.add('Group Link (Add)', () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{renderChange({
|
||||||
|
from: OUR_ID,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'group-link-add',
|
||||||
|
privilege: AccessControlEnum.ANY,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
from: ADMIN_A,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'group-link-add',
|
||||||
|
privilege: AccessControlEnum.ANY,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'group-link-add',
|
||||||
|
privilege: AccessControlEnum.ANY,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
from: OUR_ID,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'group-link-add',
|
||||||
|
privilege: AccessControlEnum.ADMINISTRATOR,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
from: ADMIN_A,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'group-link-add',
|
||||||
|
privilege: AccessControlEnum.ADMINISTRATOR,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'group-link-add',
|
||||||
|
privilege: AccessControlEnum.ADMINISTRATOR,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.add('Group Link (Reset)', () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{renderChange({
|
||||||
|
from: OUR_ID,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'group-link-reset',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
from: ADMIN_A,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'group-link-reset',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'group-link-reset',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.add('Group Link (Remove)', () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{renderChange({
|
||||||
|
from: OUR_ID,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'group-link-remove',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
from: ADMIN_A,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'group-link-remove',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'group-link-remove',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -138,10 +138,12 @@ export function renderChangeDetail(
|
||||||
}
|
}
|
||||||
return renderString('GroupV2--access-attributes--all--unknown', i18n);
|
return renderString('GroupV2--access-attributes--all--unknown', i18n);
|
||||||
}
|
}
|
||||||
throw new Error(
|
window.log.warn(
|
||||||
`access-attributes change type, privilege ${newPrivilege} is unknown`
|
`access-attributes change type, privilege ${newPrivilege} is unknown`
|
||||||
);
|
);
|
||||||
} else if (detail.type === 'access-members') {
|
return '';
|
||||||
|
}
|
||||||
|
if (detail.type === 'access-members') {
|
||||||
const { newPrivilege } = detail;
|
const { newPrivilege } = detail;
|
||||||
|
|
||||||
if (newPrivilege === AccessControlEnum.ADMINISTRATOR) {
|
if (newPrivilege === AccessControlEnum.ADMINISTRATOR) {
|
||||||
|
@ -166,10 +168,52 @@ export function renderChangeDetail(
|
||||||
}
|
}
|
||||||
return renderString('GroupV2--access-members--all--unknown', i18n);
|
return renderString('GroupV2--access-members--all--unknown', i18n);
|
||||||
}
|
}
|
||||||
throw new Error(
|
window.log.warn(
|
||||||
`access-members change type, privilege ${newPrivilege} is unknown`
|
`access-members change type, privilege ${newPrivilege} is unknown`
|
||||||
);
|
);
|
||||||
} else if (detail.type === 'member-add') {
|
return '';
|
||||||
|
}
|
||||||
|
if (detail.type === 'access-invite-link') {
|
||||||
|
const { newPrivilege } = detail;
|
||||||
|
|
||||||
|
if (newPrivilege === AccessControlEnum.ADMINISTRATOR) {
|
||||||
|
if (fromYou) {
|
||||||
|
return renderString('GroupV2--access-invite-link--enabled--you', i18n);
|
||||||
|
}
|
||||||
|
if (from) {
|
||||||
|
return renderString(
|
||||||
|
'GroupV2--access-invite-link--enabled--other',
|
||||||
|
i18n,
|
||||||
|
[renderContact(from)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return renderString(
|
||||||
|
'GroupV2--access-invite-link--enabled--unknown',
|
||||||
|
i18n
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (newPrivilege === AccessControlEnum.ANY) {
|
||||||
|
if (fromYou) {
|
||||||
|
return renderString('GroupV2--access-invite-link--disabled--you', i18n);
|
||||||
|
}
|
||||||
|
if (from) {
|
||||||
|
return renderString(
|
||||||
|
'GroupV2--access-invite-link--disabled--other',
|
||||||
|
i18n,
|
||||||
|
[renderContact(from)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return renderString(
|
||||||
|
'GroupV2--access-invite-link--disabled--unknown',
|
||||||
|
i18n
|
||||||
|
);
|
||||||
|
}
|
||||||
|
window.log.warn(
|
||||||
|
`access-invite-link change type, privilege ${newPrivilege} is unknown`
|
||||||
|
);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (detail.type === 'member-add') {
|
||||||
const { conversationId } = detail;
|
const { conversationId } = detail;
|
||||||
const weAreJoiner = conversationId === ourConversationId;
|
const weAreJoiner = conversationId === ourConversationId;
|
||||||
|
|
||||||
|
@ -198,7 +242,8 @@ export function renderChangeDetail(
|
||||||
return renderString('GroupV2--member-add--other--unknown', i18n, [
|
return renderString('GroupV2--member-add--other--unknown', i18n, [
|
||||||
renderContact(conversationId),
|
renderContact(conversationId),
|
||||||
]);
|
]);
|
||||||
} else if (detail.type === 'member-add-from-invite') {
|
}
|
||||||
|
if (detail.type === 'member-add-from-invite') {
|
||||||
const { conversationId, inviter } = detail;
|
const { conversationId, inviter } = detail;
|
||||||
const weAreJoiner = conversationId === ourConversationId;
|
const weAreJoiner = conversationId === ourConversationId;
|
||||||
const weAreInviter = Boolean(inviter && inviter === ourConversationId);
|
const weAreInviter = Boolean(inviter && inviter === ourConversationId);
|
||||||
|
@ -259,7 +304,80 @@ export function renderChangeDetail(
|
||||||
inviteeName: renderContact(conversationId),
|
inviteeName: renderContact(conversationId),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else if (detail.type === 'member-remove') {
|
}
|
||||||
|
if (detail.type === 'member-add-from-link') {
|
||||||
|
const { conversationId } = detail;
|
||||||
|
|
||||||
|
if (fromYou && conversationId === ourConversationId) {
|
||||||
|
return renderString('GroupV2--member-add-from-link--you--you', i18n);
|
||||||
|
}
|
||||||
|
if (from && conversationId === from) {
|
||||||
|
return renderString('GroupV2--member-add-from-link--other', i18n, [
|
||||||
|
renderContact(from),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: this shouldn't happen, because we only capture 'add-from-link' status
|
||||||
|
// from group change events, which always have a sender.
|
||||||
|
window.log.warn('member-add-from-link change type; we have no from!');
|
||||||
|
return renderString('GroupV2--member-add--other--unknown', i18n, [
|
||||||
|
renderContact(conversationId),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
if (detail.type === 'member-add-from-admin-approval') {
|
||||||
|
const { conversationId } = detail;
|
||||||
|
const weAreJoiner = conversationId === ourConversationId;
|
||||||
|
|
||||||
|
if (weAreJoiner) {
|
||||||
|
if (from) {
|
||||||
|
return renderString(
|
||||||
|
'GroupV2--member-add-from-admin-approval--you--other',
|
||||||
|
i18n,
|
||||||
|
[renderContact(from)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: this shouldn't happen, because we only capture 'add-from-admin-approval'
|
||||||
|
// status from group change events, which always have a sender.
|
||||||
|
window.log.warn(
|
||||||
|
'member-add-from-admin-approval change type; we have no from, and we are joiner!'
|
||||||
|
);
|
||||||
|
return renderString(
|
||||||
|
'GroupV2--member-add-from-admin-approval--you--unknown',
|
||||||
|
i18n
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fromYou) {
|
||||||
|
return renderString(
|
||||||
|
'GroupV2--member-add-from-admin-approval--other--you',
|
||||||
|
i18n,
|
||||||
|
[renderContact(conversationId)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (from) {
|
||||||
|
return renderString(
|
||||||
|
'GroupV2--member-add-from-admin-approval--other--other',
|
||||||
|
i18n,
|
||||||
|
{
|
||||||
|
adminName: renderContact(from),
|
||||||
|
joinerName: renderContact(conversationId),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: this shouldn't happen, because we only capture 'add-from-admin-approval'
|
||||||
|
// status from group change events, which always have a sender.
|
||||||
|
window.log.warn(
|
||||||
|
'member-add-from-admin-approval change type; we have no from'
|
||||||
|
);
|
||||||
|
return renderString(
|
||||||
|
'GroupV2--member-add-from-admin-approval--other--unknown',
|
||||||
|
i18n,
|
||||||
|
[renderContact(conversationId)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (detail.type === 'member-remove') {
|
||||||
const { conversationId } = detail;
|
const { conversationId } = detail;
|
||||||
const weAreLeaver = conversationId === ourConversationId;
|
const weAreLeaver = conversationId === ourConversationId;
|
||||||
|
|
||||||
|
@ -294,7 +412,8 @@ export function renderChangeDetail(
|
||||||
return renderString('GroupV2--member-remove--other--unknown', i18n, [
|
return renderString('GroupV2--member-remove--other--unknown', i18n, [
|
||||||
renderContact(conversationId),
|
renderContact(conversationId),
|
||||||
]);
|
]);
|
||||||
} else if (detail.type === 'member-privilege') {
|
}
|
||||||
|
if (detail.type === 'member-privilege') {
|
||||||
const { conversationId, newPrivilege } = detail;
|
const { conversationId, newPrivilege } = detail;
|
||||||
const weAreMember = conversationId === ourConversationId;
|
const weAreMember = conversationId === ourConversationId;
|
||||||
|
|
||||||
|
@ -375,10 +494,12 @@ export function renderChangeDetail(
|
||||||
[renderContact(conversationId)]
|
[renderContact(conversationId)]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
throw new Error(
|
window.log.warn(
|
||||||
`member-privilege change type, privilege ${newPrivilege} is unknown`
|
`member-privilege change type, privilege ${newPrivilege} is unknown`
|
||||||
);
|
);
|
||||||
} else if (detail.type === 'pending-add-one') {
|
return '';
|
||||||
|
}
|
||||||
|
if (detail.type === 'pending-add-one') {
|
||||||
const { conversationId } = detail;
|
const { conversationId } = detail;
|
||||||
const weAreInvited = conversationId === ourConversationId;
|
const weAreInvited = conversationId === ourConversationId;
|
||||||
if (weAreInvited) {
|
if (weAreInvited) {
|
||||||
|
@ -400,7 +521,8 @@ export function renderChangeDetail(
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
return renderString('GroupV2--pending-add--one--other--unknown', i18n);
|
return renderString('GroupV2--pending-add--one--other--unknown', i18n);
|
||||||
} else if (detail.type === 'pending-add-many') {
|
}
|
||||||
|
if (detail.type === 'pending-add-many') {
|
||||||
const { count } = detail;
|
const { count } = detail;
|
||||||
|
|
||||||
if (fromYou) {
|
if (fromYou) {
|
||||||
|
@ -417,7 +539,8 @@ export function renderChangeDetail(
|
||||||
return renderString('GroupV2--pending-add--many--unknown', i18n, [
|
return renderString('GroupV2--pending-add--many--unknown', i18n, [
|
||||||
count.toString(),
|
count.toString(),
|
||||||
]);
|
]);
|
||||||
} else if (detail.type === 'pending-remove-one') {
|
}
|
||||||
|
if (detail.type === 'pending-remove-one') {
|
||||||
const { inviter, conversationId } = detail;
|
const { inviter, conversationId } = detail;
|
||||||
const weAreInviter = Boolean(inviter && inviter === ourConversationId);
|
const weAreInviter = Boolean(inviter && inviter === ourConversationId);
|
||||||
const weAreInvited = conversationId === ourConversationId;
|
const weAreInvited = conversationId === ourConversationId;
|
||||||
|
@ -511,7 +634,8 @@ export function renderChangeDetail(
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
return renderString('GroupV2--pending-remove--revoke--one--unknown', i18n);
|
return renderString('GroupV2--pending-remove--revoke--one--unknown', i18n);
|
||||||
} else if (detail.type === 'pending-remove-many') {
|
}
|
||||||
|
if (detail.type === 'pending-remove-many') {
|
||||||
const { count, inviter } = detail;
|
const { count, inviter } = detail;
|
||||||
const weAreInviter = Boolean(inviter && inviter === ourConversationId);
|
const weAreInviter = Boolean(inviter && inviter === ourConversationId);
|
||||||
|
|
||||||
|
@ -590,7 +714,120 @@ export function renderChangeDetail(
|
||||||
i18n,
|
i18n,
|
||||||
[count.toString()]
|
[count.toString()]
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
throw missingCaseError(detail);
|
|
||||||
}
|
}
|
||||||
|
if (detail.type === 'admin-approval-add-one') {
|
||||||
|
const { conversationId } = detail;
|
||||||
|
const weAreJoiner = conversationId === ourConversationId;
|
||||||
|
|
||||||
|
if (weAreJoiner) {
|
||||||
|
return renderString('GroupV2--admin-approval-add-one--you', i18n);
|
||||||
|
}
|
||||||
|
return renderString('GroupV2--admin-approval-add-one--other', i18n, [
|
||||||
|
renderContact(conversationId),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
if (detail.type === 'admin-approval-remove-one') {
|
||||||
|
const { conversationId } = detail;
|
||||||
|
const weAreJoiner = conversationId === ourConversationId;
|
||||||
|
|
||||||
|
if (weAreJoiner) {
|
||||||
|
if (fromYou) {
|
||||||
|
return renderString(
|
||||||
|
'GroupV2--admin-approval-remove-one--you--you',
|
||||||
|
i18n
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return renderString(
|
||||||
|
'GroupV2--admin-approval-remove-one--you--unknown',
|
||||||
|
i18n
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fromYou) {
|
||||||
|
return renderString(
|
||||||
|
'GroupV2--admin-approval-remove-one--other--you',
|
||||||
|
i18n,
|
||||||
|
[renderContact(conversationId)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (from && from === conversationId) {
|
||||||
|
return renderString(
|
||||||
|
'GroupV2--admin-approval-remove-one--other--own',
|
||||||
|
i18n,
|
||||||
|
[renderContact(conversationId)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (from) {
|
||||||
|
return renderString(
|
||||||
|
'GroupV2--admin-approval-remove-one--other--other',
|
||||||
|
i18n,
|
||||||
|
{
|
||||||
|
adminName: renderContact(from),
|
||||||
|
joinerName: renderContact(conversationId),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We default to the user canceling their request, because it is far more likely that
|
||||||
|
// if an admin does the denial, we'll get a change event from them.
|
||||||
|
return renderString(
|
||||||
|
'GroupV2--admin-approval-remove-one--other--own',
|
||||||
|
i18n,
|
||||||
|
[renderContact(conversationId)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (detail.type === 'group-link-add') {
|
||||||
|
const { privilege } = detail;
|
||||||
|
|
||||||
|
if (privilege === AccessControlEnum.ADMINISTRATOR) {
|
||||||
|
if (fromYou) {
|
||||||
|
return renderString('GroupV2--group-link-add--enabled--you', i18n);
|
||||||
|
}
|
||||||
|
if (from) {
|
||||||
|
return renderString('GroupV2--group-link-add--enabled--other', i18n, [
|
||||||
|
renderContact(from),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return renderString('GroupV2--group-link-add--enabled--unknown', i18n);
|
||||||
|
}
|
||||||
|
if (privilege === AccessControlEnum.ANY) {
|
||||||
|
if (fromYou) {
|
||||||
|
return renderString('GroupV2--group-link-add--disabled--you', i18n);
|
||||||
|
}
|
||||||
|
if (from) {
|
||||||
|
return renderString('GroupV2--group-link-add--disabled--other', i18n, [
|
||||||
|
renderContact(from),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return renderString('GroupV2--group-link-add--disabled--unknown', i18n);
|
||||||
|
}
|
||||||
|
window.log.warn(
|
||||||
|
`group-link-add change type, privilege ${privilege} is unknown`
|
||||||
|
);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (detail.type === 'group-link-reset') {
|
||||||
|
if (fromYou) {
|
||||||
|
return renderString('GroupV2--group-link-reset--you', i18n);
|
||||||
|
}
|
||||||
|
if (from) {
|
||||||
|
return renderString('GroupV2--group-link-reset--other', i18n, [
|
||||||
|
renderContact(from),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return renderString('GroupV2--group-link-reset--unknown', i18n);
|
||||||
|
}
|
||||||
|
if (detail.type === 'group-link-remove') {
|
||||||
|
if (fromYou) {
|
||||||
|
return renderString('GroupV2--group-link-remove--you', i18n);
|
||||||
|
}
|
||||||
|
if (from) {
|
||||||
|
return renderString('GroupV2--group-link-remove--other', i18n, [
|
||||||
|
renderContact(from),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return renderString('GroupV2--group-link-remove--unknown', i18n);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw missingCaseError(detail);
|
||||||
}
|
}
|
||||||
|
|
904
ts/groups.ts
904
ts/groups.ts
File diff suppressed because it is too large
Load diff
13
ts/model-types.d.ts
vendored
13
ts/model-types.d.ts
vendored
|
@ -230,6 +230,7 @@ export type ConversationAttributesType = {
|
||||||
accessControl?: {
|
accessControl?: {
|
||||||
attributes: AccessRequiredEnum;
|
attributes: AccessRequiredEnum;
|
||||||
members: AccessRequiredEnum;
|
members: AccessRequiredEnum;
|
||||||
|
addFromInviteLink: AccessRequiredEnum;
|
||||||
};
|
};
|
||||||
avatar?: {
|
avatar?: {
|
||||||
url: string;
|
url: string;
|
||||||
|
@ -239,6 +240,8 @@ export type ConversationAttributesType = {
|
||||||
expireTimer?: number;
|
expireTimer?: number;
|
||||||
membersV2?: Array<GroupV2MemberType>;
|
membersV2?: Array<GroupV2MemberType>;
|
||||||
pendingMembersV2?: Array<GroupV2PendingMemberType>;
|
pendingMembersV2?: Array<GroupV2PendingMemberType>;
|
||||||
|
pendingAdminApprovalV2?: Array<GroupV2PendingAdminApprovalType>;
|
||||||
|
groupInviteLinkPassword?: string;
|
||||||
previousGroupV1Id?: string;
|
previousGroupV1Id?: string;
|
||||||
previousGroupV1Members?: Array<string>;
|
previousGroupV1Members?: Array<string>;
|
||||||
};
|
};
|
||||||
|
@ -247,6 +250,12 @@ export type GroupV2MemberType = {
|
||||||
conversationId: string;
|
conversationId: string;
|
||||||
role: MemberRoleEnum;
|
role: MemberRoleEnum;
|
||||||
joinedAtVersion: number;
|
joinedAtVersion: number;
|
||||||
|
|
||||||
|
// Note that these are temporary flags, generated by applyGroupChange, but eliminated
|
||||||
|
// by applyGroupState. They are used to make our diff-generation more intelligent but
|
||||||
|
// not after that.
|
||||||
|
joinedFromLink?: boolean;
|
||||||
|
approvedByAdmin?: boolean;
|
||||||
};
|
};
|
||||||
export type GroupV2PendingMemberType = {
|
export type GroupV2PendingMemberType = {
|
||||||
addedByUserId?: string;
|
addedByUserId?: string;
|
||||||
|
@ -254,6 +263,10 @@ export type GroupV2PendingMemberType = {
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
role: MemberRoleEnum;
|
role: MemberRoleEnum;
|
||||||
};
|
};
|
||||||
|
export type GroupV2PendingAdminApprovalType = {
|
||||||
|
conversationId: string;
|
||||||
|
timestamp: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type VerificationOptions = {
|
export type VerificationOptions = {
|
||||||
key?: null | ArrayBuffer;
|
key?: null | ArrayBuffer;
|
||||||
|
|
|
@ -37,6 +37,12 @@ const directConsole = {
|
||||||
|
|
||||||
const logger = createLogger({
|
const logger = createLogger({
|
||||||
logger: directConsole,
|
logger: directConsole,
|
||||||
|
predicate: (_getState, action) => {
|
||||||
|
if (action.type === 'network/CHECK_NETWORK_STATUS') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const middlewareList = [
|
const middlewareList = [
|
||||||
|
|
94
ts/textsecure.d.ts
vendored
94
ts/textsecure.d.ts
vendored
|
@ -169,13 +169,15 @@ type DeviceNameProtobufTypes = {
|
||||||
type GroupsProtobufTypes = {
|
type GroupsProtobufTypes = {
|
||||||
AvatarUploadAttributes: typeof AvatarUploadAttributesClass;
|
AvatarUploadAttributes: typeof AvatarUploadAttributesClass;
|
||||||
Member: typeof MemberClass;
|
Member: typeof MemberClass;
|
||||||
PendingMember: typeof PendingMemberClass;
|
MemberPendingProfileKey: typeof MemberPendingProfileKeyClass;
|
||||||
|
MemberPendingAdminApproval: typeof MemberPendingAdminApprovalClass;
|
||||||
AccessControl: typeof AccessControlClass;
|
AccessControl: typeof AccessControlClass;
|
||||||
Group: typeof GroupClass;
|
Group: typeof GroupClass;
|
||||||
GroupChange: typeof GroupChangeClass;
|
GroupChange: typeof GroupChangeClass;
|
||||||
GroupChanges: typeof GroupChangesClass;
|
GroupChanges: typeof GroupChangesClass;
|
||||||
GroupAttributeBlob: typeof GroupAttributeBlobClass;
|
GroupAttributeBlob: typeof GroupAttributeBlobClass;
|
||||||
GroupExternalCredential: typeof GroupExternalCredentialClass;
|
GroupExternalCredential: typeof GroupExternalCredentialClass;
|
||||||
|
GroupInviteLink: typeof GroupInviteLinkClass;
|
||||||
};
|
};
|
||||||
|
|
||||||
type SignalServiceProtobufTypes = {
|
type SignalServiceProtobufTypes = {
|
||||||
|
@ -227,7 +229,7 @@ type ProtobufCollectionType = {
|
||||||
// with a type that the app can use. Being more rigorous with these
|
// with a type that the app can use. Being more rigorous with these
|
||||||
// types would require code changes, out of scope for now.
|
// types would require code changes, out of scope for now.
|
||||||
export type ProtoBinaryType = any;
|
export type ProtoBinaryType = any;
|
||||||
type ProtoBigNumberType = any;
|
export type ProtoBigNumberType = any;
|
||||||
|
|
||||||
// Groups.proto
|
// Groups.proto
|
||||||
|
|
||||||
|
@ -272,17 +274,29 @@ export declare namespace MemberClass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export declare class PendingMemberClass {
|
export declare class MemberPendingProfileKeyClass {
|
||||||
static decode: (
|
static decode: (
|
||||||
data: ArrayBuffer | ByteBufferClass,
|
data: ArrayBuffer | ByteBufferClass,
|
||||||
encoding?: string
|
encoding?: string
|
||||||
) => PendingMemberClass;
|
) => MemberPendingProfileKeyClass;
|
||||||
|
|
||||||
member?: MemberClass;
|
member?: MemberClass;
|
||||||
addedByUserId?: ProtoBinaryType;
|
addedByUserId?: ProtoBinaryType;
|
||||||
timestamp?: ProtoBigNumberType;
|
timestamp?: ProtoBigNumberType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export declare class MemberPendingAdminApprovalClass {
|
||||||
|
static decode: (
|
||||||
|
data: ArrayBuffer | ByteBufferClass,
|
||||||
|
encoding?: string
|
||||||
|
) => MemberPendingProfileKeyClass;
|
||||||
|
|
||||||
|
userId?: ProtoBinaryType;
|
||||||
|
profileKey?: ProtoBinaryType;
|
||||||
|
presentation?: ProtoBinaryType;
|
||||||
|
timestamp?: ProtoBigNumberType;
|
||||||
|
}
|
||||||
|
|
||||||
export declare class AccessControlClass {
|
export declare class AccessControlClass {
|
||||||
static decode: (
|
static decode: (
|
||||||
data: ArrayBuffer | ByteBufferClass,
|
data: ArrayBuffer | ByteBufferClass,
|
||||||
|
@ -291,6 +305,7 @@ export declare class AccessControlClass {
|
||||||
|
|
||||||
attributes?: AccessRequiredEnum;
|
attributes?: AccessRequiredEnum;
|
||||||
members?: AccessRequiredEnum;
|
members?: AccessRequiredEnum;
|
||||||
|
addFromInviteLink?: AccessRequiredEnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AccessRequiredEnum = number;
|
export type AccessRequiredEnum = number;
|
||||||
|
@ -298,10 +313,11 @@ export type AccessRequiredEnum = number;
|
||||||
// Note: we need to use namespaces to express nested classes in Typescript
|
// Note: we need to use namespaces to express nested classes in Typescript
|
||||||
export declare namespace AccessControlClass {
|
export declare namespace AccessControlClass {
|
||||||
class AccessRequired {
|
class AccessRequired {
|
||||||
static ANY: number;
|
|
||||||
static UNKNOWN: number;
|
static UNKNOWN: number;
|
||||||
|
static ANY: number;
|
||||||
static MEMBER: number;
|
static MEMBER: number;
|
||||||
static ADMINISTRATOR: number;
|
static ADMINISTRATOR: number;
|
||||||
|
static UNSATISFIABLE: number;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,7 +335,9 @@ export declare class GroupClass {
|
||||||
accessControl?: AccessControlClass;
|
accessControl?: AccessControlClass;
|
||||||
version?: number;
|
version?: number;
|
||||||
members?: Array<MemberClass>;
|
members?: Array<MemberClass>;
|
||||||
pendingMembers?: Array<PendingMemberClass>;
|
membersPendingProfileKey?: Array<MemberPendingProfileKeyClass>;
|
||||||
|
membersPendingAdminApproval?: Array<MemberPendingAdminApprovalClass>;
|
||||||
|
inviteLinkPassword?: ProtoBinaryType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export declare class GroupChangeClass {
|
export declare class GroupChangeClass {
|
||||||
|
@ -351,18 +369,31 @@ export declare namespace GroupChangeClass {
|
||||||
modifyMemberProfileKeys?: Array<
|
modifyMemberProfileKeys?: Array<
|
||||||
GroupChangeClass.Actions.ModifyMemberProfileKeyAction
|
GroupChangeClass.Actions.ModifyMemberProfileKeyAction
|
||||||
>;
|
>;
|
||||||
addPendingMembers?: Array<GroupChangeClass.Actions.AddPendingMemberAction>;
|
addPendingMembers?: Array<
|
||||||
|
GroupChangeClass.Actions.AddMemberPendingProfileKeyAction
|
||||||
|
>;
|
||||||
deletePendingMembers?: Array<
|
deletePendingMembers?: Array<
|
||||||
GroupChangeClass.Actions.DeletePendingMemberAction
|
GroupChangeClass.Actions.DeleteMemberPendingProfileKeyAction
|
||||||
>;
|
>;
|
||||||
promotePendingMembers?: Array<
|
promotePendingMembers?: Array<
|
||||||
GroupChangeClass.Actions.PromotePendingMemberAction
|
GroupChangeClass.Actions.PromoteMemberPendingProfileKeyAction
|
||||||
>;
|
>;
|
||||||
modifyTitle?: GroupChangeClass.Actions.ModifyTitleAction;
|
modifyTitle?: GroupChangeClass.Actions.ModifyTitleAction;
|
||||||
modifyAvatar?: GroupChangeClass.Actions.ModifyAvatarAction;
|
modifyAvatar?: GroupChangeClass.Actions.ModifyAvatarAction;
|
||||||
modifyDisappearingMessagesTimer?: GroupChangeClass.Actions.ModifyDisappearingMessagesTimerAction;
|
modifyDisappearingMessagesTimer?: GroupChangeClass.Actions.ModifyDisappearingMessagesTimerAction;
|
||||||
modifyAttributesAccess?: GroupChangeClass.Actions.ModifyAttributesAccessControlAction;
|
modifyAttributesAccess?: GroupChangeClass.Actions.ModifyAttributesAccessControlAction;
|
||||||
modifyMemberAccess?: GroupChangeClass.Actions.ModifyMembersAccessControlAction;
|
modifyMemberAccess?: GroupChangeClass.Actions.ModifyMembersAccessControlAction;
|
||||||
|
modifyAddFromInviteLinkAccess?: GroupChangeClass.Actions.ModifyAddFromInviteLinkAccessControlAction;
|
||||||
|
addMemberPendingAdminApprovals?: Array<
|
||||||
|
GroupChangeClass.Actions.AddMemberPendingAdminApprovalAction
|
||||||
|
>;
|
||||||
|
deleteMemberPendingAdminApprovals?: Array<
|
||||||
|
GroupChangeClass.Actions.DeleteMemberPendingAdminApprovalAction
|
||||||
|
>;
|
||||||
|
promoteMemberPendingAdminApprovals?: Array<
|
||||||
|
GroupChangeClass.Actions.PromoteMemberPendingAdminApprovalAction
|
||||||
|
>;
|
||||||
|
modifyInviteLinkPassword?: GroupChangeClass.Actions.ModifyInviteLinkPasswordAction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,6 +401,7 @@ export declare namespace GroupChangeClass {
|
||||||
export declare namespace GroupChangeClass.Actions {
|
export declare namespace GroupChangeClass.Actions {
|
||||||
class AddMemberAction {
|
class AddMemberAction {
|
||||||
added?: MemberClass;
|
added?: MemberClass;
|
||||||
|
joinFromInviteLink?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
class DeleteMemberAction {
|
class DeleteMemberAction {
|
||||||
|
@ -389,15 +421,15 @@ export declare namespace GroupChangeClass.Actions {
|
||||||
uuid: string;
|
uuid: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
class AddPendingMemberAction {
|
class AddMemberPendingProfileKeyAction {
|
||||||
added?: PendingMemberClass;
|
added?: MemberPendingProfileKeyClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
class DeletePendingMemberAction {
|
class DeleteMemberPendingProfileKeyAction {
|
||||||
deletedUserId?: ProtoBinaryType;
|
deletedUserId?: ProtoBinaryType;
|
||||||
}
|
}
|
||||||
|
|
||||||
class PromotePendingMemberAction {
|
class PromoteMemberPendingProfileKeyAction {
|
||||||
presentation?: ProtoBinaryType;
|
presentation?: ProtoBinaryType;
|
||||||
|
|
||||||
// The result of decryption
|
// The result of decryption
|
||||||
|
@ -405,6 +437,19 @@ export declare namespace GroupChangeClass.Actions {
|
||||||
uuid: string;
|
uuid: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AddMemberPendingAdminApprovalAction {
|
||||||
|
added?: MemberPendingAdminApprovalClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
class DeleteMemberPendingAdminApprovalAction {
|
||||||
|
deletedUserId?: ProtoBinaryType;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PromoteMemberPendingAdminApprovalAction {
|
||||||
|
userId?: ProtoBinaryType;
|
||||||
|
role?: MemberRoleEnum;
|
||||||
|
}
|
||||||
|
|
||||||
class ModifyTitleAction {
|
class ModifyTitleAction {
|
||||||
title?: ProtoBinaryType;
|
title?: ProtoBinaryType;
|
||||||
}
|
}
|
||||||
|
@ -424,6 +469,14 @@ export declare namespace GroupChangeClass.Actions {
|
||||||
class ModifyMembersAccessControlAction {
|
class ModifyMembersAccessControlAction {
|
||||||
membersAccess?: AccessRequiredEnum;
|
membersAccess?: AccessRequiredEnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ModifyAddFromInviteLinkAccessControlAction {
|
||||||
|
addFromInviteLinkAccess?: AccessRequiredEnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ModifyInviteLinkPasswordAction {
|
||||||
|
inviteLinkPassword?: ProtoBinaryType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export declare class GroupChangesClass {
|
export declare class GroupChangesClass {
|
||||||
|
@ -452,6 +505,21 @@ export declare class GroupExternalCredentialClass {
|
||||||
token?: string;
|
token?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export declare class GroupInviteLinkClass {
|
||||||
|
v1Contents?: GroupInviteLinkClass.GroupInviteLinkContentsV1;
|
||||||
|
|
||||||
|
// Note: this isn't part of the proto, but our protobuf library tells us which
|
||||||
|
// field has been set with this prop.
|
||||||
|
contents?: 'v1Contents';
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare namespace GroupInviteLinkClass {
|
||||||
|
class GroupInviteLinkContentsV1 {
|
||||||
|
groupMasterKey?: ProtoBinaryType;
|
||||||
|
inviteLinkPassword?: ProtoBinaryType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export declare class GroupAttributeBlobClass {
|
export declare class GroupAttributeBlobClass {
|
||||||
static decode: (
|
static decode: (
|
||||||
data: ArrayBuffer | ByteBufferClass,
|
data: ArrayBuffer | ByteBufferClass,
|
||||||
|
|
3
ts/window.d.ts
vendored
3
ts/window.d.ts
vendored
|
@ -480,6 +480,9 @@ declare global {
|
||||||
|
|
||||||
// Flags
|
// Flags
|
||||||
isGroupCallingEnabled: () => boolean;
|
isGroupCallingEnabled: () => boolean;
|
||||||
|
GV2_ENABLE_SINGLE_CHANGE_PROCESSING: boolean;
|
||||||
|
GV2_ENABLE_CHANGE_PROCESSING: boolean;
|
||||||
|
GV2_ENABLE_STATE_PROCESSING: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Error {
|
interface Error {
|
||||||
|
|
Loading…
Reference in a new issue