From d85a0bb0629cbf36e633e75ae1bc959274f2855d Mon Sep 17 00:00:00 2001 From: Ian Macdonald Date: Tue, 17 Jan 2023 19:04:09 +0100 Subject: [PATCH 01/97] Implement server-wide open group user bans and unbans. This adds to Session the ability to ban a user not just from a single group, but from an entire SOGS. To successfully ban (or unban) a user across a whole server, the executor must be a global moderator of the SOGS instance. When banning a user, the global moderator may opt to also remove all of the user's messages from the server. This requires PySOGS > 0.3.7 to allow the simultaneous deletion of messages from multiple groups. See oxen-io/session-pysogs@2c8e4f1535bbd2cc676fa46914c691d2332cb41f. This has been tested with Session 1.10.4 in combination with `open.getsession.org` and `sog.caliban.org`, both of which have been updated to support server-wide banning. --- _locales/en/messages.json | 3 + .../message-content/MessageContextMenu.tsx | 12 ++ ts/components/dialog/BanOrUnbanUserDialog.tsx | 133 +++++++++++++++++- ts/components/dialog/ModalContainer.tsx | 5 +- ts/components/menu/ConversationHeaderMenu.tsx | 4 + .../menu/ConversationListItemContextMenu.tsx | 4 + ts/components/menu/Menu.tsx | 48 +++++++ ts/interactions/conversationInteractions.ts | 13 ++ ts/interactions/messageInteractions.ts | 47 ++++++- .../open_group_api/sogsv3/sogsV3BanUnban.ts | 60 ++++++++ .../open_group_api/sogsv3/sogsV3BatchPoll.ts | 29 ++++ ts/state/ducks/modalDialog.tsx | 11 ++ ts/state/selectors/modal.ts | 6 + ts/types/LocalizerKeys.ts | 3 + 14 files changed, 369 insertions(+), 9 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index beeefcc030..48024e3ae6 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -247,10 +247,13 @@ "blockedSettingsTitle": "Blocked Contacts", "conversationsSettingsTitle": "Conversations", "unbanUser": "Unban User", + "serverUnbanUser": "Unban User from Server", "userUnbanned": "User unbanned successfully", "userUnbanFailed": "Unban failed!", "banUser": "Ban User", "banUserAndDeleteAll": "Ban and Delete All", + "serverBanUser": "Ban User from Server", + "serverBanUserAndDeleteAll": "Ban from Server and Delete All", "userBanned": "Banned successfully", "userBanFailed": "Ban failed!", "leaveGroup": "Leave Group", diff --git a/ts/components/conversation/message/message-content/MessageContextMenu.tsx b/ts/components/conversation/message/message-content/MessageContextMenu.tsx index 8a1c31248e..8fb3f2cf8a 100644 --- a/ts/components/conversation/message/message-content/MessageContextMenu.tsx +++ b/ts/components/conversation/message/message-content/MessageContextMenu.tsx @@ -210,6 +210,14 @@ export const MessageContextMenu = (props: Props) => { MessageInteraction.unbanUser(sender, convoId); }, [sender, convoId]); + const onServerBan = useCallback(() => { + MessageInteraction.serverBanUser(sender, convoId); + }, [sender, convoId]); + + const onServerUnban = useCallback(() => { + MessageInteraction.serverUnbanUser(sender, convoId); + }, [sender, convoId]); + const onSelect = useCallback(() => { dispatch(toggleSelectedMessageId(messageId)); }, [messageId]); @@ -334,6 +342,10 @@ export const MessageContextMenu = (props: Props) => { {weAreAdmin && isPublic ? ( {window.i18n('unbanUser')} ) : null} + {weAreAdmin && isPublic ? {window.i18n('serverBanUser')} : null} + {weAreAdmin && isPublic ? ( + {window.i18n('serverUnbanUser')} + ) : null} {weAreAdmin && isPublic && !isSenderAdmin ? ( {window.i18n('addAsModerator')} ) : null} diff --git a/ts/components/dialog/BanOrUnbanUserDialog.tsx b/ts/components/dialog/BanOrUnbanUserDialog.tsx index 02ed38b939..745a44380a 100644 --- a/ts/components/dialog/BanOrUnbanUserDialog.tsx +++ b/ts/components/dialog/BanOrUnbanUserDialog.tsx @@ -3,7 +3,11 @@ import { PubKey } from '../../session/types'; import { ToastUtils } from '../../session/utils'; import { Flex } from '../basic/Flex'; import { useDispatch, useSelector } from 'react-redux'; -import { BanType, updateBanOrUnbanUserModal } from '../../state/ducks/modalDialog'; +import { + BanType, + updateBanOrUnbanUserModal, + updateServerBanOrUnbanUserModal +} from '../../state/ducks/modalDialog'; import { SpacerSM } from '../basic/Text'; import { getConversationController } from '../../session/conversations/ConversationController'; import { SessionWrapperModal } from '../SessionWrapperModal'; @@ -14,7 +18,9 @@ import { useFocusMount } from '../../hooks/useFocusMount'; import { useConversationPropsById } from '../../hooks/useParamSelector'; import { sogsV3BanUser, - sogsV3UnbanUser, + sogsV3ServerBanUser, + sogsV3ServerUnbanUser, + sogsV3UnbanUser } from '../../session/apis/open_group_api/sogsv3/sogsV3BanUnban'; import { SessionHeaderSearchInput } from '../SessionHeaderSearchInput'; import { isDarkTheme } from '../../state/selectors/theme'; @@ -25,7 +31,8 @@ async function banOrUnBanUserCall( convo: ConversationModel, textValue: string, banType: BanType, - deleteAll: boolean + deleteAll: boolean, + isGlobal: boolean ) { // if we don't have valid data entered by the user const pubkey = PubKey.from(textValue); @@ -39,8 +46,12 @@ async function banOrUnBanUserCall( const roomInfos = convo.toOpenGroupV2(); const isChangeApplied = banType === 'ban' - ? await sogsV3BanUser(pubkey, roomInfos, deleteAll) - : await sogsV3UnbanUser(pubkey, roomInfos); + ? isGlobal + ? await sogsV3ServerBanUser(pubkey, roomInfos, deleteAll) + : await sogsV3BanUser(pubkey, roomInfos, deleteAll) + : isGlobal + ? await sogsV3ServerUnbanUser(pubkey, roomInfos) + : await sogsV3UnbanUser(pubkey, roomInfos); if (!isChangeApplied) { window?.log?.warn(`failed to ${banType} user: ${isChangeApplied}`); @@ -92,7 +103,7 @@ export const BanOrUnBanUserDialog = (props: { window?.log?.info(`asked to ${banType} user: ${castedPubkey}, banAndDeleteAll:${deleteAll}`); setInProgress(true); - const isBanned = await banOrUnBanUserCall(convo, castedPubkey, banType, deleteAll); + const isBanned = await banOrUnBanUserCall(convo, castedPubkey, banType, deleteAll, false); if (isBanned) { // clear input box setInputBoxValue(''); @@ -163,4 +174,112 @@ export const BanOrUnBanUserDialog = (props: { ); -}; +} + +// FIXME: Refactor with BanOrUnBanUserDialog(). +export const ServerBanOrUnBanUserDialog = (props: { + conversationId: string; + banType: BanType; + pubkey?: string; +}) => { + const { conversationId, banType, pubkey } = props; + const { i18n } = window; + const isBan = banType === 'ban'; + const dispatch = useDispatch(); + const darkMode = useSelector(isDarkTheme); + const convo = getConversationController().get(conversationId); + const inputRef = useRef(null); + + useFocusMount(inputRef, true); + const wasGivenAPubkey = Boolean(pubkey?.length); + const [inputBoxValue, setInputBoxValue] = useState(''); + const [inProgress, setInProgress] = useState(false); + + const sourceConvoProps = useConversationPropsById(pubkey); + + const inputTextToDisplay = + wasGivenAPubkey && sourceConvoProps + ? `${sourceConvoProps.displayNameInProfile} ${PubKey.shorten(sourceConvoProps.id)}` + : undefined; + + /** + * Ban or Unban a user from an open group + * @param deleteAll Delete all messages for that user in the group (only works with ban) + */ + const banOrUnBanUser = async (deleteAll: boolean = false) => { + const castedPubkey = pubkey?.length ? pubkey : inputBoxValue; + + window?.log?.info(`asked to ${banType} user server-wide: ${castedPubkey}, banAndDeleteAll:${deleteAll}`); + setInProgress(true); + const isBanned = await banOrUnBanUserCall(convo, castedPubkey, banType, deleteAll, true); + if (isBanned) { + // clear input box + setInputBoxValue(''); + if (wasGivenAPubkey) { + dispatch(updateServerBanOrUnbanUserModal(null)); + } + } + + setInProgress(false); + }; + + const serverHost = new window.URL(convo.toOpenGroupV2().serverUrl).host; + const title = `${isBan ? window.i18n('banUser') : window.i18n('unbanUser')} @ ${serverHost}`; + + const onPubkeyBoxChanges = (e: React.ChangeEvent) => { + setInputBoxValue(e.target.value?.trim() || ''); + }; + + /** + * Starts procedure for banning/unbanning user and all their messages using dialog + */ + const startBanAndDeleteAllSequence = async () => { + await banOrUnBanUser(true); + }; + + const buttonText = isBan ? i18n('banUser') : i18n('unbanUser'); + + return ( + { + dispatch(updateServerBanOrUnbanUserModal(null)); + }} + > + + + + + {isBan && ( + <> + + + + )} + + + + + ); +} diff --git a/ts/components/dialog/ModalContainer.tsx b/ts/components/dialog/ModalContainer.tsx index d54bbe7e81..8d5ce620f3 100644 --- a/ts/components/dialog/ModalContainer.tsx +++ b/ts/components/dialog/ModalContainer.tsx @@ -14,6 +14,7 @@ import { getReactListDialog, getRecoveryPhraseDialog, getRemoveModeratorsModal, + getServerBanOrUnbanUserModalState, getSessionPasswordDialog, getUpdateGroupMembersModal, getUpdateGroupNameModal, @@ -33,7 +34,7 @@ import { RemoveModeratorsDialog } from './ModeratorsRemoveDialog'; import { UpdateGroupMembersDialog } from './UpdateGroupMembersDialog'; import { UpdateGroupNameDialog } from './UpdateGroupNameDialog'; import { SessionNicknameDialog } from './SessionNicknameDialog'; -import { BanOrUnBanUserDialog } from './BanOrUnbanUserDialog'; +import { BanOrUnBanUserDialog, ServerBanOrUnBanUserDialog } from './BanOrUnbanUserDialog'; import { ReactListModal } from './ReactListModal'; import { ReactClearAllModal } from './ReactClearAllModal'; @@ -53,12 +54,14 @@ export const ModalContainer = () => { const sessionPasswordModalState = useSelector(getSessionPasswordDialog); const deleteAccountModalState = useSelector(getDeleteAccountModalState); const banOrUnbanUserModalState = useSelector(getBanOrUnbanUserModalState); + const serverBanOrUnbanUserModalState = useSelector(getServerBanOrUnbanUserModalState); const reactListModalState = useSelector(getReactListDialog); const reactClearAllModalState = useSelector(getReactClearAllDialog); return ( <> {banOrUnbanUserModalState && } + {serverBanOrUnbanUserModalState && } {inviteModalState && } {addModeratorsModalState && } {removeModeratorsModalState && } diff --git a/ts/components/menu/ConversationHeaderMenu.tsx b/ts/components/menu/ConversationHeaderMenu.tsx index 6ee07b4b3e..25e8730cea 100644 --- a/ts/components/menu/ConversationHeaderMenu.tsx +++ b/ts/components/menu/ConversationHeaderMenu.tsx @@ -18,6 +18,8 @@ import { NotificationForConvoMenuItem, PinConversationMenuItem, RemoveModeratorsMenuItem, + ServerBanMenuItem, + ServerUnbanMenuItem, ShowUserDetailsMenuItem, UnbanMenuItem, UpdateGroupNameMenuItem, @@ -60,6 +62,8 @@ export const ConversationHeaderMenu = (props: PropsConversationHeaderMenu) => { + + diff --git a/ts/components/menu/ConversationListItemContextMenu.tsx b/ts/components/menu/ConversationListItemContextMenu.tsx index 7f91d0b629..5cad968085 100644 --- a/ts/components/menu/ConversationListItemContextMenu.tsx +++ b/ts/components/menu/ConversationListItemContextMenu.tsx @@ -17,6 +17,8 @@ import { MarkAllReadMenuItem, NotificationForConvoMenuItem, PinConversationMenuItem, + ServerBanMenuItem, + ServerUnbanMenuItem, ShowUserDetailsMenuItem, UnbanMenuItem, } from './Menu'; @@ -44,6 +46,8 @@ const ConversationListItemContextMenu = (props: PropsContextConversationItem) => + + diff --git a/ts/components/menu/Menu.tsx b/ts/components/menu/Menu.tsx index 6c0fc05cc7..77c652982c 100644 --- a/ts/components/menu/Menu.tsx +++ b/ts/components/menu/Menu.tsx @@ -33,6 +33,8 @@ import { showInviteContactByConvoId, showLeaveGroupByConvoId, showRemoveModeratorsByConvoId, + showServerBanUserByConvoId, + showServerUnbanUserByConvoId, showUnbanUserByConvoId, showUpdateGroupNameByConvoId, unblockConvoById, @@ -116,6 +118,14 @@ const showBanUser = (weAreAdmin: boolean, isPublic: boolean, isKickedFromGroup: return !isKickedFromGroup && weAreAdmin && isPublic; }; +const showServerUnbanUser = (weAreAdmin: boolean, isPublic: boolean) => { + return weAreAdmin && isPublic; +}; + +const showServerBanUser = (weAreAdmin: boolean, isPublic: boolean) => { + return weAreAdmin && isPublic; +}; + function showAddModerators( weAreAdmin: boolean, isPublic: boolean, @@ -387,6 +397,44 @@ export const BanMenuItem = (): JSX.Element | null => { return null; }; +export const ServerUnbanMenuItem = (): JSX.Element | null => { + const convoId = useContext(ContextConversationId); + const isPublic = useIsPublic(convoId); + const weAreAdmin = useWeAreAdmin(convoId); + + if (showServerUnbanUser(weAreAdmin, isPublic)) { + return ( + { + showServerUnbanUserByConvoId(convoId); + }} + > + {window.i18n('serverUnbanUser')} + + ); + } + return null; +}; + +export const ServerBanMenuItem = (): JSX.Element | null => { + const convoId = useContext(ContextConversationId); + const isPublic = useIsPublic(convoId); + const weAreAdmin = useWeAreAdmin(convoId); + + if (showServerBanUser(weAreAdmin, isPublic)) { + return ( + { + showServerBanUserByConvoId(convoId); + }} + > + {window.i18n('serverBanUser')} + + ); + } + return null; +}; + export const CopyMenuItem = (): JSX.Element | null => { const convoId = useContext(ContextConversationId); const isPublic = useIsPublic(convoId); diff --git a/ts/interactions/conversationInteractions.ts b/ts/interactions/conversationInteractions.ts index 6b4cd28983..e09782e5ac 100644 --- a/ts/interactions/conversationInteractions.ts +++ b/ts/interactions/conversationInteractions.ts @@ -23,6 +23,7 @@ import { updateGroupNameModal, updateInviteContactModal, updateRemoveModeratorsModal, + updateServerBanOrUnbanUserModal } from '../state/ducks/modalDialog'; import { Data, hasLinkPreviewPopupBeenDisplayed, lastAvatarUploadTimestamp } from '../data/data'; import { quoteMessage, resetConversationExternal } from '../state/ducks/conversations'; @@ -275,6 +276,18 @@ export function showUnbanUserByConvoId(conversationId: string, pubkey?: string) ); } +export function showServerBanUserByConvoId(conversationId: string, pubkey?: string) { + window.inboxStore?.dispatch( + updateServerBanOrUnbanUserModal({ banType: 'ban', conversationId, pubkey }) + ); +} + +export function showServerUnbanUserByConvoId(conversationId: string, pubkey?: string) { + window.inboxStore?.dispatch( + updateServerBanOrUnbanUserModal({ banType: 'unban', conversationId, pubkey }) + ); +} + export async function markAllReadByConvoId(conversationId: string) { const conversation = getConversationController().get(conversationId); perfStart(`markAllReadByConvoId-${conversationId}`); diff --git a/ts/interactions/messageInteractions.ts b/ts/interactions/messageInteractions.ts index 76cfccec90..ecc121351c 100644 --- a/ts/interactions/messageInteractions.ts +++ b/ts/interactions/messageInteractions.ts @@ -12,7 +12,11 @@ import { getConversationController } from '../session/conversations'; import { PubKey } from '../session/types'; import { ToastUtils } from '../session/utils'; -import { updateBanOrUnbanUserModal, updateConfirmModal } from '../state/ducks/modalDialog'; +import { + updateBanOrUnbanUserModal, + updateConfirmModal, + updateServerBanOrUnbanUserModal +} from '../state/ducks/modalDialog'; export function banUser(userToBan: string, conversationId: string) { let pubKeyToBan: PubKey; @@ -59,6 +63,47 @@ export function unbanUser(userToUnBan: string, conversationId: string) { ); } +export function serverBanUser(userToBan: string, conversationId: string) { + let pubKeyToBan: PubKey; + try { + pubKeyToBan = PubKey.cast(userToBan); + } catch (e) { + window?.log?.warn(e); + ToastUtils.pushUserBanFailure(); + return; + } + if (!isOpenGroupV2(conversationId)) { + window.log.warn(`Conversation ${conversationId} is not an open group`); + ToastUtils.pushUserBanFailure(); + + return; + } + + window.inboxStore?.dispatch( + updateServerBanOrUnbanUserModal({ banType: 'ban', conversationId, pubkey: pubKeyToBan.key }) + ); +} + +export function serverUnbanUser(userToUnBan: string, conversationId: string) { + let pubKeyToUnban: PubKey; + try { + pubKeyToUnban = PubKey.cast(userToUnBan); + } catch (e) { + window?.log?.warn(e); + ToastUtils.pushUserBanFailure(); + return; + } + if (!isOpenGroupV2(conversationId)) { + window.log.warn(`Conversation ${conversationId} is not an open group`); + ToastUtils.pushUserUnbanFailure(); + + return; + } + window.inboxStore?.dispatch( + updateServerBanOrUnbanUserModal({ banType: 'unban', conversationId, pubkey: pubKeyToUnban.key }) + ); +} + export function copyBodyToClipboard(body?: string | null) { window.clipboard.writeText(body); diff --git a/ts/session/apis/open_group_api/sogsv3/sogsV3BanUnban.ts b/ts/session/apis/open_group_api/sogsv3/sogsV3BanUnban.ts index 680d583dae..295407d555 100644 --- a/ts/session/apis/open_group_api/sogsv3/sogsV3BanUnban.ts +++ b/ts/session/apis/open_group_api/sogsv3/sogsV3BanUnban.ts @@ -15,6 +15,7 @@ export const sogsV3BanUser = async ( sessionId: userToBan.key, roomId: roomInfos.roomId, type: 'ban', + isGlobal: false }, }, ]; @@ -51,10 +52,69 @@ export const sogsV3UnbanUser = async ( sessionId: userToBan.key, roomId: roomInfos.roomId, type: 'unban', + isGlobal: false }, }, ], 'batch' ); return batchFirstSubIsSuccess(batchSendResponse); +} + +export const sogsV3ServerBanUser = async ( + userToBan: PubKey, + roomInfos: OpenGroupRequestCommonType, + deleteAllMessages: boolean, +): Promise => { + const sequence: Array = [ + { + type: 'banUnbanUser', + banUnbanUser: { + sessionId: userToBan.key, + roomId: roomInfos.roomId, + type: 'ban', + isGlobal: true + }, + }, + ]; + + if (deleteAllMessages) { + sequence.push({ + type: 'deleteAllUserPosts', + deleteAllUserPosts: { sessionId: userToBan.key }, + }); + } + + const batchSendResponse = await sogsBatchSend( + roomInfos.serverUrl, + new Set([roomInfos.roomId]), + new AbortController().signal, + sequence, + 'sequence' + ); + return batchFirstSubIsSuccess(batchSendResponse); }; + +export const sogsV3ServerUnbanUser = async ( + userToBan: PubKey, + roomInfos: OpenGroupRequestCommonType +): Promise => { + const batchSendResponse = await sogsBatchSend( + roomInfos.serverUrl, + new Set([roomInfos.roomId]), + new AbortController().signal, + [ + { + type: 'banUnbanUser', + banUnbanUser: { + sessionId: userToBan.key, + roomId: roomInfos.roomId, + type: 'unban', + isGlobal: true + }, + }, + ], + 'batch' + ); + return batchFirstSubIsSuccess(batchSendResponse); +} diff --git a/ts/session/apis/open_group_api/sogsv3/sogsV3BatchPoll.ts b/ts/session/apis/open_group_api/sogsv3/sogsV3BatchPoll.ts index 7461b16f4e..69d77a43bf 100644 --- a/ts/session/apis/open_group_api/sogsv3/sogsV3BatchPoll.ts +++ b/ts/session/apis/open_group_api/sogsv3/sogsV3BatchPoll.ts @@ -179,6 +179,7 @@ export type SubRequestBanUnbanUserType = { type: 'ban' | 'unban'; sessionId: string; // can be blinded id or not roomId: string; + isGlobal: boolean; }; }; @@ -190,6 +191,13 @@ export type SubRequestDeleteAllUserPostsType = { }; }; +export type SubRequestDeleteAllUserServerPostsType = { + type: 'deleteAllUserPosts'; + deleteAllUserPosts: { + sessionId: string; // can be blinded id or not + }; +}; + export type SubRequestUpdateRoomType = { type: 'updateRoom'; updateRoom: { @@ -218,6 +226,7 @@ export type OpenGroupBatchRow = | SubRequestAddRemoveModeratorType | SubRequestBanUnbanUserType | SubRequestDeleteAllUserPostsType + | SubRequestDeleteAllUserServerPostsType | SubRequestUpdateRoomType | SubRequestDeleteReactionType; @@ -225,6 +234,7 @@ export type OpenGroupBatchRow = * * @param options Array of subrequest options to be made. */ +// tslint:disable-next-line: cyclomatic-complexity const makeBatchRequestPayload = ( options: OpenGroupBatchRow ): BatchSubRequest | Array | null => { @@ -295,6 +305,20 @@ const makeBatchRequestPayload = ( })); case 'banUnbanUser': const isBan = Boolean(options.banUnbanUser.type === 'ban'); + const isGlobal = options.banUnbanUser.isGlobal; + window?.log?.info(`BAN: ${options.banUnbanUser.sessionId}, global: ${options.banUnbanUser.isGlobal}`); + if (isGlobal) { + // Issue server-wide (un)ban. + return { + method: 'POST', + path: `/user/${options.banUnbanUser.sessionId}/${isBan ? 'ban' : 'unban'}`, + json: { + global: true, + // timeout: null, // for now we do not support the timeout argument + }, + } + } + // Issue room-wide (un)ban. return { method: 'POST', path: `/user/${options.banUnbanUser.sessionId}/${isBan ? 'ban' : 'unban'}`, @@ -311,6 +335,11 @@ const makeBatchRequestPayload = ( method: 'DELETE', path: `/room/${options.deleteAllPosts.roomId}/all/${options.deleteAllPosts.sessionId}`, }; + case 'deleteAllUserPosts': + return { + method: 'DELETE', + path: `/rooms/all/${options.deleteAllUserPosts.sessionId}`, + }; case 'updateRoom': return { method: 'PUT', diff --git a/ts/state/ducks/modalDialog.tsx b/ts/state/ducks/modalDialog.tsx index ea8428b703..4a9213b9b5 100644 --- a/ts/state/ducks/modalDialog.tsx +++ b/ts/state/ducks/modalDialog.tsx @@ -10,6 +10,11 @@ export type BanOrUnbanUserModalState = { banType: BanType; pubkey?: string; } | null; +export type ServerBanOrUnbanUserModalState = { + conversationId: string; + banType: BanType; + pubkey?: string; +} | null; export type AddModeratorsModalState = InviteContactModalState; export type RemoveModeratorsModalState = InviteContactModalState; export type UpdateGroupMembersModalState = InviteContactModalState; @@ -38,6 +43,7 @@ export type ModalState = { confirmModal: ConfirmModalState; inviteContactModal: InviteContactModalState; banOrUnbanUserModal: BanOrUnbanUserModalState; + serverBanOrUnbanUserModal: ServerBanOrUnbanUserModalState; removeModeratorsModal: RemoveModeratorsModalState; addModeratorsModal: AddModeratorsModalState; groupNameModal: UpdateGroupNameModalState; @@ -60,6 +66,7 @@ export const initialModalState: ModalState = { addModeratorsModal: null, removeModeratorsModal: null, banOrUnbanUserModal: null, + serverBanOrUnbanUserModal: null, groupNameModal: null, groupMembersModal: null, userDetailsModal: null, @@ -87,6 +94,9 @@ const ModalSlice = createSlice({ updateBanOrUnbanUserModal(state, action: PayloadAction) { return { ...state, banOrUnbanUserModal: action.payload }; }, + updateServerBanOrUnbanUserModal(state, action: PayloadAction) { + return { ...state, serverBanOrUnbanUserModal: action.payload }; + }, updateAddModeratorsModal(state, action: PayloadAction) { return { ...state, addModeratorsModal: action.payload }; }, @@ -149,6 +159,7 @@ export const { sessionPassword, updateDeleteAccountModal, updateBanOrUnbanUserModal, + updateServerBanOrUnbanUserModal, updateReactListModal, updateReactClearAllModal, } = actions; diff --git a/ts/state/selectors/modal.ts b/ts/state/selectors/modal.ts index f959bc243c..55d3e159a6 100644 --- a/ts/state/selectors/modal.ts +++ b/ts/state/selectors/modal.ts @@ -15,6 +15,7 @@ import { ReactModalsState, RecoveryPhraseModalState, RemoveModeratorsModalState, + ServerBanOrUnbanUserModalState, SessionPasswordModalState, UpdateGroupMembersModalState, UpdateGroupNameModalState, @@ -50,6 +51,11 @@ export const getBanOrUnbanUserModalState = createSelector( (state: ModalState): BanOrUnbanUserModalState => state.banOrUnbanUserModal ); +export const getServerBanOrUnbanUserModalState = createSelector( + getModal, + (state: ModalState): ServerBanOrUnbanUserModalState => state.serverBanOrUnbanUserModal +); + export const getUpdateGroupNameModal = createSelector( getModal, (state: ModalState): UpdateGroupNameModalState => state.groupNameModal diff --git a/ts/types/LocalizerKeys.ts b/ts/types/LocalizerKeys.ts index 2aa7aff76b..8c8b8b3382 100644 --- a/ts/types/LocalizerKeys.ts +++ b/ts/types/LocalizerKeys.ts @@ -147,12 +147,14 @@ export type LocalizerKeys = | 'reactionNotification' | 'leaveGroupConfirmation' | 'banUserAndDeleteAll' + | 'serverBanUserAndDeleteAll' | 'joinOpenGroupAfterInvitationConfirmationDesc' | 'invalidNumberError' | 'contextMenuNoSuggestions' | 'callMediaPermissionsDialogTitle' | 'recoveryPhraseRevealButtonText' | 'banUser' + | 'serverBanUser' | 'primaryColorBlue' | 'sendMessage' | 'recoveryPhraseRevealMessage' @@ -491,6 +493,7 @@ export type LocalizerKeys = | 'you' | 'pruneSettingTitle' | 'unbanUser' + | 'serverUnbanUser' | 'notificationForConvo_mentions_only' | 'trustThisContactDialogDescription' | 'unknownCountry' From 3f8327c0c43a8979ec41f07fe1f55ff995503911 Mon Sep 17 00:00:00 2001 From: Ian Macdonald Date: Fri, 27 Jan 2023 11:42:19 +0100 Subject: [PATCH 02/97] Fix failed user unban being reported as success. --- ts/components/dialog/BanOrUnbanUserDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ts/components/dialog/BanOrUnbanUserDialog.tsx b/ts/components/dialog/BanOrUnbanUserDialog.tsx index 745a44380a..6faba0081d 100644 --- a/ts/components/dialog/BanOrUnbanUserDialog.tsx +++ b/ts/components/dialog/BanOrUnbanUserDialog.tsx @@ -56,7 +56,7 @@ async function banOrUnBanUserCall( if (!isChangeApplied) { window?.log?.warn(`failed to ${banType} user: ${isChangeApplied}`); - banType === 'ban' ? ToastUtils.pushUserBanFailure() : ToastUtils.pushUserUnbanSuccess(); + banType === 'ban' ? ToastUtils.pushUserBanFailure() : ToastUtils.pushUserUnbanFailure(); return false; } window?.log?.info(`${pubkey.key} user ${banType}ned successfully...`); From 93c6b06fc0ac82b1104eec5a4b91a89237bea652 Mon Sep 17 00:00:00 2001 From: Ian Macdonald Date: Fri, 27 Jan 2023 11:44:54 +0100 Subject: [PATCH 03/97] Toast a hint of the likely reason for a failed global (un)ban. --- _locales/en/messages.json | 2 ++ ts/components/dialog/BanOrUnbanUserDialog.tsx | 8 +++++++- ts/session/utils/Toast.tsx | 8 ++++++++ ts/types/LocalizerKeys.ts | 2 ++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 48024e3ae6..12381a5e81 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -250,12 +250,14 @@ "serverUnbanUser": "Unban User from Server", "userUnbanned": "User unbanned successfully", "userUnbanFailed": "Unban failed!", + "globalUserUnbanFailed": "Unban failed! Are you a global admin/mod?", "banUser": "Ban User", "banUserAndDeleteAll": "Ban and Delete All", "serverBanUser": "Ban User from Server", "serverBanUserAndDeleteAll": "Ban from Server and Delete All", "userBanned": "Banned successfully", "userBanFailed": "Ban failed!", + "GlobalUserBanFailed": "Ban failed! Are you a global admin/mod?", "leaveGroup": "Leave Group", "leaveAndRemoveForEveryone": "Leave Group and Remove for Everyone", "leaveGroupConfirmation": "Are you sure you want to leave this group?", diff --git a/ts/components/dialog/BanOrUnbanUserDialog.tsx b/ts/components/dialog/BanOrUnbanUserDialog.tsx index 6faba0081d..a7120a1263 100644 --- a/ts/components/dialog/BanOrUnbanUserDialog.tsx +++ b/ts/components/dialog/BanOrUnbanUserDialog.tsx @@ -56,7 +56,13 @@ async function banOrUnBanUserCall( if (!isChangeApplied) { window?.log?.warn(`failed to ${banType} user: ${isChangeApplied}`); - banType === 'ban' ? ToastUtils.pushUserBanFailure() : ToastUtils.pushUserUnbanFailure(); + banType === 'ban' + ? isGlobal + ? ToastUtils.pushGlobalUserBanFailure() + : ToastUtils.pushUserBanFailure() + : isGlobal + ? ToastUtils.pushGlobalUserUnbanFailure() + : ToastUtils.pushUserUnbanFailure(); return false; } window?.log?.info(`${pubkey.key} user ${banType}ned successfully...`); diff --git a/ts/session/utils/Toast.tsx b/ts/session/utils/Toast.tsx index 4170dc64d2..4c3918fc83 100644 --- a/ts/session/utils/Toast.tsx +++ b/ts/session/utils/Toast.tsx @@ -117,6 +117,10 @@ export function pushUserBanFailure() { pushToastError('userBanFailed', window.i18n('userBanFailed')); } +export function pushGlobalUserBanFailure() { + pushToastError('globalUserBanFailed', window.i18n('globalUserBanFailed')); +} + export function pushUserUnbanSuccess() { pushToastSuccess('userUnbanned', window.i18n('userUnbanned')); } @@ -125,6 +129,10 @@ export function pushUserUnbanFailure() { pushToastError('userUnbanFailed', window.i18n('userUnbanFailed')); } +export function pushGlobalUserUnbanFailure() { + pushToastError('globalUserUnbanFailed', window.i18n('globalUserUnbanFailed')); +} + export function pushMessageDeleteForbidden() { pushToastError('messageDeletionForbidden', window.i18n('messageDeletionForbidden')); } diff --git a/ts/types/LocalizerKeys.ts b/ts/types/LocalizerKeys.ts index 8c8b8b3382..a94576707d 100644 --- a/ts/types/LocalizerKeys.ts +++ b/ts/types/LocalizerKeys.ts @@ -2,6 +2,7 @@ export type LocalizerKeys = | 'removePassword' | 'classicDarkThemeTitle' | 'userUnbanFailed' + | 'globalUserUnbanFailed' | 'changePassword' | 'saved' | 'startedACall' @@ -39,6 +40,7 @@ export type LocalizerKeys = | 'video' | 'readReceiptSettingDescription' | 'userBanFailed' + | 'globalUserBanFailed' | 'autoUpdateLaterButtonLabel' | 'maximumAttachments' | 'deviceOnly' From 82d82d80f0f9e10efccad3ba4e03a3cd1bc6ebc4 Mon Sep 17 00:00:00 2001 From: gravel Date: Wed, 7 Feb 2024 20:06:28 +0000 Subject: [PATCH 04/97] feat: crudely add upload permission menu items New menu items are visible in Communities. One allows the target user to upload attachment, while the other clears this permission. This only has an effect in Communities where uploads are off, but the options are still shown. Furthermore, both options are shown at the same time. These limitations stem from the limited Open Group data model in the codebase. --- _locales/en/messages.json | 4 ++ .../message-content/MessageContextMenu.tsx | 24 +++++++ ts/interactions/messageInteractions.ts | 45 +++++++++++++ .../apis/open_group_api/sogsv3/sogsApiV3.ts | 1 + .../open_group_api/sogsv3/sogsV3BatchPoll.ts | 61 ++++++++++++++++- .../sogsv3/sogsV3UserPermissions.ts | 67 +++++++++++++++++++ ts/session/utils/Toast.tsx | 8 +++ ts/shared/array_utils.ts | 5 ++ ts/types/LocalizerKeys.ts | 4 ++ 9 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 ts/session/apis/open_group_api/sogsv3/sogsV3UserPermissions.ts create mode 100644 ts/shared/array_utils.ts diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 09a67aa7be..fcccc674d4 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -254,6 +254,10 @@ "userUnbanFailed": "Unban failed!", "banUser": "Ban User", "banUserAndDeleteAll": "Ban and Delete All", + "addUploadPermission": "Allow sending attachments", + "clearUploadPermission": "Remove attachment exception", + "userPermissionsChanged": "Changed user permissions successfully", + "failedToChangeUserPermissions": "Failed to change user permissions", "userBanned": "Banned successfully", "userBanFailed": "Ban failed!", "leaveGroup": "Leave Group", diff --git a/ts/components/conversation/message/message-content/MessageContextMenu.tsx b/ts/components/conversation/message/message-content/MessageContextMenu.tsx index d5c47625a6..93af20b092 100644 --- a/ts/components/conversation/message/message-content/MessageContextMenu.tsx +++ b/ts/components/conversation/message/message-content/MessageContextMenu.tsx @@ -133,6 +133,20 @@ const AdminActionItems = ({ messageId }: MessageId) => { MessageInteraction.unbanUser(sender, convoId); }; + const addUploadPermission = () => { + MessageInteraction.addUserPermissions(sender, convoId, ['upload']); + } + + const clearUploadPermission = () => { + MessageInteraction.clearUserPermissions(sender, convoId, ['upload']); + } + + // TODO: This codebase is a pain. + // Fixed to `true`. + const isRoomUploadRestricted = true; + const canSenderUpload = true; + const canSenderNotUpload = true; + return showAdminActions ? ( <> {window.i18n('banUser')} @@ -142,6 +156,16 @@ const AdminActionItems = ({ messageId }: MessageId) => { ) : ( {window.i18n('addAsModerator')} )} + {isPublic && !isSenderAdmin && isRoomUploadRestricted && + <> + {canSenderUpload && ( + {window.i18n('addUploadPermission')} + )} + {canSenderNotUpload && ( + {window.i18n('clearUploadPermission')} + )} + + } ) : null; }; diff --git a/ts/interactions/messageInteractions.ts b/ts/interactions/messageInteractions.ts index 2e4d15eea5..0c6bd097fc 100644 --- a/ts/interactions/messageInteractions.ts +++ b/ts/interactions/messageInteractions.ts @@ -3,6 +3,9 @@ import { sogsV3AddAdmin, sogsV3RemoveAdmins, } from '../session/apis/open_group_api/sogsv3/sogsV3AddRemoveMods'; +import { + OpenGroupPermissionType, sogsV3AddPermissions, sogsV3ClearPermissions +} from '../session/apis/open_group_api/sogsv3/sogsV3UserPermissions' import { isOpenGroupV2, openGroupV2CompleteURLRegex, @@ -104,6 +107,48 @@ export async function addSenderAsModerator(sender: string, convoId: string) { } } +export async function addUserPermissions(sender: string, convoId: string, permissions: Array) { + try { + const user = PubKey.cast(sender); + const convo = getConversationController().getOrThrow(convoId); + + const roomInfo = convo.toOpenGroupV2(); + const res = await sogsV3AddPermissions([user], roomInfo, permissions); + if (!res) { + window?.log?.warn('failed to add user permissions:', res); + + ToastUtils.pushFailedToChangeUserPermissions(); + } else { + window?.log?.info(`${user.key} given permissions ${permissions.join(", ")}...`); + ToastUtils.pushUserPermissionsChanged(); + } + } catch (e) { + window?.log?.error('Got error while adding user permissions:', e); + ToastUtils.pushFailedToChangeUserPermissions(); + } +} + +export async function clearUserPermissions(sender: string, convoId: string, permissions: Array) { + try { + const user = PubKey.cast(sender); + const convo = getConversationController().getOrThrow(convoId); + + const roomInfo = convo.toOpenGroupV2(); + const res = await sogsV3ClearPermissions([user], roomInfo, permissions); + if (!res) { + window?.log?.warn('failed to add user permissions:', res); + + ToastUtils.pushFailedToChangeUserPermissions(); + } else { + window?.log?.info(`${user.key} given permissions ${permissions.join(", ")}...`); + ToastUtils.pushUserPermissionsChanged(); + } + } catch (e) { + window?.log?.error('Got error while clearing user permissions:', e); + ToastUtils.pushFailedToChangeUserPermissions(); + } +} + const acceptOpenGroupInvitationV2 = (completeUrl: string, roomName?: string) => { const onClickClose = () => { window.inboxStore?.dispatch(updateConfirmModal(null)); diff --git a/ts/session/apis/open_group_api/sogsv3/sogsApiV3.ts b/ts/session/apis/open_group_api/sogsv3/sogsApiV3.ts index 6a110d873a..e822f1b1f0 100644 --- a/ts/session/apis/open_group_api/sogsv3/sogsApiV3.ts +++ b/ts/session/apis/open_group_api/sogsv3/sogsApiV3.ts @@ -559,6 +559,7 @@ export const handleBatchPollResults = async ( case 'deleteAllPosts': case 'updateRoom': case 'deleteReaction': + case 'updateRoomUserPerms': // Could save new user permissions here // we do nothing for all of those, but let's make sure if we ever add something batch polled for, we include it's handling here. // the assertUnreachable will fail to compile every time we add a new batch poll endpoint without taking care of it. break; diff --git a/ts/session/apis/open_group_api/sogsv3/sogsV3BatchPoll.ts b/ts/session/apis/open_group_api/sogsv3/sogsV3BatchPoll.ts index 5b63d22853..e1e0236488 100644 --- a/ts/session/apis/open_group_api/sogsv3/sogsV3BatchPoll.ts +++ b/ts/session/apis/open_group_api/sogsv3/sogsV3BatchPoll.ts @@ -10,6 +10,8 @@ import { OpenGroupRequestHeaders, } from '../opengroupV2/OpenGroupPollingUtils'; import { addJsonContentTypeToHeaders } from './sogsV3SendMessage'; +import { OpenGroupPermissionType } from './sogsV3UserPermissions'; +import { hasDuplicates } from '../../../../shared/array_utils'; type BatchFetchRequestOptions = { method: 'POST' | 'PUT' | 'GET' | 'DELETE'; @@ -209,6 +211,17 @@ export type SubRequestDeleteReactionType = { }; }; +export type SubRequestUpdateUserRoomPermissionsType = { + type: 'updateRoomUserPerms', + updateUserRoomPerms: { + sessionId: string; + roomId: string; + permsToAdd?: OpenGroupPermissionType[], + permsToRemove?: OpenGroupPermissionType[] + permsToClear?: OpenGroupPermissionType[], + } +} + export type OpenGroupBatchRow = | SubRequestCapabilitiesType | SubRequestMessagesType @@ -220,7 +233,36 @@ export type OpenGroupBatchRow = | SubRequestBanUnbanUserType | SubRequestDeleteAllUserPostsType | SubRequestUpdateRoomType - | SubRequestDeleteReactionType; + | SubRequestDeleteReactionType + | SubRequestUpdateUserRoomPermissionsType; + +type OpenGroupPermissionSelection = { + [permission in `${Prefix}${OpenGroupPermissionType}`]?: boolean; +}; + +function makePermissionSelection ( + permissions: OpenGroupPermissionType[] | undefined, + choice: boolean, + prefix: Prefix +): OpenGroupPermissionSelection; + +function makePermissionSelection ( + permissions: OpenGroupPermissionType[] | undefined, + choice: boolean +): OpenGroupPermissionSelection; + +function makePermissionSelection ( + permissions: OpenGroupPermissionType[] | undefined, + choice: boolean, + prefix: string = "" +): OpenGroupPermissionSelection { + return permissions?.reduce( + ( aggregatePermissions, newPermission ) => ({ + ...aggregatePermissions, + [`${prefix}${newPermission}`]: choice + }), {} + ) ?? {}; +} /** * @@ -324,6 +366,23 @@ const makeBatchRequestPayload = ( method: 'DELETE', path: `/room/${options.deleteReaction.roomId}/reactions/${options.deleteReaction.messageId}/${options.deleteReaction.reaction}`, }; + case 'updateRoomUserPerms': + if (hasDuplicates([ + ...options.updateUserRoomPerms.permsToAdd ?? [], + ...options.updateUserRoomPerms.permsToRemove ?? [], + ...options.updateUserRoomPerms.permsToClear ?? [] + ])) { + throw new Error("Cannot change the same permission in more than one way"); + } + return { + method: 'POST', + path: `/room/${options.updateUserRoomPerms.roomId}/permissions/${options.updateUserRoomPerms.sessionId}`, + json: ({ + ...makePermissionSelection(options.updateUserRoomPerms.permsToAdd, true), + ...makePermissionSelection(options.updateUserRoomPerms.permsToRemove, false), + ...makePermissionSelection(options.updateUserRoomPerms.permsToClear, true, "default_"), + }) + }; default: assertUnreachable(type, 'Invalid batch request row'); } diff --git a/ts/session/apis/open_group_api/sogsv3/sogsV3UserPermissions.ts b/ts/session/apis/open_group_api/sogsv3/sogsV3UserPermissions.ts new file mode 100644 index 0000000000..c40a150d86 --- /dev/null +++ b/ts/session/apis/open_group_api/sogsv3/sogsV3UserPermissions.ts @@ -0,0 +1,67 @@ +/** + * @file + * Add, remove, or clear certain per-room user permissions. + */ + +import AbortController from 'abort-controller'; +import { PubKey } from '../../../types'; +import { OpenGroupRequestCommonType } from '../opengroupV2/ApiUtil'; +import { sogsBatchSend } from './sogsV3BatchPoll'; + +export type OpenGroupPermissionType = 'access' | 'read' | 'upload' | 'write'; + +export const sogsV3AddPermissions = async ( + usersToAddPermissionsTo: Array, + roomInfos: OpenGroupRequestCommonType, + permissions: Array +): Promise => { + const batchSendResponse = await sogsBatchSend( + roomInfos.serverUrl, + new Set([roomInfos.roomId]), + new AbortController().signal, + usersToAddPermissionsTo.map((user) => ( + { + type: 'updateRoomUserPerms', + updateUserRoomPerms: { + roomId: roomInfos.roomId, + sessionId: user.key, + permsToAdd: permissions, + } + } + )), + 'batch' + ); + const isSuccess = batchSendResponse?.body?.every(m => m?.code === 200) || false; + if (!isSuccess) { + window.log.warn('add permissions failed with body', batchSendResponse?.body); + } + return isSuccess; +} + +export const sogsV3ClearPermissions = async ( + usersToClearPermissionsFor: Array, + roomInfos: OpenGroupRequestCommonType, + permissions: Array +): Promise => { + const batchSendResponse = await sogsBatchSend( + roomInfos.serverUrl, + new Set([roomInfos.roomId]), + new AbortController().signal, + usersToClearPermissionsFor.map((user) => ( + { + type: 'updateRoomUserPerms', + updateUserRoomPerms: { + roomId: roomInfos.roomId, + sessionId: user.key, + permsToClear: permissions + } + } + )), + 'batch' + ); + const isSuccess = batchSendResponse?.body?.every(m => m?.code === 200) || false; + if (!isSuccess) { + window.log.warn('add permissions failed with body', batchSendResponse?.body); + } + return isSuccess; +} diff --git a/ts/session/utils/Toast.tsx b/ts/session/utils/Toast.tsx index 1087345edd..596041bd7b 100644 --- a/ts/session/utils/Toast.tsx +++ b/ts/session/utils/Toast.tsx @@ -250,6 +250,14 @@ export function pushUserRemovedFromModerators() { pushToastSuccess('userRemovedFromModerators', window.i18n('userRemovedFromModerators')); } +export function pushFailedToChangeUserPermissions() { + pushToastWarning('failedToChangeUserPermissions', window.i18n('failedToChangeUserPermissions')); +} + +export function pushUserPermissionsChanged() { + pushToastSuccess('userPermissionsChanged', window.i18n('userPermissionsChanged')); +} + export function pushInvalidPubKey() { pushToastSuccess('invalidPubKey', window.i18n('invalidPubkeyFormat')); } diff --git a/ts/shared/array_utils.ts b/ts/shared/array_utils.ts new file mode 100644 index 0000000000..f54dc64cf8 --- /dev/null +++ b/ts/shared/array_utils.ts @@ -0,0 +1,5 @@ +import _ from "lodash"; + +export function hasDuplicates(array: Array): boolean { + return (new Set(array)).size < array.length; +} diff --git a/ts/types/LocalizerKeys.ts b/ts/types/LocalizerKeys.ts index ed5d4ad7f8..3f589dc3df 100644 --- a/ts/types/LocalizerKeys.ts +++ b/ts/types/LocalizerKeys.ts @@ -15,6 +15,7 @@ export type LocalizerKeys = | 'appMenuHideOthers' | 'appMenuQuit' | 'appMenuUnhide' + | 'addUploadPermission' | 'appearanceSettingsTitle' | 'areYouSureClearDevice' | 'areYouSureDeleteDeviceOnly' @@ -181,6 +182,7 @@ export type LocalizerKeys = | 'expandedReactionsText' | 'failedResolveOns' | 'failedToAddAsModerator' + | 'failedToChangeUserPermissions' | 'failedToRemoveFromModerator' | 'faq' | 'fileSizeWarning' @@ -373,6 +375,7 @@ export type LocalizerKeys = | 'removePasswordTitle' | 'removePasswordToastDescription' | 'removeResidueMembers' + | 'clearUploadPermission' | 'replyToMessage' | 'replyingToMessage' | 'reportIssue' @@ -486,6 +489,7 @@ export type LocalizerKeys = | 'userAddedToModerators' | 'userBanFailed' | 'userBanned' + | 'userPermissionsChanged' | 'userRemovedFromModerators' | 'userUnbanFailed' | 'userUnbanned' From 1c2f0e6c1b64fbce03db6ea8b8edeef3c65d1e0d Mon Sep 17 00:00:00 2001 From: gravel Date: Wed, 28 Feb 2024 11:26:18 +0000 Subject: [PATCH 05/97] fix: empty global ban fail toast message --- _locales/en/messages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 2e7dd9b1cd..8526bf2131 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -260,7 +260,7 @@ "serverBanUserAndDeleteAll": "Ban from Server and Delete All", "userBanned": "Banned successfully", "userBanFailed": "Ban failed!", - "GlobalUserBanFailed": "Ban failed! Are you a global admin/mod?", + "globalUserBanFailed": "Ban failed! Are you a global admin/mod?", "leaveGroup": "Leave Group", "leaveAndRemoveForEveryone": "Leave Group and Remove for Everyone", "leaveGroupConfirmation": "Are you sure you want to leave this group?", From 68f655df00833a3239c02030417c685e4ab50964 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 7 Nov 2024 20:21:17 +0000 Subject: [PATCH 06/97] fix: build appimage by default --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d5b0f2cd63..ebca93a1d4 100644 --- a/package.json +++ b/package.json @@ -261,7 +261,7 @@ "StartupWMClass": "Session" }, "asarUnpack": "node_modules/spellchecker/vendor/hunspell_dictionaries", - "target": ["deb"], + "target": ["appImage"], "icon": "build/icon-linux.icns" }, "asarUnpack": [ From 06e2ed99933efe2c89590f8e287d5ad03ff06727 Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 8 Nov 2024 19:36:11 +0000 Subject: [PATCH 07/97] feat: add open group permissions modal --- _locales/en/messages.json | 1 + .../overlay/OverlayRightPanelSettings.tsx | 13 ++ ts/components/dialog/ModalContainer.tsx | 6 + .../dialog/UpdateGroupPermissionsDialog.tsx | 191 ++++++++++++++++++ ts/interactions/conversationInteractions.ts | 8 + .../apis/open_group_api/sogsv3/sogsApiV3.ts | 1 + .../open_group_api/sogsv3/sogsV3BatchPoll.ts | 20 ++ .../sogsv3/sogsV3RoomPermissions.ts | 48 +++++ ts/state/ducks/modalDialog.tsx | 10 + ts/state/selectors/modal.ts | 6 + 10 files changed, 304 insertions(+) create mode 100644 ts/components/dialog/UpdateGroupPermissionsDialog.tsx create mode 100644 ts/session/apis/open_group_api/sogsv3/sogsV3RoomPermissions.ts diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 1d8da80e6a..68039f6a91 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -374,6 +374,7 @@ "giphyWarning": "Giphy", "giphyWarningDescription": "{app_name} will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs.", "groupAddMemberMaximum": "Groups have a maximum of 100 members", + "groupChangePermissions": "Edit Permissions", "groupCreate": "Create Group", "groupCreateErrorNoMembers": "Please pick at least one other group member.", "groupDelete": "Delete Group", diff --git a/ts/components/conversation/right-panel/overlay/OverlayRightPanelSettings.tsx b/ts/components/conversation/right-panel/overlay/OverlayRightPanelSettings.tsx index 1b4d5daf1e..73c1bd2bae 100644 --- a/ts/components/conversation/right-panel/overlay/OverlayRightPanelSettings.tsx +++ b/ts/components/conversation/right-panel/overlay/OverlayRightPanelSettings.tsx @@ -19,6 +19,7 @@ import { showRemoveModeratorsByConvoId, showUpdateGroupMembersByConvoId, showUpdateGroupNameByConvoId, + showUpdateGroupPermissionsByConvoId, } from '../../../../interactions/conversationInteractions'; import { Constants } from '../../../../session'; import { closeRightPanel } from '../../../../state/ducks/conversations'; @@ -272,6 +273,7 @@ export const OverlayRightPanelSettings = () => { : window.i18n('groupLeave'); const showUpdateGroupNameButton = isGroup && weAreAdmin && !commonNoShow; // legacy groups non-admin cannot change groupname anymore + const showUpdateGroupPermissions = weAreAdmin && isPublic; const showAddRemoveModeratorsButton = weAreAdmin && !commonNoShow && isPublic; const showUpdateGroupMembersButton = !isPublic && isGroup && !commonNoShow; @@ -295,6 +297,17 @@ export const OverlayRightPanelSettings = () => { /> )} + {showUpdateGroupPermissions && ( + { + void showUpdateGroupPermissionsByConvoId(selectedConvoKey); + }} + dataTestId="edit-group-name" + /> + )} + {showAddRemoveModeratorsButton && ( <> { const confirmModalState = useSelector(getConfirmModal); @@ -50,6 +52,7 @@ export const ModalContainer = () => { const addModeratorsModalState = useSelector(getAddModeratorsModal); const removeModeratorsModalState = useSelector(getRemoveModeratorsModal); const updateGroupMembersModalState = useSelector(getUpdateGroupMembersModal); + const updateGroupPermissionsModalState = useSelector(getUpdateGroupPermissionsModal); const updateGroupNameModalState = useSelector(getUpdateGroupNameModal); const userDetailsModalState = useSelector(getUserDetailsModal); const changeNicknameModal = useSelector(getChangeNickNameDialog); @@ -77,6 +80,9 @@ export const ModalContainer = () => { {updateGroupMembersModalState && ( )} + {updateGroupPermissionsModalState && ( + + )} {updateGroupNameModalState && } {userDetailsModalState && } {changeNicknameModal && } diff --git a/ts/components/dialog/UpdateGroupPermissionsDialog.tsx b/ts/components/dialog/UpdateGroupPermissionsDialog.tsx new file mode 100644 index 0000000000..ef88ec72ca --- /dev/null +++ b/ts/components/dialog/UpdateGroupPermissionsDialog.tsx @@ -0,0 +1,191 @@ +/* eslint-disable @typescript-eslint/no-misused-promises */ +import autoBind from 'auto-bind'; + +import { motion } from 'framer-motion'; +import { Component } from 'react'; +import styled from 'styled-components'; +import { ConversationModel } from '../../models/conversation'; +import { getConversationController } from '../../session/conversations'; +import { updateGroupPermissionsModal } from '../../state/ducks/modalDialog'; +import { THEME_GLOBALS } from '../../themes/globals'; +import { SessionWrapperModal } from '../SessionWrapperModal'; +import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton'; +import { SpacerMD } from '../basic/Text'; +import { SessionToggleWithDescription } from '../settings/SessionSettingListItem'; +import { OpenGroupData } from '../../data/opengroups'; +import { + OpenGroupRoomPermissionType, + sogsV3SetRoomPermissions, +} from '../../session/apis/open_group_api/sogsv3/sogsV3RoomPermissions'; + +const StyledErrorMessage = styled(motion.p)` + text-align: center; + color: var(--danger-color); + display: block; + user-select: none; +`; + +type Props = { + conversationId: string; +}; + +interface State { + errorDisplayed: boolean; + errorMessage: string; + default_read: boolean; + default_write: boolean; + default_accessible: boolean; + default_upload: boolean; +} + +export class UpdateGroupPermissionsDialog extends Component { + private readonly convo: ConversationModel; + + constructor(props: Props) { + super(props); + + autoBind(this); + this.convo = getConversationController().get(props.conversationId); + + this.state = { + default_read: this.convo.attributes.default_read ?? true, + default_write: this.convo.attributes.default_write ?? true, + default_accessible: this.convo.attributes.default_accessible ?? true, + default_upload: this.convo.attributes.default_upload ?? true, + errorDisplayed: false, + errorMessage: 'placeholder', + }; + } + + public componentDidMount() { + window.addEventListener('keyup', this.onKeyUp); + } + + public componentWillUnmount() { + window.removeEventListener('keyup', this.onKeyUp); + } + + public onClickOK() { + const { default_accessible, default_read, default_upload, default_write } = this.state; + + if (this.convo.isPublic()) { + const roomInfos = OpenGroupData.getV2OpenGroupRoom(this.convo.id); + if (!roomInfos) { + return; + } + void sogsV3SetRoomPermissions(roomInfos, { + default_accessible, + default_read, + default_upload, + default_write, + }); + } + + this.closeDialog(); + } + + public render() { + const okText = 'Apply'; + const cancelText = window.i18n('cancel'); + + const errorMsg = this.state.errorMessage; + + return ( + this.closeDialog()} + additionalClassName="update-group-dialog" + > + {this.state.errorDisplayed ? ( + <> + + + {errorMsg} + + + + ) : null} + +

+ For compatibility reasons, we don't know which permissions were enabled to begin with, but you can set new values below regardless. +

+ + this.onPermissionChanged('default_accessible')} + /> + this.onPermissionChanged('default_read')} + /> + this.onPermissionChanged('default_write')} + /> + this.onPermissionChanged('default_upload')} + /> + +
+ + +
+
+ ); + } + + private onKeyUp(event: any) { + switch (event.key) { + case 'Enter': + this.onClickOK(); + break; + case 'Esc': + case 'Escape': + this.closeDialog(); + break; + default: + } + } + + private closeDialog() { + window.removeEventListener('keyup', this.onKeyUp); + + window.inboxStore?.dispatch(updateGroupPermissionsModal(null)); + } + + private onPermissionChanged(perm: OpenGroupRoomPermissionType) { + this.setState(state => { + return { + ...state, + [perm]: !state[perm], + }; + }); + } +} diff --git a/ts/interactions/conversationInteractions.ts b/ts/interactions/conversationInteractions.ts index 5f02652920..237726c2ec 100644 --- a/ts/interactions/conversationInteractions.ts +++ b/ts/interactions/conversationInteractions.ts @@ -35,6 +35,7 @@ import { updateConfirmModal, updateGroupMembersModal, updateGroupNameModal, + updateGroupPermissionsModal, updateInviteContactModal, updateRemoveModeratorsModal, } from '../state/ducks/modalDialog'; @@ -200,6 +201,13 @@ export async function showUpdateGroupNameByConvoId(conversationId: string) { window.inboxStore?.dispatch(updateGroupNameModal({ conversationId })); } +export async function showUpdateGroupPermissionsByConvoId(conversationId: string) { + const conversation = getConversationController().get(conversationId); + if (conversation.isOpenGroupV2()) { + window.inboxStore?.dispatch(updateGroupPermissionsModal({ conversationId })); + } +} + export async function showUpdateGroupMembersByConvoId(conversationId: string) { const conversation = getConversationController().get(conversationId); if (conversation.isClosedGroup()) { diff --git a/ts/session/apis/open_group_api/sogsv3/sogsApiV3.ts b/ts/session/apis/open_group_api/sogsv3/sogsApiV3.ts index 93ec7afefb..8918277612 100644 --- a/ts/session/apis/open_group_api/sogsv3/sogsApiV3.ts +++ b/ts/session/apis/open_group_api/sogsv3/sogsApiV3.ts @@ -559,6 +559,7 @@ export const handleBatchPollResults = async ( case 'deleteAllPosts': case 'updateRoom': case 'deleteReaction': + case 'updateRoomPerms': // we do nothing for all of those, but let's make sure if we ever add something batch polled for, we include it's handling here. // the assertUnreachable will fail to compile every time we add a new batch poll endpoint without taking care of it. break; diff --git a/ts/session/apis/open_group_api/sogsv3/sogsV3BatchPoll.ts b/ts/session/apis/open_group_api/sogsv3/sogsV3BatchPoll.ts index 90cdf60675..14c25c49cb 100644 --- a/ts/session/apis/open_group_api/sogsv3/sogsV3BatchPoll.ts +++ b/ts/session/apis/open_group_api/sogsv3/sogsV3BatchPoll.ts @@ -208,6 +208,19 @@ export type SubRequestUpdateRoomType = { }; }; +export type SubRequestUpdateRoomPermsType = { + type: 'updateRoomPerms'; + updateRoomPerms: { + roomId: string; + permsToSet: { + default_read?: boolean; + default_write?: boolean; + default_upload?: boolean; + default_accessible?: boolean; + }; + }; +}; + export type SubRequestDeleteReactionType = { type: 'deleteReaction'; deleteReaction: { @@ -228,6 +241,7 @@ export type OpenGroupBatchRow = | SubRequestBanUnbanUserType | SubRequestDeleteAllUserPostsType | SubRequestUpdateRoomType + | SubRequestUpdateRoomPermsType | SubRequestDeleteReactionType; /** @@ -334,6 +348,12 @@ const makeBatchRequestPayload = ( path: `/room/${options.updateRoom.roomId}`, json: { image: options.updateRoom.imageId }, }; + case 'updateRoomPerms': + return { + method: 'PUT', + path: `/room/${options.updateRoomPerms.roomId}`, + json: { ...options.updateRoomPerms.permsToSet }, + }; case 'deleteReaction': return { method: 'DELETE', diff --git a/ts/session/apis/open_group_api/sogsv3/sogsV3RoomPermissions.ts b/ts/session/apis/open_group_api/sogsv3/sogsV3RoomPermissions.ts new file mode 100644 index 0000000000..cb3ec3234e --- /dev/null +++ b/ts/session/apis/open_group_api/sogsv3/sogsV3RoomPermissions.ts @@ -0,0 +1,48 @@ +/** + * @file + * Set certain default room permissions. + */ + +import AbortController from 'abort-controller'; +import { OpenGroupRequestCommonType } from '../../../../data/types'; +import { sogsBatchSend } from './sogsV3BatchPoll'; + +export type OpenGroupRoomPermissionType = + | 'default_read' + | 'default_write' + | 'default_accessible' + | 'default_upload'; + +export type OpenGroupRoomPermissionSetType = Record; + +type PermsToSet = Partial; + +export const sogsV3SetRoomPermissions = async ( + roomInfos: OpenGroupRequestCommonType, + permissions: OpenGroupRoomPermissionSetType +): Promise => { + const permsToSet: PermsToSet = {}; + Object.entries(permissions).forEach(([permission, value]) => { + permsToSet[permission as OpenGroupRoomPermissionType] = value; + }); + const batchSendResponse = await sogsBatchSend( + roomInfos.serverUrl, + new Set([roomInfos.roomId]), + new AbortController().signal, + [ + { + type: 'updateRoomPerms', + updateRoomPerms: { + roomId: roomInfos.roomId, + permsToSet, + }, + }, + ], + 'batch' + ); + const isSuccess = batchSendResponse?.body?.every(m => m?.code === 200) || false; + if (!isSuccess) { + window.log.warn('set permissions failed with body', batchSendResponse?.body); + } + return isSuccess; +}; diff --git a/ts/state/ducks/modalDialog.tsx b/ts/state/ducks/modalDialog.tsx index 1b6c5bc69d..ae281c8db1 100644 --- a/ts/state/ducks/modalDialog.tsx +++ b/ts/state/ducks/modalDialog.tsx @@ -20,6 +20,7 @@ export type AddModeratorsModalState = InviteContactModalState; export type RemoveModeratorsModalState = InviteContactModalState; export type UpdateGroupMembersModalState = InviteContactModalState; export type UpdateGroupNameModalState = InviteContactModalState; +export type UpdateGroupPermissionsModalState = InviteContactModalState; export type ChangeNickNameModalState = InviteContactModalState; export type EditProfileModalState = object | null; export type OnionPathModalState = EditProfileModalState; @@ -60,6 +61,7 @@ export type ModalState = { addModeratorsModal: AddModeratorsModalState; groupNameModal: UpdateGroupNameModalState; groupMembersModal: UpdateGroupMembersModalState; + groupPermissionsModal: UpdateGroupPermissionsModalState; userDetailsModal: UserDetailsModalState; nickNameModal: ChangeNickNameModalState; editProfileModal: EditProfileModalState; @@ -84,6 +86,7 @@ export const initialModalState: ModalState = { blockOrUnblockModal: null, groupNameModal: null, groupMembersModal: null, + groupPermissionsModal: null, userDetailsModal: null, nickNameModal: null, editProfileModal: null, @@ -127,6 +130,12 @@ const ModalSlice = createSlice({ updateGroupMembersModal(state, action: PayloadAction) { return { ...state, groupMembersModal: action.payload }; }, + updateGroupPermissionsModal( + state, + action: PayloadAction + ) { + return { ...state, groupPermissionsModal: action.payload }; + }, updateUserDetailsModal(state, action: PayloadAction) { return { ...state, userDetailsModal: action.payload }; }, @@ -191,6 +200,7 @@ export const { updateRemoveModeratorsModal, updateGroupNameModal, updateGroupMembersModal, + updateGroupPermissionsModal, updateUserDetailsModal, changeNickNameModal, editProfileModal, diff --git a/ts/state/selectors/modal.ts b/ts/state/selectors/modal.ts index 3a6c5f7e9f..69263f2812 100644 --- a/ts/state/selectors/modal.ts +++ b/ts/state/selectors/modal.ts @@ -19,6 +19,7 @@ import { SessionPasswordModalState, UpdateGroupMembersModalState, UpdateGroupNameModalState, + UpdateGroupPermissionsModalState, UserDetailsModalState, } from '../ducks/modalDialog'; import { StateType } from '../reducer'; @@ -78,6 +79,11 @@ export const getUpdateGroupMembersModal = createSelector( (state: ModalState): UpdateGroupMembersModalState => state.groupMembersModal ); +export const getUpdateGroupPermissionsModal = createSelector( + getModal, + (state: ModalState): UpdateGroupPermissionsModalState => state.groupPermissionsModal +); + export const getUserDetailsModal = createSelector( getModal, (state: ModalState): UserDetailsModalState => state.userDetailsModal From b351f51512481423e37c9c6d9777882d980b702e Mon Sep 17 00:00:00 2001 From: gravel Date: Wed, 19 Mar 2025 21:55:21 +0000 Subject: [PATCH 08/97] ci: add first workflow --- .woodpecker/build-linux.yaml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .woodpecker/build-linux.yaml diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml new file mode 100644 index 0000000000..e03220b688 --- /dev/null +++ b/.woodpecker/build-linux.yaml @@ -0,0 +1,24 @@ +when: + - path: + exclude: '*.md' + - event: "push" + +steps: + python: + image: ubuntu-22.04 + commands: + - sudo apt install python3/3.12 + - python -m pip install --upgrade pip setuptools + yarn: + image: codeberg.org/woodpecker-plugins/node-pm + settings: + run: ["install", "build-everything"] + with: yarn + frozen_lockfile: true + publish: + image: woodpeckerci/plugin-release + settings: + files: + - "release/*.AppImage" + api_key: + from_secret: ACCESS_TOKEN From b5f1529e250d6ef8ec0b6c3fa56be7fcff037ebc Mon Sep 17 00:00:00 2001 From: gravel Date: Wed, 19 Mar 2025 22:01:30 +0000 Subject: [PATCH 09/97] ci: try fix ubuntu image reference --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index e03220b688..fe57311036 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -5,7 +5,7 @@ when: steps: python: - image: ubuntu-22.04 + image: docker.io/ubuntu:22.04 commands: - sudo apt install python3/3.12 - python -m pip install --upgrade pip setuptools From 58c69081cde8f0d7361b3dfdc933ed4fba580576 Mon Sep 17 00:00:00 2001 From: gravel Date: Wed, 19 Mar 2025 22:04:16 +0000 Subject: [PATCH 10/97] ci: try fix broad run condition --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index fe57311036..0a6d2b1793 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -1,7 +1,7 @@ when: - path: exclude: '*.md' - - event: "push" + event: "push" steps: python: From 5bb78edc910885c70b383f6fac1d0d87579389c6 Mon Sep 17 00:00:00 2001 From: gravel Date: Wed, 19 Mar 2025 22:04:49 +0000 Subject: [PATCH 11/97] ci: lint workflow --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 0a6d2b1793..39eb757b18 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -1,6 +1,6 @@ when: - path: - exclude: '*.md' + exclude: ['*.md'] event: "push" steps: From 50b1f32588c94e6150badae50e5bd13b90c7b0b5 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 07:24:16 +0000 Subject: [PATCH 12/97] ci: try fix python install --- .woodpecker/build-linux.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 39eb757b18..5c3fe9cf12 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -5,9 +5,9 @@ when: steps: python: - image: docker.io/ubuntu:22.04 + image: docker.io/_/ubuntu:22.04 commands: - - sudo apt install python3/3.12 + - apt install python3/3.12 - python -m pip install --upgrade pip setuptools yarn: image: codeberg.org/woodpecker-plugins/node-pm From 3f48347958b3b817873583fbf32458955a3d66ce Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 07:29:45 +0000 Subject: [PATCH 13/97] ci: revert docker image reference --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 5c3fe9cf12..f432ad5e9e 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -5,7 +5,7 @@ when: steps: python: - image: docker.io/_/ubuntu:22.04 + image: docker.io/ubuntu:22.04 commands: - apt install python3/3.12 - python -m pip install --upgrade pip setuptools From bf7e43fa2827e7d988275f8d6acb9e5b679d772e Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 07:32:02 +0000 Subject: [PATCH 14/97] ci: use apt-get for stability --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index f432ad5e9e..08986a08c5 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -7,7 +7,7 @@ steps: python: image: docker.io/ubuntu:22.04 commands: - - apt install python3/3.12 + - apt-get install python3/3.12 - python -m pip install --upgrade pip setuptools yarn: image: codeberg.org/woodpecker-plugins/node-pm From 5fc758e4155f543654a3a92fdd79a6a3e764e574 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 07:38:23 +0000 Subject: [PATCH 15/97] ci: install python using ppa --- .woodpecker/build-linux.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 08986a08c5..d3772a901f 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -7,7 +7,11 @@ steps: python: image: docker.io/ubuntu:22.04 commands: - - apt-get install python3/3.12 + - apt update + - apt upgrade + - add-apt-repository ppa:deadsnakes/ppa -y + - apt update + - apt-get install python3.12 - python -m pip install --upgrade pip setuptools yarn: image: codeberg.org/woodpecker-plugins/node-pm From 1fafc3d30bca152de7cf3e35a070938ae3688b1b Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 07:40:55 +0000 Subject: [PATCH 16/97] ci: use apt-get for stability --- .woodpecker/build-linux.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index d3772a901f..6f24d56865 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -7,10 +7,10 @@ steps: python: image: docker.io/ubuntu:22.04 commands: - - apt update - - apt upgrade + - apt-get update + - apt-get upgrade - add-apt-repository ppa:deadsnakes/ppa -y - - apt update + - apt-get update - apt-get install python3.12 - python -m pip install --upgrade pip setuptools yarn: From be081b8bf0a03572ca8382e4ae6acb0f6404357b Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 07:43:35 +0000 Subject: [PATCH 17/97] ci: fix frozen upgrade without -y --- .woodpecker/build-linux.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 6f24d56865..41e3674ba3 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -8,10 +8,10 @@ steps: image: docker.io/ubuntu:22.04 commands: - apt-get update - - apt-get upgrade + - apt-get upgrade -y - add-apt-repository ppa:deadsnakes/ppa -y - apt-get update - - apt-get install python3.12 + - apt-get install python3.12 -y - python -m pip install --upgrade pip setuptools yarn: image: codeberg.org/woodpecker-plugins/node-pm From ed1fd34d9d5b530e578cb22e3919746eaf29888f Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 07:47:30 +0000 Subject: [PATCH 18/97] ci: fix missing add-apt-repository --- .woodpecker/build-linux.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 41e3674ba3..06e194be6a 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -9,6 +9,7 @@ steps: commands: - apt-get update - apt-get upgrade -y + - apt-get install software-properties-common -y - add-apt-repository ppa:deadsnakes/ppa -y - apt-get update - apt-get install python3.12 -y From 17fc6cbe16616439d1b42be41fbe80290f3c5819 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 07:57:52 +0000 Subject: [PATCH 19/97] ci: fix hang on interactive prompt --- .woodpecker/build-linux.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 06e194be6a..c14eeb537a 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -7,6 +7,7 @@ steps: python: image: docker.io/ubuntu:22.04 commands: + - debconf debconf/frontend select Noninteractive' | debconf-set-selections - apt-get update - apt-get upgrade -y - apt-get install software-properties-common -y From 1abee6e196f60997e2893a8b384b8e555c21d882 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 08:02:20 +0000 Subject: [PATCH 20/97] ci: fix syntax error --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index c14eeb537a..c043699a72 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -7,7 +7,7 @@ steps: python: image: docker.io/ubuntu:22.04 commands: - - debconf debconf/frontend select Noninteractive' | debconf-set-selections + - echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections - apt-get update - apt-get upgrade -y - apt-get install software-properties-common -y From ad4d1e3acc2c1e5553cd6a834f14fce8ea801aac Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 08:09:48 +0000 Subject: [PATCH 21/97] ci: fix python invocation --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index c043699a72..740b5bc83a 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -14,7 +14,7 @@ steps: - add-apt-repository ppa:deadsnakes/ppa -y - apt-get update - apt-get install python3.12 -y - - python -m pip install --upgrade pip setuptools + - python3 -m pip install --upgrade pip setuptools yarn: image: codeberg.org/woodpecker-plugins/node-pm settings: From 2a5b059b17d2459171849c27381dfe53bac03ae9 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 08:19:42 +0000 Subject: [PATCH 22/97] ci: fix missing pip --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 740b5bc83a..03dc2bfe25 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -13,7 +13,7 @@ steps: - apt-get install software-properties-common -y - add-apt-repository ppa:deadsnakes/ppa -y - apt-get update - - apt-get install python3.12 -y + - apt-get install python3.12 python3-pip -y - python3 -m pip install --upgrade pip setuptools yarn: image: codeberg.org/woodpecker-plugins/node-pm From b4f9de7be49279d63aa4df0985c4405b9769500f Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 08:40:37 +0000 Subject: [PATCH 23/97] ci: try lower runtime --- .woodpecker/build-linux.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 03dc2bfe25..a3ff758d47 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -9,7 +9,6 @@ steps: commands: - echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections - apt-get update - - apt-get upgrade -y - apt-get install software-properties-common -y - add-apt-repository ppa:deadsnakes/ppa -y - apt-get update From b0aab94430d87ccab1c7d8b5de67ac40ed2310e1 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 13:48:56 +0000 Subject: [PATCH 24/97] ci: use prepared python image --- .woodpecker/build-linux.yaml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index a3ff758d47..c0b1b1626e 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -5,14 +5,8 @@ when: steps: python: - image: docker.io/ubuntu:22.04 + image: docker.io/python:3.12-bookworm commands: - - echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections - - apt-get update - - apt-get install software-properties-common -y - - add-apt-repository ppa:deadsnakes/ppa -y - - apt-get update - - apt-get install python3.12 python3-pip -y - python3 -m pip install --upgrade pip setuptools yarn: image: codeberg.org/woodpecker-plugins/node-pm From fafbf321731f6db63cc942254208080affe0cb8a Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 14:00:15 +0000 Subject: [PATCH 25/97] ci: use docker node image --- .woodpecker/build-linux.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index c0b1b1626e..867efc59bf 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -9,11 +9,11 @@ steps: commands: - python3 -m pip install --upgrade pip setuptools yarn: - image: codeberg.org/woodpecker-plugins/node-pm - settings: - run: ["install", "build-everything"] - with: yarn - frozen_lockfile: true + image: docker.io/node:18.5.0-slim + commands: + - npm install --global yarn + - yarn install --frozen-lockfile --network-timeout 600000 + - yarn build-everything publish: image: woodpeckerci/plugin-release settings: From fccf335329e278fbcae802ec636bae8815e18245 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 14:04:04 +0000 Subject: [PATCH 26/97] ci: fix overwriting yarn --- .woodpecker/build-linux.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 867efc59bf..911fea22f0 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -11,7 +11,6 @@ steps: yarn: image: docker.io/node:18.5.0-slim commands: - - npm install --global yarn - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything publish: From 1b16e38adc2dcbd65c2605fc907b6fa3c7cd3763 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 14:09:33 +0000 Subject: [PATCH 27/97] ci: fix wrong node version --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 911fea22f0..ec953fe894 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -9,7 +9,7 @@ steps: commands: - python3 -m pip install --upgrade pip setuptools yarn: - image: docker.io/node:18.5.0-slim + image: docker.io/node:18.15.0-slim commands: - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything From 7a10311f8f2c896b0974d3ec123cdcb2e4371560 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 14:13:47 +0000 Subject: [PATCH 28/97] ci: fix missing git --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index ec953fe894..d8ed5b3874 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -9,7 +9,7 @@ steps: commands: - python3 -m pip install --upgrade pip setuptools yarn: - image: docker.io/node:18.15.0-slim + image: docker.io/node:18.15.0 commands: - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything From 4930f09218ea53ce0f88edcbd3639b424184ba14 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 14:17:15 +0000 Subject: [PATCH 29/97] ci: fix missing cmake --- .woodpecker/build-linux.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index d8ed5b3874..ec0f4ebd8f 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -11,6 +11,7 @@ steps: yarn: image: docker.io/node:18.15.0 commands: + - apt install build-essential cmake - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything publish: From 673e6ed3082e2ebeff908fa9c6608b3bac0ff6bd Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 14:20:33 +0000 Subject: [PATCH 30/97] ci: fix unavailable package --- .woodpecker/build-linux.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index ec0f4ebd8f..d399a772ba 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -11,7 +11,8 @@ steps: yarn: image: docker.io/node:18.15.0 commands: - - apt install build-essential cmake + - apt-get update + - apt-get install build-essential cmake - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything publish: From 01fa5b37ecd563835c63f5d23cbf69f3b643c3ee Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 14:21:33 +0000 Subject: [PATCH 31/97] ci: fix noninteractive install --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index d399a772ba..6ee46880e8 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -12,7 +12,7 @@ steps: image: docker.io/node:18.15.0 commands: - apt-get update - - apt-get install build-essential cmake + - apt-get install build-essential cmake -y - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything publish: From 940bb0cc038093b28fe7b9d7a6a136d6f068bcd5 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 14:28:39 +0000 Subject: [PATCH 32/97] ci: fix apt-get timing out --- .woodpecker/build-linux.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 6ee46880e8..f2717c90e7 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -11,6 +11,7 @@ steps: yarn: image: docker.io/node:18.15.0 commands: + - echo 'Acquire::http::Timeout "20";' > /etc/apt/apt.conf.d/80-retries - apt-get update - apt-get install build-essential cmake -y - yarn install --frozen-lockfile --network-timeout 600000 From a40e070c2b85b8ad859691d213eac9fe2bba7b27 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 14:38:07 +0000 Subject: [PATCH 33/97] ci: fix old cmake version --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index f2717c90e7..4465c488fd 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -9,7 +9,7 @@ steps: commands: - python3 -m pip install --upgrade pip setuptools yarn: - image: docker.io/node:18.15.0 + image: docker.io/node:18.15.0-bullseye commands: - echo 'Acquire::http::Timeout "20";' > /etc/apt/apt.conf.d/80-retries - apt-get update From 5b27e1b6862ba2a8de617d25b127ae1a2160bc54 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 14:43:06 +0000 Subject: [PATCH 34/97] ci: fix old cmake version --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 4465c488fd..1a004c0539 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -9,7 +9,7 @@ steps: commands: - python3 -m pip install --upgrade pip setuptools yarn: - image: docker.io/node:18.15.0-bullseye + image: docker.io/node:18.15.0-alpine3.17 commands: - echo 'Acquire::http::Timeout "20";' > /etc/apt/apt.conf.d/80-retries - apt-get update From 846f2e44159c006b267fdb3cd535cd78d4079354 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 14:46:29 +0000 Subject: [PATCH 35/97] ci: fix non-alpine commands --- .woodpecker/build-linux.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 1a004c0539..ff71279300 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -11,9 +11,8 @@ steps: yarn: image: docker.io/node:18.15.0-alpine3.17 commands: - - echo 'Acquire::http::Timeout "20";' > /etc/apt/apt.conf.d/80-retries - - apt-get update - - apt-get install build-essential cmake -y + - apk update + - apk add build-base cmake -y - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything publish: From b586e472e2aa06f232b3a101e2f848d6066774b6 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 14:48:06 +0000 Subject: [PATCH 36/97] ci: fix non-alpine flags --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index ff71279300..b2f61ffb86 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -12,7 +12,7 @@ steps: image: docker.io/node:18.15.0-alpine3.17 commands: - apk update - - apk add build-base cmake -y + - apk add build-base cmake - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything publish: From 7d95d6eee0d10933279737328d07f0059b7509ea Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 14:49:48 +0000 Subject: [PATCH 37/97] ci: fix missing git --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index b2f61ffb86..ae134910e8 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -12,7 +12,7 @@ steps: image: docker.io/node:18.15.0-alpine3.17 commands: - apk update - - apk add build-base cmake + - apk add git build-base cmake - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything publish: From 320d9917183415bbda1041ae4488e4c134f99b79 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 14:55:41 +0000 Subject: [PATCH 38/97] ci: fix missing python --- .woodpecker/build-linux.yaml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index ae134910e8..24df8da61c 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -4,17 +4,16 @@ when: event: "push" steps: - python: + build: image: docker.io/python:3.12-bookworm commands: + - apt update - python3 -m pip install --upgrade pip setuptools - yarn: - image: docker.io/node:18.15.0-alpine3.17 - commands: - - apk update - - apk add git build-base cmake + - apt-get install git build-essentials cmake nodejs=18.15.0 -y + - if ! which yarn; do npm install --global yarn; done - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything + publish: image: woodpeckerci/plugin-release settings: From 6891df99a231afa51fd2c2ca71a68755f6d8a6f6 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 14:57:50 +0000 Subject: [PATCH 39/97] ci: fix apt warning [skip ci] --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 24df8da61c..1c03baa293 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -7,7 +7,7 @@ steps: build: image: docker.io/python:3.12-bookworm commands: - - apt update + - apt-get update - python3 -m pip install --upgrade pip setuptools - apt-get install git build-essentials cmake nodejs=18.15.0 -y - if ! which yarn; do npm install --global yarn; done From fd1bf2397c443bbc656e025d0ce4cad05f0ecd90 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 15:03:41 +0000 Subject: [PATCH 40/97] ci: fix unavailable node version --- .woodpecker/build-linux.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 1c03baa293..c0ec230e16 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -9,7 +9,10 @@ steps: commands: - apt-get update - python3 -m pip install --upgrade pip setuptools - - apt-get install git build-essentials cmake nodejs=18.15.0 -y + - apt-get install git build-essentials cmake -y + - curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.2/install.sh | bash + - source "$HOME/.nvm/nvm.sh" + - nvm use - if ! which yarn; do npm install --global yarn; done - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything From 3ea7bf0e2f8667b4b2caca0147f5bde7d41e852c Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 15:07:51 +0000 Subject: [PATCH 41/97] ci: fix missing build-essentials package --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index c0ec230e16..fee52ec0e1 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -9,7 +9,7 @@ steps: commands: - apt-get update - python3 -m pip install --upgrade pip setuptools - - apt-get install git build-essentials cmake -y + - apt-get install git build-essential cmake -y - curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.2/install.sh | bash - source "$HOME/.nvm/nvm.sh" - nvm use From 06ad545b41b4dd0d077d4c2529a7fbbca37f1649 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 15:10:42 +0000 Subject: [PATCH 42/97] ci: fix missing source command --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index fee52ec0e1..e3e363e129 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -11,7 +11,7 @@ steps: - python3 -m pip install --upgrade pip setuptools - apt-get install git build-essential cmake -y - curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.2/install.sh | bash - - source "$HOME/.nvm/nvm.sh" + - \. "$HOME/.nvm/nvm.sh" - nvm use - if ! which yarn; do npm install --global yarn; done - yarn install --frozen-lockfile --network-timeout 600000 From 9ae4781bd8502e56935661940c4435eaa95f5023 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 15:16:06 +0000 Subject: [PATCH 43/97] ci: fix nvm exit code 3 --- .woodpecker/build-linux.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index e3e363e129..96c3d8481e 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -12,7 +12,8 @@ steps: - apt-get install git build-essential cmake -y - curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.2/install.sh | bash - \. "$HOME/.nvm/nvm.sh" - - nvm use + - nvm install 18.15.0 + - nvm use 18.15.0 - if ! which yarn; do npm install --global yarn; done - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything From 2f52175c993d0fd3ee96d8604c93b8a048e8ff92 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 20 Mar 2025 15:21:43 +0000 Subject: [PATCH 44/97] ci: fix unreadable nvm error --- .woodpecker/build-linux.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 96c3d8481e..ff7c45f7af 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -10,10 +10,8 @@ steps: - apt-get update - python3 -m pip install --upgrade pip setuptools - apt-get install git build-essential cmake -y - - curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.2/install.sh | bash - - \. "$HOME/.nvm/nvm.sh" - - nvm install 18.15.0 - - nvm use 18.15.0 + - curl -o- https://fnm.vercel.app/install | bash + - fnm install 18.15.0 - if ! which yarn; do npm install --global yarn; done - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything From 9ea4ea98baf63610fd5983ab5b6636fce885392e Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 21 Mar 2025 10:24:59 +0000 Subject: [PATCH 45/97] ci: fix fnm cannot infer shell --- .woodpecker/build-linux.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index ff7c45f7af..cfa3b24b28 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -15,6 +15,7 @@ steps: - if ! which yarn; do npm install --global yarn; done - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything + entrypoint: ["/bin/bash", "-c", "echo $CI_SCRIPT | base64 -d | /bin/bash -e"] publish: image: woodpeckerci/plugin-release From 346178945ee029a9141d5c4e452f4777951ef410 Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 21 Mar 2025 10:24:59 +0000 Subject: [PATCH 46/97] ci: fix fnm cannot infer shell --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index cfa3b24b28..7cfb28b263 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -11,7 +11,7 @@ steps: - python3 -m pip install --upgrade pip setuptools - apt-get install git build-essential cmake -y - curl -o- https://fnm.vercel.app/install | bash - - fnm install 18.15.0 + - SHELL=/bin/bash fnm install 18.15.0 - if ! which yarn; do npm install --global yarn; done - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything From ff0944e5548b0ff17e191ad47626aac2a0d0ce30 Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 21 Mar 2025 10:24:59 +0000 Subject: [PATCH 47/97] ci: fix fnm cannot infer shell --- .woodpecker/build-linux.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 7cfb28b263..d31bdba0ac 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -10,8 +10,9 @@ steps: - apt-get update - python3 -m pip install --upgrade pip setuptools - apt-get install git build-essential cmake -y - - curl -o- https://fnm.vercel.app/install | bash - - SHELL=/bin/bash fnm install 18.15.0 + - curl -fsSL https://fnm.vercel.app/install | bash -s -- --skip-shell + - eval "$(fnm env --use-on-cd --shell bash)" + - fnm install 18.15.0 - if ! which yarn; do npm install --global yarn; done - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything From c07887f62e7d6db541830d4993e6b246b2655cdc Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 21 Mar 2025 10:24:59 +0000 Subject: [PATCH 48/97] ci: fix fnm not found --- .woodpecker/build-linux.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index d31bdba0ac..07c1225ac0 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -10,9 +10,10 @@ steps: - apt-get update - python3 -m pip install --upgrade pip setuptools - apt-get install git build-essential cmake -y - - curl -fsSL https://fnm.vercel.app/install | bash -s -- --skip-shell - - eval "$(fnm env --use-on-cd --shell bash)" - - fnm install 18.15.0 + - curl -fsSL https://fnm.vercel.app/install | bash -s -- --skip-shell --install-dir "/.fnm" + - eval "$(/.fnm/fnm env --use-on-cd --shell bash)" + - /.fnm/fnm install + - /.fnm/fnm use - if ! which yarn; do npm install --global yarn; done - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything From 18cc541bd2a3c0c9517ec9dfcad8c8a9dfa5d16e Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 21 Mar 2025 10:24:59 +0000 Subject: [PATCH 49/97] ci: fix fnm not found --- .woodpecker/build-linux.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 07c1225ac0..635fd1f503 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -11,9 +11,10 @@ steps: - python3 -m pip install --upgrade pip setuptools - apt-get install git build-essential cmake -y - curl -fsSL https://fnm.vercel.app/install | bash -s -- --skip-shell --install-dir "/.fnm" - - eval "$(/.fnm/fnm env --use-on-cd --shell bash)" - - /.fnm/fnm install - - /.fnm/fnm use + - export PATH="/.fnm:$PATH" + - eval "$(fnm env --use-on-cd --shell bash)" + - fnm install + - fnm use - if ! which yarn; do npm install --global yarn; done - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything From 612464456f80fb60adb69b15af8dc7a5ec3bfecb Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 21 Mar 2025 14:52:12 +0000 Subject: [PATCH 50/97] ci: limit build branches --- .woodpecker/build-linux.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 635fd1f503..a8d107f300 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -2,6 +2,7 @@ when: - path: exclude: ['*.md'] event: "push" + branch: ["woodpecker-ci", "dev-gravel"] steps: build: From 9ae6f6c1c304dd9db3a981a78508b7e4f9efa21d Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 21 Mar 2025 14:57:15 +0000 Subject: [PATCH 51/97] ci: fix node version not installed --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index a8d107f300..b81de823d6 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -13,7 +13,7 @@ steps: - apt-get install git build-essential cmake -y - curl -fsSL https://fnm.vercel.app/install | bash -s -- --skip-shell --install-dir "/.fnm" - export PATH="/.fnm:$PATH" - - eval "$(fnm env --use-on-cd --shell bash)" + - eval "$(fnm env --shell bash)" - fnm install - fnm use - if ! which yarn; do npm install --global yarn; done From 22b21c1c7339d3f896e00aa02e0de74861fc49c6 Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 21 Mar 2025 15:03:20 +0000 Subject: [PATCH 52/97] ci: fix syntax error --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index b81de823d6..43b56d827d 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -16,7 +16,7 @@ steps: - eval "$(fnm env --shell bash)" - fnm install - fnm use - - if ! which yarn; do npm install --global yarn; done + - if ! which yarn; then npm install --global yarn; done - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything entrypoint: ["/bin/bash", "-c", "echo $CI_SCRIPT | base64 -d | /bin/bash -e"] From e015d59d6a8eaeb733c25f120b3d6086ee12693d Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 21 Mar 2025 15:04:34 +0000 Subject: [PATCH 53/97] ci: fix syntax error --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 43b56d827d..fccacbe8d2 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -16,7 +16,7 @@ steps: - eval "$(fnm env --shell bash)" - fnm install - fnm use - - if ! which yarn; then npm install --global yarn; done + - if ! which yarn; then npm install --global yarn; fi - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything entrypoint: ["/bin/bash", "-c", "echo $CI_SCRIPT | base64 -d | /bin/bash -e"] From 7bbf5daa27464e11d205069c41d2b428cf061995 Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 21 Mar 2025 15:18:19 +0000 Subject: [PATCH 54/97] ci: build actual release AppImage --- .woodpecker/build-linux.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index fccacbe8d2..6e0f61d92b 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -19,6 +19,7 @@ steps: - if ! which yarn; then npm install --global yarn; fi - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything + - yarn build-release --linux appImage entrypoint: ["/bin/bash", "-c", "echo $CI_SCRIPT | base64 -d | /bin/bash -e"] publish: From 1249e41b1243598e45aeed90c0b2e64436072e47 Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 21 Mar 2025 15:22:42 +0000 Subject: [PATCH 55/97] ci: fix trigger release for non-tag --- .woodpecker/build-linux.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 6e0f61d92b..f283f54236 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -1,7 +1,7 @@ when: - path: exclude: ['*.md'] - event: "push" + event: ["push", "tag"] branch: ["woodpecker-ci", "dev-gravel"] steps: @@ -29,3 +29,5 @@ steps: - "release/*.AppImage" api_key: from_secret: ACCESS_TOKEN + when: + event: tag From db23779bb8fd4d89c1bc862555d707e485da6fd0 Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 21 Mar 2025 16:07:19 +0000 Subject: [PATCH 56/97] ci: add [nolinux] keyword --- .woodpecker/build-linux.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index f283f54236..bb5485cbd9 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -3,6 +3,7 @@ when: exclude: ['*.md'] event: ["push", "tag"] branch: ["woodpecker-ci", "dev-gravel"] + evaluate: 'not (CI_COMMIT_MESSAGE contains "[nolinux]")' steps: build: From 6b4723e2461de3494e55c2212d0f1e282729ce0c Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 21 Mar 2025 16:07:40 +0000 Subject: [PATCH 57/97] ci: customize artifact name [skip ci] --- .woodpecker/build-linux.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index bb5485cbd9..22dfe2ead0 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -9,6 +9,8 @@ steps: build: image: docker.io/python:3.12-bookworm commands: + - export ARTIFACT_VERSION="$${CI_COMMIT_TAG=${CI_COMMIT_SHA:0:6}}" + - echo "Compiling version $ARTIFACT_VERSION" - apt-get update - python3 -m pip install --upgrade pip setuptools - apt-get install git build-essential cmake -y @@ -20,7 +22,7 @@ steps: - if ! which yarn; then npm install --global yarn; fi - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything - - yarn build-release --linux appImage + - yarn build-release --linux appImage --config.artifactName="$${name}-$${os}-$${arch}-${CI_REPO_OWNER}-${ARTIFACT_VERSION}.$${ext}" entrypoint: ["/bin/bash", "-c", "echo $CI_SCRIPT | base64 -d | /bin/bash -e"] publish: From dd0ca06222295c9090b20ae9f6da8573929f833f Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 21 Mar 2025 16:16:32 +0000 Subject: [PATCH 58/97] ci: manage version in package.json --- .woodpecker/build-linux.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 22dfe2ead0..12c020128e 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -9,8 +9,6 @@ steps: build: image: docker.io/python:3.12-bookworm commands: - - export ARTIFACT_VERSION="$${CI_COMMIT_TAG=${CI_COMMIT_SHA:0:6}}" - - echo "Compiling version $ARTIFACT_VERSION" - apt-get update - python3 -m pip install --upgrade pip setuptools - apt-get install git build-essential cmake -y @@ -22,7 +20,7 @@ steps: - if ! which yarn; then npm install --global yarn; fi - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything - - yarn build-release --linux appImage --config.artifactName="$${name}-$${os}-$${arch}-${CI_REPO_OWNER}-${ARTIFACT_VERSION}.$${ext}" + - yarn build-release --linux appImage --config.artifactName="$${name}-$${os}-$${arch}-${CI_REPO_OWNER}-${version}.$${ext}" entrypoint: ["/bin/bash", "-c", "echo $CI_SCRIPT | base64 -d | /bin/bash -e"] publish: From 67e49da1bc0ed2b7e1fcf823af4fd591d7584068 Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 21 Mar 2025 16:17:13 +0000 Subject: [PATCH 59/97] chore: bump version to 1.15.0-0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 984b162e5f..822f8fe6e4 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.15.0", + "version": "1.15.0-0.1", "license": "GPL-3.0", "author": { "name": "Session Foundation", From d455d575aa734915ed168c2362d3078f29a8ddce Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 21 Mar 2025 16:55:55 +0000 Subject: [PATCH 60/97] ci: test releasing [nolinux][testreleasing] --- .woodpecker/test-releasing.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .woodpecker/test-releasing.yaml diff --git a/.woodpecker/test-releasing.yaml b/.woodpecker/test-releasing.yaml new file mode 100644 index 0000000000..c3c61b3dda --- /dev/null +++ b/.woodpecker/test-releasing.yaml @@ -0,0 +1,13 @@ +when: + - evaluate: 'CI_COMMIT_MESSAGE contains [testreleasing]' + event: ["tag"] + +steps: + publish: + image: woodpeckerci/plugin-release + settings: + draft: true + files: + - .woodpecker/test-releasing.yaml + api_key: + from_secret: ACCESS_TOKEN From 9b36571065487d32e28958a97c348f233713573e Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 21 Mar 2025 16:57:28 +0000 Subject: [PATCH 61/97] ci: test releasing [nolinux][testreleasing] --- .woodpecker/test-releasing.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/test-releasing.yaml b/.woodpecker/test-releasing.yaml index c3c61b3dda..7618fcd6fe 100644 --- a/.woodpecker/test-releasing.yaml +++ b/.woodpecker/test-releasing.yaml @@ -1,5 +1,5 @@ when: - - evaluate: 'CI_COMMIT_MESSAGE contains [testreleasing]' + - evaluate: 'CI_COMMIT_MESSAGE contains "[testreleasing]"' event: ["tag"] steps: From 6788a2c71a7f6ea4b94803c7acbfb30be2a49ae9 Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 21 Mar 2025 17:05:41 +0000 Subject: [PATCH 62/97] ci: test releasing [nolinux][testreleasing] --- .woodpecker/build-linux.yaml | 2 +- .woodpecker/test-releasing.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 12c020128e..39030710d3 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -3,7 +3,7 @@ when: exclude: ['*.md'] event: ["push", "tag"] branch: ["woodpecker-ci", "dev-gravel"] - evaluate: 'not (CI_COMMIT_MESSAGE contains "[nolinux]")' + evaluate: 'not (CI_COMMIT_MESSAGE contains "[nolinux]") and (not CI_COMMIT_TAG contains "releasetest")' steps: build: diff --git a/.woodpecker/test-releasing.yaml b/.woodpecker/test-releasing.yaml index 7618fcd6fe..1ced933854 100644 --- a/.woodpecker/test-releasing.yaml +++ b/.woodpecker/test-releasing.yaml @@ -1,5 +1,5 @@ when: - - evaluate: 'CI_COMMIT_MESSAGE contains "[testreleasing]"' + - evaluate: 'CI_COMMIT_TAG contains "releasetest"' event: ["tag"] steps: From 593aad67112a5039fd536d93aa75da2b72a9a12d Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 21 Mar 2025 17:06:42 +0000 Subject: [PATCH 63/97] ci: test releasing [nolinux][testreleasing] --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 39030710d3..f0f32a7e45 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -3,7 +3,7 @@ when: exclude: ['*.md'] event: ["push", "tag"] branch: ["woodpecker-ci", "dev-gravel"] - evaluate: 'not (CI_COMMIT_MESSAGE contains "[nolinux]") and (not CI_COMMIT_TAG contains "releasetest")' + evaluate: 'not (CI_COMMIT_MESSAGE contains "[nolinux]") and not (CI_COMMIT_TAG contains "releasetest")' steps: build: From a121c7bca86ce5be7a6cfb1aaac9f86ceba174c9 Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 21 Mar 2025 17:13:31 +0000 Subject: [PATCH 64/97] ci: fix wrong artifact name --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index f0f32a7e45..7ac52ce31a 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -20,7 +20,7 @@ steps: - if ! which yarn; then npm install --global yarn; fi - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything - - yarn build-release --linux appImage --config.artifactName="$${name}-$${os}-$${arch}-${CI_REPO_OWNER}-${version}.$${ext}" + - yarn build-release --linux appImage --config.artifactName="$${name}-$${os}-$${arch}-${CI_REPO_OWNER}-$${version}.$${ext}" entrypoint: ["/bin/bash", "-c", "echo $CI_SCRIPT | base64 -d | /bin/bash -e"] publish: From c6807f704fcb078fcf0ff7d3fe74a7306774e7e7 Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 21 Mar 2025 17:25:38 +0000 Subject: [PATCH 65/97] ci: fix wrong artifact name --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 7ac52ce31a..29d9760ca1 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -20,7 +20,7 @@ steps: - if ! which yarn; then npm install --global yarn; fi - yarn install --frozen-lockfile --network-timeout 600000 - yarn build-everything - - yarn build-release --linux appImage --config.artifactName="$${name}-$${os}-$${arch}-${CI_REPO_OWNER}-$${version}.$${ext}" + - yarn build-release --linux appImage --config.artifactName='$${name}-$${os}-$${arch}-${CI_REPO_OWNER}-$${version}.$${ext}' entrypoint: ["/bin/bash", "-c", "echo $CI_SCRIPT | base64 -d | /bin/bash -e"] publish: From a4205776103c68b4b061a375a73c4ea23f21a09f Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 21 Mar 2025 17:46:16 +0000 Subject: [PATCH 66/97] chore: bump version in package.json [skip ci] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 822f8fe6e4..1a5ddf0549 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.15.0-0.1", + "version": "1.15.0-0.6", "license": "GPL-3.0", "author": { "name": "Session Foundation", From 94dd767cc1ff960cab3d06c31c43353a3adf30a8 Mon Sep 17 00:00:00 2001 From: gravel Date: Sun, 27 Apr 2025 20:47:53 +0000 Subject: [PATCH 67/97] fix: increase message length to accommodate PGP --- ts/session/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ts/session/constants.ts b/ts/session/constants.ts index 8735ccbddb..65028c4f0b 100644 --- a/ts/session/constants.ts +++ b/ts/session/constants.ts @@ -79,7 +79,7 @@ export const CONVERSATION = { LAST_JOINED_FALLBACK_TIMESTAMP: 1, /** * the maximum chars that can be typed/pasted in the composition box. - * Same as android. + * Increased to accommodate PGP payloads. */ MAX_MESSAGE_CHAR_COUNT: 2000, } as const; From d5e98142322235c862889f6451ce16f464b47f5b Mon Sep 17 00:00:00 2001 From: gravel Date: Sun, 27 Apr 2025 20:48:17 +0000 Subject: [PATCH 68/97] chore: bump to 1.15.2-0.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4172dee3c2..fea2d9cfc1 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.15.2", + "version": "1.15.2-0.5", "license": "GPL-3.0", "author": { "name": "Session Foundation", From 1a1783880992d9b9b54c5fd5d2234603d24f3171 Mon Sep 17 00:00:00 2001 From: gravel Date: Sun, 27 Apr 2025 21:16:54 +0000 Subject: [PATCH 69/97] fix: increase message length to accommodate PGP --- ts/session/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ts/session/constants.ts b/ts/session/constants.ts index 65028c4f0b..a7aa78c12c 100644 --- a/ts/session/constants.ts +++ b/ts/session/constants.ts @@ -81,7 +81,7 @@ export const CONVERSATION = { * the maximum chars that can be typed/pasted in the composition box. * Increased to accommodate PGP payloads. */ - MAX_MESSAGE_CHAR_COUNT: 2000, + MAX_MESSAGE_CHAR_COUNT: 10000, } as const; /** From 198266c3c70e0c07418dd08adf07b3619add451c Mon Sep 17 00:00:00 2001 From: gravel Date: Sun, 27 Apr 2025 21:17:26 +0000 Subject: [PATCH 70/97] chore: bump to 1.15.2-0.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fea2d9cfc1..9426761efe 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.15.2-0.5", + "version": "1.15.2-0.6", "license": "GPL-3.0", "author": { "name": "Session Foundation", From 1353cc15da8163a8550e44beabb59e72540ea056 Mon Sep 17 00:00:00 2001 From: gravel Date: Sat, 24 May 2025 07:07:21 +0000 Subject: [PATCH 71/97] chore: bump to 1.16.1-0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b407e32381..4c072cc6c3 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.16.1", + "version": "1.16.1-0.1", "license": "GPL-3.0", "author": { "name": "Session Foundation", From 79d9e8e4d9b3eb4fefde04a4532b456fe608f632 Mon Sep 17 00:00:00 2001 From: gravel Date: Sun, 8 Jun 2025 11:11:22 +0000 Subject: [PATCH 72/97] chore: bump to v1.16.2-0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 84164dce85..3de1e86408 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.16.2", + "version": "1.16.2-0.1", "license": "GPL-3.0", "author": { "name": "Session Foundation", From 455fc72c6e1225fc779703e84d39620b73ec7ba5 Mon Sep 17 00:00:00 2001 From: gravel Date: Sun, 6 Jul 2025 10:45:45 +0000 Subject: [PATCH 73/97] chore: bump to v1.16.3-0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 95167abe9d..5e0d1f335a 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.16.3", + "version": "1.16.3-0.1", "license": "GPL-3.0", "author": { "name": "Session Foundation", From ee495965824979d658ac318a2e530accbf06c502 Mon Sep 17 00:00:00 2001 From: gravel Date: Sun, 6 Jul 2025 10:46:32 +0000 Subject: [PATCH 74/97] ci: do not run on push to dev --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 29d9760ca1..87c99c4aa3 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -2,7 +2,7 @@ when: - path: exclude: ['*.md'] event: ["push", "tag"] - branch: ["woodpecker-ci", "dev-gravel"] + branch: ["woodpecker-ci"] evaluate: 'not (CI_COMMIT_MESSAGE contains "[nolinux]") and not (CI_COMMIT_TAG contains "releasetest")' steps: From 4fb1ecd2bbf93c8e011dad8290caf55bac1beedc Mon Sep 17 00:00:00 2001 From: gravel Date: Tue, 22 Jul 2025 07:11:54 +0000 Subject: [PATCH 75/97] chore: bump to v1.16.5-0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6f90d78d04..c12444df6e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.16.5", + "version": "1.16.5-0.1", "license": "GPL-3.0", "author": { "name": "Session Foundation", From 3067c23b14b5934b354c18160913694072e04a5f Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 14 Aug 2025 14:40:55 +0000 Subject: [PATCH 76/97] chore: bump to v1.16.6-0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d8b5a6a46a..5acacca868 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.16.6", + "version": "1.16.6-0.1", "license": "GPL-3.0", "author": { "name": "Session Foundation", From 7f52653075628691e55ada87810c1cadaefd0811 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 14 Aug 2025 14:50:38 +0000 Subject: [PATCH 77/97] ci: fix updated yarn command --- .woodpecker/build-linux.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml index 87c99c4aa3..b6840a01db 100644 --- a/.woodpecker/build-linux.yaml +++ b/.woodpecker/build-linux.yaml @@ -19,7 +19,7 @@ steps: - fnm use - if ! which yarn; then npm install --global yarn; fi - yarn install --frozen-lockfile --network-timeout 600000 - - yarn build-everything + - yarn build - yarn build-release --linux appImage --config.artifactName='$${name}-$${os}-$${arch}-${CI_REPO_OWNER}-$${version}.$${ext}' entrypoint: ["/bin/bash", "-c", "echo $CI_SCRIPT | base64 -d | /bin/bash -e"] From b69e0421130ebb357783b1d9813c47274ba8fbc3 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 14 Aug 2025 14:50:57 +0000 Subject: [PATCH 78/97] chore: bump to v1.16.6-0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5acacca868..ce771a1a4e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.16.6-0.1", + "version": "1.16.6-0.2", "license": "GPL-3.0", "author": { "name": "Session Foundation", From 6a0765a8d26998ee69aa05a778e2d3edaf6eb1e8 Mon Sep 17 00:00:00 2001 From: gravel Date: Sat, 13 Sep 2025 10:28:05 +0000 Subject: [PATCH 79/97] chore: bump to v1.16.8-0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0c70e35f5b..4c36125403 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.16.8", + "version": "1.16.8-0.1", "license": "GPL-3.0", "author": { "name": "Session Foundation", From 06d768528f989b39a7c66d6d32efd136e4802a70 Mon Sep 17 00:00:00 2001 From: gravel Date: Sat, 20 Sep 2025 07:29:41 +0000 Subject: [PATCH 80/97] chore: bump to v1.16.10-0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4120f7ce26..f52689eed8 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.16.10", + "version": "1.16.10-0.1", "license": "GPL-3.0", "author": { "name": "Session Foundation", From 33c103788a8203b8c678bd571e8900f17066078c Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 3 Oct 2025 09:19:37 +0000 Subject: [PATCH 81/97] chore: bump to v1.17.0-0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5b3ab132a4..23763c8b5b 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.17.0", + "version": "1.17.0-0.1", "license": "GPL-3.0", "author": { "name": "Session Foundation", From 7bb2fad4f5993629cceeb43adeaa44e5fa967e29 Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 3 Oct 2025 13:28:21 +0000 Subject: [PATCH 82/97] fix: unbreak after upstream refactors --- ts/components/dialog/BanOrUnbanUserDialog.tsx | 5 +- .../dialog/UpdateGroupPermissionsDialog.tsx | 68 ++++++++++++++----- .../conversationSettingsItems.tsx | 2 +- ts/react.d.ts | 1 + ts/state/ducks/modalDialog.tsx | 1 + 5 files changed, 57 insertions(+), 20 deletions(-) diff --git a/ts/components/dialog/BanOrUnbanUserDialog.tsx b/ts/components/dialog/BanOrUnbanUserDialog.tsx index a7ae051430..5013bca481 100644 --- a/ts/components/dialog/BanOrUnbanUserDialog.tsx +++ b/ts/components/dialog/BanOrUnbanUserDialog.tsx @@ -227,7 +227,7 @@ export const ServerBanOrUnBanUserDialog = (props: { const [inputBoxValue, setInputBoxValue] = useState(''); const [inProgress, setInProgress] = useState(false); - const displayName = useConversationUsername(pubkey); + const displayName = useConversationUsernameWithFallback(true, pubkey); const inputTextToDisplay = !!pubkey && displayName ? `${displayName} ${PubKey.shorten(pubkey)}` : undefined; @@ -272,10 +272,11 @@ export const ServerBanOrUnBanUserDialog = (props: { }; return ( } onClose={onClose} buttonChildren={ - + { return ( } onClose={() => this.closeDialog()} > @@ -122,29 +124,61 @@ export class UpdateGroupPermissionsDialog extends Component { you can set new values below regardless.

- + } active={this.state.default_accessible} - onClickToggle={() => this.onPermissionChanged('default_accessible')} + onClick={async () => this.onPermissionChanged('default_accessible')} + rowDataTestId='test-ignore' + toggleDataTestId='test-ignore' /> - + } active={this.state.default_read} - onClickToggle={() => this.onPermissionChanged('default_read')} + onClick={async () => this.onPermissionChanged('default_read')} + rowDataTestId='test-ignore' + toggleDataTestId='test-ignore' /> - + } active={this.state.default_write} - onClickToggle={() => this.onPermissionChanged('default_write')} + onClick={async () => this.onPermissionChanged('default_write')} + rowDataTestId='test-ignore' + toggleDataTestId='test-ignore' /> - + } active={this.state.default_upload} - onClickToggle={() => this.onPermissionChanged('default_upload')} + onClick={async () => this.onPermissionChanged('default_upload')} + rowDataTestId='test-ignore' + toggleDataTestId='test-ignore' />
diff --git a/ts/components/dialog/conversationSettings/conversationSettingsItems.tsx b/ts/components/dialog/conversationSettings/conversationSettingsItems.tsx index bc45728f05..4030b00071 100644 --- a/ts/components/dialog/conversationSettings/conversationSettingsItems.tsx +++ b/ts/components/dialog/conversationSettings/conversationSettingsItems.tsx @@ -287,7 +287,7 @@ export function ChangeCommunityPermissionsButton({ conversationId }: WithConvoId iconElement={ } - text={tr('groupChangePermissions').toString()} + text={{ token: 'groupChangePermissions' }} onClick={cb} dataTestId="edit-group-name" /> diff --git a/ts/react.d.ts b/ts/react.d.ts index a2a92a24d6..c9d293b84a 100644 --- a/ts/react.d.ts +++ b/ts/react.d.ts @@ -401,6 +401,7 @@ declare module 'react' { | 'empty-msg-view-welcome' | 'last-updated-timestamp' | 'account-id-pill' + | 'test-ignore' // Once the whole app have datatestId when required, this `invalid-data-testid` will be removed | 'invalid-data-testid'; diff --git a/ts/state/ducks/modalDialog.tsx b/ts/state/ducks/modalDialog.tsx index 2fa6d55a8c..21b67dd1c8 100644 --- a/ts/state/ducks/modalDialog.tsx +++ b/ts/state/ducks/modalDialog.tsx @@ -108,6 +108,7 @@ export type ModalId = | 'confirmModal' | 'inviteContactModal' | 'banOrUnbanUserModal' + | 'serverBanOrUnbanUserModal' | 'blockOrUnblockModal' | 'removeModeratorsModal' | 'addModeratorsModal' From 86ad920a32b6e9cd3893e749dbb1b0657c3e3466 Mon Sep 17 00:00:00 2001 From: gravel Date: Fri, 3 Oct 2025 13:55:20 +0000 Subject: [PATCH 83/97] chore: bump to v1.17.0-0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 23763c8b5b..193ee68511 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.17.0-0.1", + "version": "1.17.0-0.2", "license": "GPL-3.0", "author": { "name": "Session Foundation", From c718c820b53b527b3cb7dd26eeb48a650fd413ce Mon Sep 17 00:00:00 2001 From: gravel Date: Sun, 5 Oct 2025 16:14:09 +0000 Subject: [PATCH 84/97] fix: unbreak after upstream refactors --- _locales/en/messages.json | 10 +++++++++- .../dialog/UpdateGroupPermissionsDialog.tsx | 16 ++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 4fda09f996..68f759db79 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -510,7 +510,15 @@ "groupNoMessages": "You have no messages from {group_name}. Send a message to start the conversation!", "groupNotUpdatedWarning": "This group has not been updated in over 30 days. You may experience issues sending messages or viewing group information.", "groupOnlyAdmin": "You are the only admin in {group_name}.

Group members and settings cannot be changed without an admin.", - "groupPendingRemoval": "Pending removal", + "groupPendingemoval": "Pending removal", + "groupPermissionAccessDescription": "Anyone can see the room (+a)", + "groupPermissionAccessEnable": "Enable room visibility", + "groupPermissionReadDescription": "Anyone can read messages (+r)", + "groupPermissionReadEnable": "Enable reading", + "groupPermissionUploadDescription": "Anyone can upload files (+u)", + "groupPermissionUploadEnable": "Enable uploads", + "groupPermissionWriteDescription": "Anyone can send messages (+w)", + "groupPermissionWriteEnable": "Enable writing", "groupPromotedYou": "You were promoted to Admin.", "groupPromotedYouMultiple": "You and {count} others were promoted to Admin.", "groupPromotedYouTwo": "You and {other_name} were promoted to Admin.", diff --git a/ts/components/dialog/UpdateGroupPermissionsDialog.tsx b/ts/components/dialog/UpdateGroupPermissionsDialog.tsx index e9f1d32029..f957173ea1 100644 --- a/ts/components/dialog/UpdateGroupPermissionsDialog.tsx +++ b/ts/components/dialog/UpdateGroupPermissionsDialog.tsx @@ -127,8 +127,8 @@ export class UpdateGroupPermissionsDialog extends Component { @@ -141,8 +141,8 @@ export class UpdateGroupPermissionsDialog extends Component { @@ -155,8 +155,8 @@ export class UpdateGroupPermissionsDialog extends Component { @@ -169,8 +169,8 @@ export class UpdateGroupPermissionsDialog extends Component { From 686aa2f0c7f95e868c3d627ea8aa96f36bf3f499 Mon Sep 17 00:00:00 2001 From: gravel Date: Sun, 5 Oct 2025 16:14:37 +0000 Subject: [PATCH 85/97] chore: bump to v1.17.0-0.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 193ee68511..2a310fb170 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.17.0-0.2", + "version": "1.17.0-0.3", "license": "GPL-3.0", "author": { "name": "Session Foundation", From fd2285f6a8fc0af0cfab080122fe87c13df01aa5 Mon Sep 17 00:00:00 2001 From: gravel Date: Sun, 5 Oct 2025 16:31:25 +0000 Subject: [PATCH 86/97] fix: fix typo --- _locales/en/messages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 68f759db79..b2f90ffe14 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -510,7 +510,7 @@ "groupNoMessages": "You have no messages from {group_name}. Send a message to start the conversation!", "groupNotUpdatedWarning": "This group has not been updated in over 30 days. You may experience issues sending messages or viewing group information.", "groupOnlyAdmin": "You are the only admin in {group_name}.

Group members and settings cannot be changed without an admin.", - "groupPendingemoval": "Pending removal", + "groupPendingRemoval": "Pending removal", "groupPermissionAccessDescription": "Anyone can see the room (+a)", "groupPermissionAccessEnable": "Enable room visibility", "groupPermissionReadDescription": "Anyone can read messages (+r)", From e45f10bfa9dab908aa7b548ef7a23a9319909349 Mon Sep 17 00:00:00 2001 From: gravel Date: Sun, 5 Oct 2025 16:31:48 +0000 Subject: [PATCH 87/97] chore: bump to v1.17.0-0.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2a310fb170..d7d9aad5d0 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.17.0-0.3", + "version": "1.17.0-0.4", "license": "GPL-3.0", "author": { "name": "Session Foundation", From 9a353095b21f7dcf2b4aac090ad223ac279f38a1 Mon Sep 17 00:00:00 2001 From: gravel Date: Sun, 5 Oct 2025 17:32:36 +0000 Subject: [PATCH 88/97] chore: bump to v1.17.1-0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1deb614e8c..775676bb30 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.17.1", + "version": "1.17.1-0.1", "license": "GPL-3.0", "author": { "name": "Session Foundation", From 0e1013d2b32a780b9ad4086c396d01b538b7438d Mon Sep 17 00:00:00 2001 From: gravel Date: Mon, 3 Nov 2025 19:34:50 +0000 Subject: [PATCH 89/97] chore: bump to v1.17.2-0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d31f1c76e9..3629a3f073 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.17.2", + "version": "1.17.2-0.1", "license": "GPL-3.0", "author": { "name": "Session Foundation", From 2b554414d0472f5b93651b219a2594ef81baa6fc Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 11 Dec 2025 12:02:16 +0000 Subject: [PATCH 90/97] chore: bump to v1.17.4-0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b67e60ad51..88eae66946 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.17.4", + "version": "1.17.4-0.1", "license": "GPL-3.0", "author": { "name": "Session Foundation", From 0b968b94eb646c1a49dc2d9147b7f7aa54e0de02 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 11 Dec 2025 12:26:48 +0000 Subject: [PATCH 91/97] chore: bump to v1.17.4-0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 88eae66946..41c3343e3f 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.17.4-0.1", + "version": "1.17.4-0.2", "license": "GPL-3.0", "author": { "name": "Session Foundation", From 86f130506447716bcc6147fa668391bc01554445 Mon Sep 17 00:00:00 2001 From: gravel Date: Thu, 25 Dec 2025 10:55:27 +0000 Subject: [PATCH 92/97] chore: bump to v1.17.5-0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fdb767fbef..48ddf39644 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.17.5", + "version": "1.17.5-0.1", "license": "GPL-3.0", "author": { "name": "Session Foundation", From 93caf27ab09909da003f5aa202769c5e3e84d777 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Tue, 3 Feb 2026 15:41:53 +1100 Subject: [PATCH 93/97] fix: modernize global server ban/unban --- .woodpecker/build-linux.yaml | 34 --- .woodpecker/test-releasing.yaml | 13 - .../message-content/MessageContextMenu.tsx | 75 +++--- ts/components/dialog/BanOrUnbanUserDialog.tsx | 230 +++++++----------- ts/components/dialog/ModalContainer.tsx | 17 +- .../UpdateCommunityPermissionsDialog.tsx | 155 ++++++++++++ .../dialog/UpdateGroupPermissionsDialog.tsx | 228 ----------------- .../conversationSettingsItems.tsx | 13 +- ts/components/dialog/debug/constants.ts | 8 +- ts/components/icon/Icons.tsx | 6 - ts/components/menu/Menu.tsx | 72 ++---- .../useAddUserPermissions.tsx | 69 ++++++ .../menuAndSettingsHooks/useBanUser.ts | 29 ++- .../useChangeCommunityPermissions.ts | 8 +- .../menuAndSettingsHooks/useServerBanUser.ts | 17 -- .../useServerUnbanUser.ts | 17 -- .../menuAndSettingsHooks/useUnbanUser.ts | 18 -- ts/interactions/conversationInteractions.ts | 49 ---- ts/interactions/messageInteractions.ts | 211 +--------------- ts/models/message.ts | 1 - ts/react.d.ts | 2 +- .../sogsv3/sogsV3AddRemoveMods.ts | 4 +- .../open_group_api/sogsv3/sogsV3BanUnban.ts | 140 +++++------ .../open_group_api/sogsv3/sogsV3BatchPoll.ts | 66 ++--- .../sogsv3/sogsV3RoomPermissions.ts | 10 +- .../sogsv3/sogsV3UserPermissions.ts | 6 +- ts/state/ducks/modalDialog.tsx | 53 ++-- ts/state/ducks/types/defaultFeatureFlags.ts | 1 + .../ducks/types/releasedFeaturesReduxTypes.ts | 1 + ts/state/selectors/modal.ts | 8 +- 30 files changed, 563 insertions(+), 998 deletions(-) delete mode 100644 .woodpecker/build-linux.yaml delete mode 100644 .woodpecker/test-releasing.yaml create mode 100644 ts/components/dialog/UpdateCommunityPermissionsDialog.tsx delete mode 100644 ts/components/dialog/UpdateGroupPermissionsDialog.tsx create mode 100644 ts/components/menuAndSettingsHooks/useAddUserPermissions.tsx delete mode 100644 ts/components/menuAndSettingsHooks/useServerBanUser.ts delete mode 100644 ts/components/menuAndSettingsHooks/useServerUnbanUser.ts delete mode 100644 ts/components/menuAndSettingsHooks/useUnbanUser.ts diff --git a/.woodpecker/build-linux.yaml b/.woodpecker/build-linux.yaml deleted file mode 100644 index b6840a01db..0000000000 --- a/.woodpecker/build-linux.yaml +++ /dev/null @@ -1,34 +0,0 @@ -when: - - path: - exclude: ['*.md'] - event: ["push", "tag"] - branch: ["woodpecker-ci"] - evaluate: 'not (CI_COMMIT_MESSAGE contains "[nolinux]") and not (CI_COMMIT_TAG contains "releasetest")' - -steps: - build: - image: docker.io/python:3.12-bookworm - commands: - - apt-get update - - python3 -m pip install --upgrade pip setuptools - - apt-get install git build-essential cmake -y - - curl -fsSL https://fnm.vercel.app/install | bash -s -- --skip-shell --install-dir "/.fnm" - - export PATH="/.fnm:$PATH" - - eval "$(fnm env --shell bash)" - - fnm install - - fnm use - - if ! which yarn; then npm install --global yarn; fi - - yarn install --frozen-lockfile --network-timeout 600000 - - yarn build - - yarn build-release --linux appImage --config.artifactName='$${name}-$${os}-$${arch}-${CI_REPO_OWNER}-$${version}.$${ext}' - entrypoint: ["/bin/bash", "-c", "echo $CI_SCRIPT | base64 -d | /bin/bash -e"] - - publish: - image: woodpeckerci/plugin-release - settings: - files: - - "release/*.AppImage" - api_key: - from_secret: ACCESS_TOKEN - when: - event: tag diff --git a/.woodpecker/test-releasing.yaml b/.woodpecker/test-releasing.yaml deleted file mode 100644 index 1ced933854..0000000000 --- a/.woodpecker/test-releasing.yaml +++ /dev/null @@ -1,13 +0,0 @@ -when: - - evaluate: 'CI_COMMIT_TAG contains "releasetest"' - event: ["tag"] - -steps: - publish: - image: woodpeckerci/plugin-release - settings: - draft: true - files: - - .woodpecker/test-releasing.yaml - api_key: - from_secret: ACCESS_TOKEN diff --git a/ts/components/conversation/message/message-content/MessageContextMenu.tsx b/ts/components/conversation/message/message-content/MessageContextMenu.tsx index f2e37297c1..e699bcf056 100644 --- a/ts/components/conversation/message/message-content/MessageContextMenu.tsx +++ b/ts/components/conversation/message/message-content/MessageContextMenu.tsx @@ -47,13 +47,14 @@ import { WithMessageId } from '../../../../session/types/with'; import { DeleteItem } from '../../../menu/items/DeleteMessage/DeleteMessageMenuItem'; import { RetryItem } from '../../../menu/items/RetrySend/RetrySendMenuItem'; import { useBanUserCb } from '../../../menuAndSettingsHooks/useBanUser'; -import { useUnbanUserCb } from '../../../menuAndSettingsHooks/useUnbanUser'; import { tr } from '../../../../localization/localeTools'; import { sectionActions } from '../../../../state/ducks/section'; import { useRemoveSenderFromCommunityAdmin } from '../../../menuAndSettingsHooks/useRemoveSenderFromCommunityAdmin'; import { useAddSenderAsCommunityAdmin } from '../../../menuAndSettingsHooks/useAddSenderAsCommunityAdmin'; -import { useServerBanUserCb } from '../../../menuAndSettingsHooks/useServerBanUser'; -import { useServerUnbanUserCb } from '../../../menuAndSettingsHooks/useServerUnbanUser'; +import { + useAddUserPermissions, + useClearUserPermissions, +} from '../../../menuAndSettingsHooks/useAddUserPermissions'; export type MessageContextMenuSelectorProps = Pick< MessageRenderingProps, @@ -98,10 +99,27 @@ const CommunityAdminActionItems = ({ messageId }: WithMessageId) => { const sender = useMessageSender(messageId); const isSenderAdmin = useMessageSenderIsAdmin(messageId); - const banUserCb = useBanUserCb(convoId, sender); - const unbanUserCb = useUnbanUserCb(convoId, sender); - const serverBanUser = useServerBanUserCb(convoId, sender); - const serverUnbanUser = useServerUnbanUserCb(convoId, sender); + const sharedBanUnbanProps = { + conversationId: convoId, + pubkey: sender, + }; + + const banUserCb = useBanUserCb({ + banType: 'ban', + ...sharedBanUnbanProps, + }); + const unbanUserCb = useBanUserCb({ + banType: 'unban', + ...sharedBanUnbanProps, + }); + const serverBanUser = useBanUserCb({ + banType: 'server-ban', + ...sharedBanUnbanProps, + }); + const serverUnbanUser = useBanUserCb({ + banType: 'server-unban', + ...sharedBanUnbanProps, + }); const removeSenderFromCommunityAdminCb = useRemoveSenderFromCommunityAdmin({ conversationId: convoId, @@ -113,22 +131,16 @@ const CommunityAdminActionItems = ({ messageId }: WithMessageId) => { senderId: sender, }); - const addUploadPermission = () => { - void MessageInteraction.addUserPermissions(sender, convoId, ['upload']); - }; - - const clearUploadPermission = () => { - void MessageInteraction.clearUserPermissions(sender, convoId, ['upload']); - }; + const addUploadPermissionCb = useAddUserPermissions(sender, convoId, ['upload']); + const clearUploadPermissionCb = useClearUserPermissions(sender, convoId, ['upload']); - // TODO: This codebase is a pain. - // Fixed to `true`. + // Fixed to `true` as not currently exposed by the backend/tracked in session-desktop const isRoomUploadRestricted = true; const canSenderUpload = true; const canSenderNotUpload = true; // Note: add/removeSenderFromCommunityAdminCb can be null if we are a moderator only, see below - if (!convoId || !sender || !banUserCb || !unbanUserCb || !serverBanUser || !serverUnbanUser) { + if (!convoId || !sender || !banUserCb || !unbanUserCb) { return null; } @@ -148,24 +160,25 @@ const CommunityAdminActionItems = ({ messageId }: WithMessageId) => { {tr('adminPromoteToAdmin')} ) : null} - - {tr('serverBanUser').toString()} - - - {tr('serverUnbanUser').toString()} - + + {serverBanUser ? ( + {tr('serverBanUser')} + ) : null} + {serverUnbanUser ? ( + {tr('serverUnbanUser')} + ) : null} {!isSenderAdmin && isRoomUploadRestricted && ( <> - {canSenderUpload && ( - - {tr('addUploadPermission').toString()} + {canSenderUpload && addUploadPermissionCb ? ( + + {tr('addUploadPermission')} - )} - {canSenderNotUpload && ( - - {tr('clearUploadPermission').toString()} + ) : null} + {canSenderNotUpload && clearUploadPermissionCb ? ( + + {tr('clearUploadPermission')} - )} + ) : null} )} diff --git a/ts/components/dialog/BanOrUnbanUserDialog.tsx b/ts/components/dialog/BanOrUnbanUserDialog.tsx index 3b388ae523..d5e23a06d7 100644 --- a/ts/components/dialog/BanOrUnbanUserDialog.tsx +++ b/ts/components/dialog/BanOrUnbanUserDialog.tsx @@ -6,8 +6,6 @@ import { useConversationUsernameWithFallback } from '../../hooks/useParamSelecto import { ConversationModel } from '../../models/conversation'; import { sogsV3BanUser, - sogsV3ServerBanUser, - sogsV3ServerUnbanUser, sogsV3UnbanUser, } from '../../session/apis/open_group_api/sogsv3/sogsV3BanUnban'; import { ConvoHub } from '../../session/conversations/ConversationController'; @@ -15,8 +13,9 @@ import { PubKey } from '../../session/types'; import { ToastUtils } from '../../session/utils'; import { BanType, + isBan, + isServerBanUnban, updateBanOrUnbanUserModal, - updateServerBanOrUnbanUserModal, } from '../../state/ducks/modalDialog'; import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton'; import { SessionSpinner } from '../loading'; @@ -24,18 +23,21 @@ import { ModalBasicHeader, ModalActionsContainer, SessionWrapperModal, + WrapperModalWidth, } from '../SessionWrapperModal'; import { tr } from '../../localization/localeTools'; import { SimpleSessionInput } from '../inputs/SessionInput'; import { ModalDescription } from './shared/ModalDescriptionContainer'; import { ModalFlexContainer } from './shared/ModalFlexContainer'; +import { SessionToggle } from '../basic/SessionToggle'; +import { getFeatureFlag } from '../../state/ducks/types/releasedFeaturesReduxTypes'; +import { Flex } from '../basic/Flex'; async function banOrUnBanUserCall( convo: ConversationModel, textValue: string, banType: BanType, - deleteAll: boolean, - isGlobal: boolean + deleteAll: boolean ) { // if we don't have valid data entered by the user const pubkey = PubKey.from(textValue); @@ -47,37 +49,47 @@ async function banOrUnBanUserCall( try { // this is a v2 opengroup const roomInfos = convo.toOpenGroupV2(); - const isChangeApplied = - banType === 'ban' - ? isGlobal - ? await sogsV3ServerBanUser(pubkey, roomInfos, deleteAll) - : await sogsV3BanUser(pubkey, roomInfos, deleteAll) - : isGlobal - ? await sogsV3ServerUnbanUser(pubkey, roomInfos) - : await sogsV3UnbanUser(pubkey, roomInfos); + const isChangeApplied = isBan(banType) + ? await sogsV3BanUser({ + userToBan: pubkey, + roomInfos, + deleteAllMessages: deleteAll, + banType, + }) + : await sogsV3UnbanUser({ + userToUnban: pubkey, + roomInfos, + banType, + }); if (!isChangeApplied) { window?.log?.warn(`failed to ${banType} user: ${isChangeApplied}`); - // eslint-disable-next-line default-case - switch (`${banType}-${isGlobal ? 'global' : 'local'}` as `${BanType}-${'global' | 'local'}`) { - case 'ban-local': + + switch (banType) { + case 'ban': ToastUtils.pushUserBanFailure(); break; - case 'ban-global': + case 'unban': ToastUtils.pushGlobalUserBanFailure(); break; - case 'unban-local': + case 'server-ban': ToastUtils.pushUserUnbanFailure(); break; - case 'unban-global': + case 'server-unban': ToastUtils.pushGlobalUserUnbanFailure(); break; + default: + throw new Error('Unknown banType'); } return false; } window?.log?.info(`${pubkey.key} user ${banType}ned successfully...`); - // eslint-disable-next-line no-unused-expressions - banType === 'ban' ? ToastUtils.pushUserBanSuccess() : ToastUtils.pushUserUnbanSuccess(); + + if (isBan(banType)) { + ToastUtils.pushUserBanSuccess(); + } else { + ToastUtils.pushUserUnbanSuccess(); + } return true; } catch (e) { window?.log?.error(`Got error while ${banType}ning user:`, e); @@ -92,7 +104,6 @@ export const BanOrUnBanUserDialog = (props: { pubkey?: string; }) => { const { conversationId, banType, pubkey } = props; - const isBan = banType === 'ban'; const dispatch = getAppDispatch(); const convo = ConvoHub.use().get(conversationId); const inputRef = useRef(null); @@ -100,24 +111,29 @@ export const BanOrUnBanUserDialog = (props: { useFocusMount(inputRef, true); const [inputBoxValue, setInputBoxValue] = useState(''); const [inProgress, setInProgress] = useState(false); + const [localBanType, setLocalBanType] = useState(banType); - const displayName = useConversationUsernameWithFallback(true, pubkey); + const isServerWide = isServerBanUnban(localBanType); + const isBanAction = isBan(localBanType); + const displayName = useConversationUsernameWithFallback(true, pubkey); const hasPubkeyOnLoad = pubkey?.length; const inputTextToDisplay = !!pubkey && displayName ? `${displayName} ${PubKey.shorten(pubkey)}` : undefined; /** - * Ban or Unban a user from an open group - * @param deleteAll Delete all messages for that user in the group (only works with ban) + * Ban or Unban a user from a community + * @param deleteAll Delete all messages for that user in the community (only works with ban) */ const banOrUnBanUser = async (deleteAll: boolean) => { const castedPubkey = pubkey?.length ? pubkey : inputBoxValue; - window?.log?.info(`asked to ${banType} user: ${castedPubkey}, banAndDeleteAll:${deleteAll}`); + window?.log?.info( + `asked to ${localBanType} user: ${castedPubkey}, banAndDeleteAll:${deleteAll}` + ); setInProgress(true); - const isBanned = await banOrUnBanUserCall(convo, castedPubkey, banType, deleteAll, false); + const isBanned = await banOrUnBanUserCall(convo, castedPubkey, localBanType, deleteAll); if (isBanned) { // clear input box setInputBoxValue(''); @@ -129,7 +145,9 @@ export const BanOrUnBanUserDialog = (props: { setInProgress(false); }; - const title = isBan ? tr('banUser') : tr('banUnbanUser'); + const serverHost = new window.URL(convo.toOpenGroupV2().serverUrl).host; + const serverWideSuffix = isServerWide ? ` @ ${serverHost}` : ''; + const title = `${isBanAction ? tr('banUser') : tr('banUnbanUser')}${serverWideSuffix}`; /** * Starts procedure for banning/unbanning user and all their messages using dialog @@ -142,22 +160,39 @@ export const BanOrUnBanUserDialog = (props: { dispatch(updateBanOrUnbanUserModal(null)); }; - const buttonText = isBan ? tr('banUser') : tr('banUnbanUser'); + let buttonText = ''; + + if (isServerWide) { + if (isBanAction) { + buttonText = tr('serverBanUser'); + } else { + buttonText = tr('serverUnbanUser'); + } + } else if (isBanAction) { + buttonText = tr('banUser'); + } else { + buttonText = tr('banUnbanUser'); + } return ( } onClose={onClose} buttonChildren={ - + {/* * Note: we can only ban-and-delete-all when we have a pubkey on load currently. @@ -166,12 +201,12 @@ export const BanOrUnBanUserDialog = (props: { * When hasPubkeyOnLoad is true, the dialog was shown from a right click on the messages list, * so we do have the blindedId already in this case. */} - {isBan && hasPubkeyOnLoad ? ( + {isBanAction && hasPubkeyOnLoad ? ( @@ -189,7 +224,7 @@ export const BanOrUnBanUserDialog = (props: { {}} - inputDataTestId={isBan ? 'ban-user-input' : 'unban-user-input'} + inputDataTestId={isBanAction ? 'ban-user-input' : 'unban-user-input'} /> + {getFeatureFlag('useDevCommunityActions') ? ( + +

Server-wide:

+ { + const withoutServer = localBanType.replace('server-', '') as BanType; + const withServer = `server-${withoutServer}` as BanType; + setLocalBanType(isServerWide ? withoutServer : withServer); + }} + /> +
+ ) : null}
); }; - -// FIXME: Refactor with BanOrUnBanUserDialog(). -export const ServerBanOrUnBanUserDialog = (props: { - conversationId: string; - banType: BanType; - pubkey?: string; -}) => { - const { conversationId, banType, pubkey } = props; - const isBan = banType === 'ban'; - const dispatch = useDispatch(); - const convo = ConvoHub.use().get(conversationId); - const inputRef = useRef(null); - - useFocusMount(inputRef, true); - const [inputBoxValue, setInputBoxValue] = useState(''); - const [inProgress, setInProgress] = useState(false); - - const displayName = useConversationUsernameWithFallback(true, pubkey); - - const inputTextToDisplay = - !!pubkey && displayName ? `${displayName} ${PubKey.shorten(pubkey)}` : undefined; - - /** - * Ban or Unban a user from an open group - * @param deleteAll Delete all messages for that user in the group (only works with ban) - */ - const banOrUnBanUser = async (deleteAll: boolean = false) => { - const castedPubkey = pubkey?.length ? pubkey : inputBoxValue; - - window?.log?.info( - `asked to ${banType} user server-wide: ${castedPubkey}, banAndDeleteAll:${deleteAll}` - ); - setInProgress(true); - const isBanned = await banOrUnBanUserCall(convo, castedPubkey, banType, deleteAll, true); - if (isBanned) { - // clear input box - setInputBoxValue(''); - if (pubkey) { - dispatch(updateServerBanOrUnbanUserModal(null)); - } - } - - setInProgress(false); - }; - - const serverHost = new window.URL(convo.toOpenGroupV2().serverUrl).host; - const title = `${isBan ? tr('banUser') : tr('banUnbanUser')} @ ${serverHost}`; - - /** - * Starts procedure for banning/unbanning user and all their messages using dialog - */ - const startBanAndDeleteAllSequence = async () => { - await banOrUnBanUser(true); - }; - - const buttonText = isBan ? tr('banUser') : tr('banUnbanUser'); - - const onClose = () => { - dispatch(updateServerBanOrUnbanUserModal(null)); - }; - return ( - } - onClose={onClose} - buttonChildren={ - - - {isBan && ( - <> - - - )} - - } - > - - {}} - /> - - - - ); -}; diff --git a/ts/components/dialog/ModalContainer.tsx b/ts/components/dialog/ModalContainer.tsx index 8b6c861226..26d9c8ed5e 100644 --- a/ts/components/dialog/ModalContainer.tsx +++ b/ts/components/dialog/ModalContainer.tsx @@ -1,6 +1,5 @@ import { - useServerBanOrUnbanUserModalState, - useUpdateGroupPermissionsModalState, + useUpdateCommunityPermissionsModalState, useConfirmModal, useInviteContactModal, useAddModeratorsModal, @@ -27,7 +26,7 @@ import { useConversationSettingsModal, } from '../../state/selectors/modal'; import { LightboxGallery } from '../lightbox/LightboxGallery'; -import { BanOrUnBanUserDialog, ServerBanOrUnBanUserDialog } from './BanOrUnbanUserDialog'; +import { BanOrUnBanUserDialog } from './BanOrUnbanUserDialog'; import { DeleteAccountModal } from './DeleteAccountModal'; import { EditProfilePictureModal } from './EditProfilePictureModal'; import { EnterPasswordModal } from './EnterPasswordModal'; @@ -44,7 +43,7 @@ import { UpdateConversationDetailsDialog } from './UpdateConversationDetailsDial import { UserProfileModal } from './UserProfileModal'; import { OpenUrlModal } from './OpenUrlModal'; import { BlockOrUnblockDialog } from './blockOrUnblock/BlockOrUnblockDialog'; -import { UpdateGroupPermissionsDialog } from './UpdateGroupPermissionsDialog'; +import { UpdateCommunityPermissionsDialog } from './UpdateCommunityPermissionsDialog'; import { DebugMenuModal } from './debug/DebugMenuModal'; import { ConversationSettingsDialog } from './conversationSettings/conversationSettingsDialog'; import { SessionConfirm } from './SessionConfirm'; @@ -58,7 +57,7 @@ export const ModalContainer = () => { const addModeratorsModalState = useAddModeratorsModal(); const removeModeratorsModalState = useRemoveModeratorsModal(); const updateGroupMembersModalState = useUpdateGroupMembersModal(); - const updateGroupPermissionsModalState = useUpdateGroupPermissionsModalState(); + const updateCommunityPermissionsModalState = useUpdateCommunityPermissionsModalState(); const updateConversationDetailsModalState = useUpdateConversationDetailsModal(); const userProfileModalState = useUserProfileModal(); const changeNicknameModal = useChangeNickNameDialog(); @@ -67,7 +66,6 @@ export const ModalContainer = () => { const enterPasswordModalState = useEnterPasswordModal(); const deleteAccountModalState = useDeleteAccountModal(); const banOrUnbanUserModalState = useBanOrUnbanUserModal(); - const serverBanOrUnbanUserModalState = useServerBanOrUnbanUserModalState(); const blockOrUnblockModalState = useBlockOrUnblockUserModal(); const reactListModalState = useReactListDialog(); const reactClearAllModalState = useReactClearAllDialog(); @@ -95,9 +93,6 @@ export const ModalContainer = () => { {debugMenuModalState && } {/* Actions */} {banOrUnbanUserModalState && } - {serverBanOrUnbanUserModalState && ( - - )} {blockOrUnblockModalState && } {inviteModalState && } {addModeratorsModalState && } @@ -105,8 +100,8 @@ export const ModalContainer = () => { {updateGroupMembersModalState && ( )} - {updateGroupPermissionsModalState && ( - + {updateCommunityPermissionsModalState && ( + )} {updateConversationDetailsModalState && ( diff --git a/ts/components/dialog/UpdateCommunityPermissionsDialog.tsx b/ts/components/dialog/UpdateCommunityPermissionsDialog.tsx new file mode 100644 index 0000000000..66b6cf56b5 --- /dev/null +++ b/ts/components/dialog/UpdateCommunityPermissionsDialog.tsx @@ -0,0 +1,155 @@ +/* eslint-disable @typescript-eslint/no-misused-promises */ + +import { useState } from 'react'; +import { + ModalActionsContainer, + ModalBasicHeader, + ModalBottomButtonWithBorder, + SessionWrapperModal, +} from '../SessionWrapperModal'; +import { SessionButtonColor, SessionButtonType } from '../basic/SessionButton'; +import { OpenGroupData } from '../../data/opengroups'; +import { sogsV3SetRoomPermissions } from '../../session/apis/open_group_api/sogsv3/sogsV3RoomPermissions'; +import { ConvoHub } from '../../session/conversations'; +import { tr } from '../../localization/localeTools'; +import { PanelToggleButton } from '../buttons/panel/PanelToggleButton'; +import { PanelButtonGroup, PanelButtonTextWithSubText } from '../buttons/panel/PanelButton'; +import { ModalDescription } from './shared/ModalDescriptionContainer'; +import { ModalFlexContainer } from './shared/ModalFlexContainer'; +import { getAppDispatch } from '../../state/dispatch'; +import { updateCommunityPermissionsModal } from '../../state/ducks/modalDialog'; +import type { WithConvoId } from '../../session/types/with'; + +export function UpdateCommunityPermissionsDialog(props: WithConvoId) { + const [defaultRead, setDefaultRead] = useState(true); + const [defaultWrite, setDefaultWrite] = useState(true); + const [defaultAccessible, setDefaultAccessible] = useState(true); + const [defaultUpload, setDefaultUpload] = useState(true); + const dispatch = getAppDispatch(); + + const convo = ConvoHub.use().get(props.conversationId); + + function onClickOK() { + if (convo.isOpenGroupV2()) { + const roomInfos = OpenGroupData.getV2OpenGroupRoom(convo.id); + if (!roomInfos) { + return; + } + void sogsV3SetRoomPermissions(roomInfos, { + default_accessible: defaultAccessible, + default_read: defaultRead, + default_upload: defaultUpload, + default_write: defaultWrite, + }); + } + + closeDialog(); + } + + function closeDialog() { + dispatch(updateCommunityPermissionsModal(null)); + } + + return ( + } + onClose={closeDialog} + buttonChildren={ + + + + + } + > + + + + + + } + active={defaultAccessible} + onClick={async () => setDefaultAccessible(!defaultAccessible)} + rowDataTestId="invalid-data-testid" + toggleDataTestId="invalid-data-testid" + /> + + } + active={defaultRead} + onClick={async () => setDefaultRead(!defaultRead)} + rowDataTestId="invalid-data-testid" + toggleDataTestId="invalid-data-testid" + /> + + } + active={defaultWrite} + onClick={async () => setDefaultWrite(!defaultWrite)} + rowDataTestId="invalid-data-testid" + toggleDataTestId="invalid-data-testid" + /> + + } + active={defaultUpload} + onClick={async () => setDefaultUpload(!defaultUpload)} + rowDataTestId="invalid-data-testid" + toggleDataTestId="invalid-data-testid" + /> + + + + ); +} + +// private onKeyUp(event: any) { +// switch (event.key) { +// case 'Enter': +// this.onClickOK(); +// break; +// case 'Esc': +// case 'Escape': +// this.closeDialog(); +// break; +// default: +// } +// } diff --git a/ts/components/dialog/UpdateGroupPermissionsDialog.tsx b/ts/components/dialog/UpdateGroupPermissionsDialog.tsx deleted file mode 100644 index f957173ea1..0000000000 --- a/ts/components/dialog/UpdateGroupPermissionsDialog.tsx +++ /dev/null @@ -1,228 +0,0 @@ -/* eslint-disable @typescript-eslint/no-misused-promises */ -import autoBind from 'auto-bind'; - -import { motion } from 'framer-motion'; -import { Component } from 'react'; -import styled from 'styled-components'; -import { ConversationModel } from '../../models/conversation'; -import { updateGroupPermissionsModal } from '../../state/ducks/modalDialog'; -import { THEME_GLOBALS } from '../../themes/globals'; -import { ModalBasicHeader, SessionWrapperModal } from '../SessionWrapperModal'; -import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton'; -import { SpacerMD } from '../basic/Text'; -import { OpenGroupData } from '../../data/opengroups'; -import { - OpenGroupRoomPermissionType, - sogsV3SetRoomPermissions, -} from '../../session/apis/open_group_api/sogsv3/sogsV3RoomPermissions'; -import { ConvoHub } from '../../session/conversations'; -import { tr } from '../../localization/localeTools'; -import { PanelToggleButton } from '../buttons/panel/PanelToggleButton'; -import { PanelButtonTextWithSubText } from '../buttons/panel/PanelButton'; - -const StyledErrorMessage = styled(motion.p)` - text-align: center; - color: var(--danger-color); - display: block; - user-select: none; -`; - -type Props = { - conversationId: string; -}; - -interface State { - errorDisplayed: boolean; - errorMessage: string; - default_read: boolean; - default_write: boolean; - default_accessible: boolean; - default_upload: boolean; -} - -export class UpdateGroupPermissionsDialog extends Component { - private readonly convo: ConversationModel; - - constructor(props: Props) { - super(props); - - autoBind(this); - this.convo = ConvoHub.use().get(props.conversationId); - - this.state = { - default_read: true, - default_write: true, - default_accessible: true, - default_upload: true, - errorDisplayed: false, - errorMessage: 'placeholder', - }; - } - - public componentDidMount() { - window.addEventListener('keyup', this.onKeyUp); - } - - public componentWillUnmount() { - window.removeEventListener('keyup', this.onKeyUp); - } - - public onClickOK() { - const { default_accessible, default_read, default_upload, default_write } = this.state; - - if (this.convo.isPublic()) { - const roomInfos = OpenGroupData.getV2OpenGroupRoom(this.convo.id); - if (!roomInfos) { - return; - } - void sogsV3SetRoomPermissions(roomInfos, { - default_accessible, - default_read, - default_upload, - default_write, - }); - } - - this.closeDialog(); - } - - public render() { - const okText = 'Apply'; - const cancelText = tr('cancel'); - - const errorMsg = this.state.errorMessage; - - return ( - } - onClose={() => this.closeDialog()} - > - {this.state.errorDisplayed ? ( - <> - - - {errorMsg} - - - - ) : null} - -

- For compatibility reasons, we don't know which permissions were enabled to begin with, but - you can set new values below regardless. -

- - - } - active={this.state.default_accessible} - onClick={async () => this.onPermissionChanged('default_accessible')} - rowDataTestId='test-ignore' - toggleDataTestId='test-ignore' - /> - - } - active={this.state.default_read} - onClick={async () => this.onPermissionChanged('default_read')} - rowDataTestId='test-ignore' - toggleDataTestId='test-ignore' - /> - - } - active={this.state.default_write} - onClick={async () => this.onPermissionChanged('default_write')} - rowDataTestId='test-ignore' - toggleDataTestId='test-ignore' - /> - - } - active={this.state.default_upload} - onClick={async () => this.onPermissionChanged('default_upload')} - rowDataTestId='test-ignore' - toggleDataTestId='test-ignore' - /> - -
- - -
-
- ); - } - - private onKeyUp(event: any) { - switch (event.key) { - case 'Enter': - this.onClickOK(); - break; - case 'Esc': - case 'Escape': - this.closeDialog(); - break; - default: - } - } - - private closeDialog() { - window.removeEventListener('keyup', this.onKeyUp); - - window.inboxStore?.dispatch(updateGroupPermissionsModal(null)); - } - - private onPermissionChanged(perm: OpenGroupRoomPermissionType) { - this.setState(state => { - return { - ...state, - [perm]: !state[perm], - }; - }); - } -} diff --git a/ts/components/dialog/conversationSettings/conversationSettingsItems.tsx b/ts/components/dialog/conversationSettings/conversationSettingsItems.tsx index 2ea700a748..b18e66fdf7 100644 --- a/ts/components/dialog/conversationSettings/conversationSettingsItems.tsx +++ b/ts/components/dialog/conversationSettings/conversationSettingsItems.tsx @@ -28,7 +28,6 @@ import { useShowInviteContactToGroupCb } from '../../menuAndSettingsHooks/useSho import { useShowCopyAccountIdCb } from '../../menuAndSettingsHooks/useCopyAccountId'; import { useShowCopyCommunityUrlCb } from '../../menuAndSettingsHooks/useCopyCommunityUrl'; import { useBanUserCb } from '../../menuAndSettingsHooks/useBanUser'; -import { useUnbanUserCb } from '../../menuAndSettingsHooks/useUnbanUser'; import { useAddModeratorsCb } from '../../menuAndSettingsHooks/useAddModerators'; import { useRemoveModeratorsCb } from '../../menuAndSettingsHooks/useRemoveModerators'; import { useShowLeaveCommunityCb } from '../../menuAndSettingsHooks/useShowLeaveCommunity'; @@ -285,12 +284,10 @@ export function ChangeCommunityPermissionsButton({ conversationId }: WithConvoId } return ( - } - text={{ token: 'groupChangePermissions' }} + iconElement={} + text={{ token: 'communityChangePermissions' }} onClick={cb} - dataTestId="edit-group-name" + dataTestId="edit-community-permissions" /> ); } @@ -337,7 +334,7 @@ export function RemoveAdminCommunityButton({ conversationId }: WithConvoId) { } export function BanFromCommunityButton({ conversationId }: WithConvoId) { - const showBanUserCb = useBanUserCb(conversationId); + const showBanUserCb = useBanUserCb({ banType: 'ban', conversationId }); if (!showBanUserCb) { return null; @@ -353,7 +350,7 @@ export function BanFromCommunityButton({ conversationId }: WithConvoId) { } export function UnbanFromCommunityButton({ conversationId }: WithConvoId) { - const showUnbanUserCb = useUnbanUserCb(conversationId); + const showUnbanUserCb = useBanUserCb({ banType: 'unban', conversationId }); if (!showUnbanUserCb) { return null; diff --git a/ts/components/dialog/debug/constants.ts b/ts/components/dialog/debug/constants.ts index 72712ef199..5ab5657b24 100644 --- a/ts/components/dialog/debug/constants.ts +++ b/ts/components/dialog/debug/constants.ts @@ -12,7 +12,13 @@ type DebugFeatureFlagsType = { export const DEBUG_FEATURE_FLAGS: DebugFeatureFlagsType = { // NOTE Put new feature flags in here during development so they are not available in production environments. Remove from here when they are ready for QA and production - DEV: ['showPopoverAnchors', 'debugInputCommands', 'proAvailable', 'useTestProBackend'], + DEV: [ + 'showPopoverAnchors', + 'debugInputCommands', + 'proAvailable', + 'useTestProBackend', + 'useDevCommunityActions', + ], UNSUPPORTED: ['useTestNet', 'useLocalDevNet', 'fsTTL30s', 'proGroupsAvailable'], UNTESTED: ['disableOnionRequests', 'replaceLocalizedStringsWithKeys'], }; diff --git a/ts/components/icon/Icons.tsx b/ts/components/icon/Icons.tsx index 25602698c3..0c4c619950 100644 --- a/ts/components/icon/Icons.tsx +++ b/ts/components/icon/Icons.tsx @@ -1,7 +1,6 @@ /* eslint-disable max-len */ /* eslint-disable no-multi-str */ export type SessionIconType = - | 'padlock' // community permissions icon | 'mute' // lucide equivalent, but because bell doesn't have one we need to keep this one (so the style of icons matches) | 'pin' // lucide equivalent, but because bell doesn't have one we need to keep this one (so the style of icons matches) | 'bell' // no lucide alternative (this bell has the @ in it) @@ -97,11 +96,6 @@ export const icons: Record = { viewBox: '0 0 24 24', ratio: 1, }, - padlock: { - path: 'M10.4986 11.2568c-.78025 0-1.41266.6329-1.41266 1.4136 0 .5847.35401 1.0869.86269 1.3035v1.5409c0 .1754.14087.3164.31617.3164h.4743c.1753 0 .3162-.141.3162-.3164v-1.5409c.5053-.2166.8627-.7153.8627-1.3035 0-.7807-.6324-1.4136-1.4126-1.4136h-.0068ZM16.1131 7.90026V5.61651C16.1131 2.52107 13.5938 0 10.497 0 7.40026 0 4.88436 2.52107 4.88436 5.61651v2.28375c-1.06204.63972-1.77694 1.7988-1.77694 3.12644v5.3241C3.10742 18.3629 4.74344 20 6.7541 20h7.4893c2.0106 0 3.6466-1.6371 3.6466-3.6492v-5.3241c0-1.32764-.7149-2.49016-1.7769-3.12644ZM6.60287 5.61651c0-2.14961 1.746-3.89682 3.89413-3.89682 2.1481 0 3.8941 1.74721 3.8941 3.89682V7.3362H6.60287V5.61651ZM16.1715 16.3508c0 1.0628-.8661 1.9295-1.9281 1.9295H6.7541c-1.06204 0-1.92817-.8667-1.92817-1.9295v-5.3241c0-1.06281.86613-1.92954 1.92817-1.92954h7.4893c1.062 0 1.9281.86673 1.9281 1.92954v5.3241Z', - viewBox: '0 0 21 20', - ratio: 21 / 20, - }, pin: { path: 'M83.88.451L122.427 39c.603.601.603 1.585 0 2.188l-13.128 13.125c-.602.604-1.586.604-2.187 0l-3.732-3.73-17.303 17.3c3.882 14.621.095 30.857-11.37 42.32-.266.268-.535.529-.808.787-1.004.955-.843.949-1.813-.021L47.597 86.48 0 122.867l36.399-47.584L11.874 50.76c-.978-.98-.896-.826.066-1.837.24-.251.485-.503.734-.753C24.137 36.707 40.376 32.917 54.996 36.8l17.301-17.3-3.733-3.732c-.601-.601-.601-1.585 0-2.188L81.691.451c.604-.601 1.588-.601 2.189 0z', viewBox: '0 0 122.879 122.867', diff --git a/ts/components/menu/Menu.tsx b/ts/components/menu/Menu.tsx index c9252b4faa..35fd90c43c 100644 --- a/ts/components/menu/Menu.tsx +++ b/ts/components/menu/Menu.tsx @@ -2,22 +2,16 @@ import { Submenu } from 'react-contexify'; import type { JSX } from 'react'; import { useConvoIdFromContext } from '../../contexts/ConvoIdContext'; import { - useIsBlinded, useIsGroupV2, useIsIncomingRequest, useIsPrivate, useIsPrivateAndFriend, - useIsPublic, useNotificationSetting, - useWeAreAdmin, } from '../../hooks/useParamSelector'; import { - copyPublicKeyByConvoId, declineConversationWithConfirm, handleAcceptConversationRequest, markAllReadByConvoId, - showServerBanUserByConvoId, - showServerUnbanUserByConvoId, } from '../../interactions/conversationInteractions'; import { ConvoHub } from '../../session/conversations'; import { PubKey } from '../../session/types'; @@ -37,7 +31,6 @@ import { useShowDeletePrivateConversationCb } from '../menuAndSettingsHooks/useS import { useShowInviteContactToCommunity } from '../menuAndSettingsHooks/useShowInviteContactToCommunity'; import { useAddModeratorsCb } from '../menuAndSettingsHooks/useAddModerators'; import { useRemoveModeratorsCb } from '../menuAndSettingsHooks/useRemoveModerators'; -import { useUnbanUserCb } from '../menuAndSettingsHooks/useUnbanUser'; import { useBanUserCb } from '../menuAndSettingsHooks/useBanUser'; import { useSetNotificationsFor } from '../menuAndSettingsHooks/useSetNotificationsFor'; import { Localizer } from '../basic/Localizer'; @@ -140,7 +133,10 @@ export const AddModeratorsMenuItem = (): JSX.Element | null => { export const UnbanMenuItem = (): JSX.Element | null => { const convoId = useConvoIdFromContext(); - const showUnbanUserCb = useUnbanUserCb(convoId); + const showUnbanUserCb = useBanUserCb({ + conversationId: convoId, + banType: 'unban', + }); if (!showUnbanUserCb) { return null; @@ -151,7 +147,10 @@ export const UnbanMenuItem = (): JSX.Element | null => { export const BanMenuItem = (): JSX.Element | null => { const convoId = useConvoIdFromContext(); - const showBanUserCb = useBanUserCb(convoId); + const showBanUserCb = useBanUserCb({ + conversationId: convoId, + banType: 'ban', + }); if (!showBanUserCb) { return null; @@ -161,17 +160,15 @@ export const BanMenuItem = (): JSX.Element | null => { export const ServerUnbanMenuItem = (): JSX.Element | null => { const convoId = useConvoIdFromContext(); - const isPublic = useIsPublic(convoId); - const weAreAdmin = useWeAreAdmin(convoId); + const showUnbanUserCb = useBanUserCb({ + conversationId: convoId, + banType: 'server-unban', + }); - if (weAreAdmin && isPublic) { + if (showUnbanUserCb) { return ( - { - showServerUnbanUserByConvoId(convoId); - }} - > - {tr('serverUnbanUser')} + + ); } @@ -180,40 +177,15 @@ export const ServerUnbanMenuItem = (): JSX.Element | null => { export const ServerBanMenuItem = (): JSX.Element | null => { const convoId = useConvoIdFromContext(); - const isPublic = useIsPublic(convoId); - const weAreAdmin = useWeAreAdmin(convoId); + const showUnbanUserCb = useBanUserCb({ + conversationId: convoId, + banType: 'server-ban', + }); - if (weAreAdmin && isPublic) { + if (showUnbanUserCb) { return ( - { - showServerBanUserByConvoId(convoId); - }} - > - {tr('serverBanUser')} - - ); - } - return null; -}; - -export const CopyMenuItem = (): JSX.Element | null => { - const convoId = useConvoIdFromContext(); - const isPublic = useIsPublic(convoId); - const isPrivate = useIsPrivate(convoId); - const isBlinded = useIsBlinded(convoId); - - // we want to show the copyId for open groups and private chats only - - if ((isPrivate && !isBlinded) || isPublic) { - const copyIdLabel = isPublic ? tr('communityUrlCopy') : tr('accountIDCopy'); - return ( - { - void copyPublicKeyByConvoId(convoId); - }} - > - {copyIdLabel} + + ); } diff --git a/ts/components/menuAndSettingsHooks/useAddUserPermissions.tsx b/ts/components/menuAndSettingsHooks/useAddUserPermissions.tsx new file mode 100644 index 0000000000..96e21123cc --- /dev/null +++ b/ts/components/menuAndSettingsHooks/useAddUserPermissions.tsx @@ -0,0 +1,69 @@ +import { + sogsV3AddPermissions, + sogsV3ClearPermissions, + type OpenGroupPermissionType, +} from '../../session/apis/open_group_api/sogsv3/sogsV3UserPermissions'; +import { ConvoHub } from '../../session/conversations'; +import { PubKey } from '../../session/types'; +import { ToastUtils } from '../../session/utils'; +import { getFeatureFlag } from '../../state/ducks/types/releasedFeaturesReduxTypes'; + +export function useAddUserPermissions( + sender: string | undefined, + convoId: string | undefined, + permissions: Array +) { + if (!sender || !convoId || !permissions.length || !getFeatureFlag('useDevCommunityActions')) { + return null; + } + return async () => { + try { + const user = PubKey.cast(sender); + const convo = ConvoHub.use().getOrThrow(convoId); + + const roomInfo = convo.toOpenGroupV2(); + const res = await sogsV3AddPermissions([user], roomInfo, permissions); + if (!res) { + window?.log?.warn('failed to add user permissions:', res); + + ToastUtils.pushFailedToChangeUserPermissions(); + } else { + window?.log?.info(`${user.key} given permissions ${permissions.join(', ')}...`); + ToastUtils.pushUserPermissionsChanged(); + } + } catch (e) { + window?.log?.error('Got error while adding user permissions:', e); + ToastUtils.pushFailedToChangeUserPermissions(); + } + }; +} + +export function useClearUserPermissions( + sender: string | undefined, + convoId: string | undefined, + permissions: Array +) { + if (!sender || !convoId || !permissions.length || !getFeatureFlag('useDevCommunityActions')) { + return null; + } + return async () => { + try { + const user = PubKey.cast(sender); + const convo = ConvoHub.use().getOrThrow(convoId); + + const roomInfo = convo.toOpenGroupV2(); + const res = await sogsV3ClearPermissions([user], roomInfo, permissions); + if (!res) { + window?.log?.warn('failed to clear user permissions:', res); + + ToastUtils.pushFailedToChangeUserPermissions(); + } else { + window?.log?.info(`${user.key} given permissions ${permissions.join(', ')}...`); + ToastUtils.pushUserPermissionsChanged(); + } + } catch (e) { + window?.log?.error('Got error while clearing user permissions:', e); + ToastUtils.pushFailedToChangeUserPermissions(); + } + }; +} diff --git a/ts/components/menuAndSettingsHooks/useBanUser.ts b/ts/components/menuAndSettingsHooks/useBanUser.ts index a1c98a9c75..d6a36e6706 100644 --- a/ts/components/menuAndSettingsHooks/useBanUser.ts +++ b/ts/components/menuAndSettingsHooks/useBanUser.ts @@ -1,18 +1,37 @@ import { getAppDispatch } from '../../state/dispatch'; import { useIsPublic } from '../../hooks/useParamSelector'; -import { updateBanOrUnbanUserModal } from '../../state/ducks/modalDialog'; +import { + isServerBanUnban, + updateBanOrUnbanUserModal, + type BanType, +} from '../../state/ducks/modalDialog'; import { useWeAreCommunityAdminOrModerator } from '../../state/selectors/conversations'; +import { getFeatureFlag } from '../../state/ducks/types/releasedFeaturesReduxTypes'; -export function useBanUserCb(conversationId?: string, pubkey?: string) { +export function useBanUserCb({ + conversationId, + banType, + pubkey, +}: { + banType: BanType; + conversationId?: string; + pubkey?: string; +}) { const dispatch = getAppDispatch(); const isPublic = useIsPublic(conversationId); - const weAreCommunityAdminOrModerator = useWeAreCommunityAdminOrModerator(conversationId); + const weAreAdminOrMod = useWeAreCommunityAdminOrModerator(conversationId); + const hasDevCommunityActions = getFeatureFlag('useDevCommunityActions'); - if (!isPublic || !weAreCommunityAdminOrModerator || !conversationId) { + if ( + !isPublic || + !weAreAdminOrMod || + !conversationId || + (isServerBanUnban(banType) && !hasDevCommunityActions) + ) { return null; } return () => { - dispatch(updateBanOrUnbanUserModal({ banType: 'ban', conversationId, pubkey })); + dispatch(updateBanOrUnbanUserModal({ banType, conversationId, pubkey })); }; } diff --git a/ts/components/menuAndSettingsHooks/useChangeCommunityPermissions.ts b/ts/components/menuAndSettingsHooks/useChangeCommunityPermissions.ts index 9972b88323..1d45fcce6c 100644 --- a/ts/components/menuAndSettingsHooks/useChangeCommunityPermissions.ts +++ b/ts/components/menuAndSettingsHooks/useChangeCommunityPermissions.ts @@ -1,17 +1,19 @@ import { useDispatch } from 'react-redux'; import { useIsPublic, useWeAreAdmin } from '../../hooks/useParamSelector'; -import { updateGroupPermissionsModal } from '../../state/ducks/modalDialog'; +import { updateCommunityPermissionsModal } from '../../state/ducks/modalDialog'; +import { getFeatureFlag } from '../../state/ducks/types/releasedFeaturesReduxTypes'; export function useChangeCommunityPermissionsCb(conversationId?: string) { const dispatch = useDispatch(); const isPublic = useIsPublic(conversationId); const weAreAdmin = useWeAreAdmin(conversationId); + const hasDevCommunityActions = getFeatureFlag('useDevCommunityActions'); - if (!isPublic || !weAreAdmin || !conversationId) { + if (!isPublic || !weAreAdmin || !conversationId || !hasDevCommunityActions) { return null; } return () => { - dispatch(updateGroupPermissionsModal({ conversationId })); + dispatch(updateCommunityPermissionsModal({ conversationId })); }; } diff --git a/ts/components/menuAndSettingsHooks/useServerBanUser.ts b/ts/components/menuAndSettingsHooks/useServerBanUser.ts deleted file mode 100644 index 1786afa81a..0000000000 --- a/ts/components/menuAndSettingsHooks/useServerBanUser.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { useDispatch } from 'react-redux'; -import { updateServerBanOrUnbanUserModal } from '../../state/ducks/modalDialog'; -import { useIsPublic, useWeAreAdmin } from '../../hooks/useParamSelector'; - -export function useServerBanUserCb(conversationId?: string, pubkey?: string) { - const dispatch = useDispatch(); - const isPublic = useIsPublic(conversationId); - const weAreAdmin = useWeAreAdmin(conversationId); - - if (!isPublic || !weAreAdmin || !conversationId) { - return null; - } - - return () => { - dispatch(updateServerBanOrUnbanUserModal({ banType: 'ban', conversationId, pubkey })); - }; -} diff --git a/ts/components/menuAndSettingsHooks/useServerUnbanUser.ts b/ts/components/menuAndSettingsHooks/useServerUnbanUser.ts deleted file mode 100644 index 95ceda0308..0000000000 --- a/ts/components/menuAndSettingsHooks/useServerUnbanUser.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { useDispatch } from 'react-redux'; -import { updateServerBanOrUnbanUserModal } from '../../state/ducks/modalDialog'; -import { useIsPublic, useWeAreAdmin } from '../../hooks/useParamSelector'; - -export function useServerUnbanUserCb(conversationId?: string, pubkey?: string) { - const dispatch = useDispatch(); - const isPublic = useIsPublic(conversationId); - const weAreAdmin = useWeAreAdmin(conversationId); - - if (!isPublic || !weAreAdmin || !conversationId) { - return null; - } - - return () => { - dispatch(updateServerBanOrUnbanUserModal({ banType: 'unban', conversationId, pubkey })); - }; -} diff --git a/ts/components/menuAndSettingsHooks/useUnbanUser.ts b/ts/components/menuAndSettingsHooks/useUnbanUser.ts deleted file mode 100644 index 427d6e6b8d..0000000000 --- a/ts/components/menuAndSettingsHooks/useUnbanUser.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { getAppDispatch } from '../../state/dispatch'; -import { useIsPublic } from '../../hooks/useParamSelector'; -import { updateBanOrUnbanUserModal } from '../../state/ducks/modalDialog'; -import { useWeAreCommunityAdminOrModerator } from '../../state/selectors/conversations'; - -export function useUnbanUserCb(conversationId?: string, pubkey?: string) { - const dispatch = getAppDispatch(); - const isPublic = useIsPublic(conversationId); - const weAreCommunityAdminOrModerator = useWeAreCommunityAdminOrModerator(conversationId); - - if (!isPublic || !weAreCommunityAdminOrModerator || !conversationId) { - return null; - } - - return () => { - dispatch(updateBanOrUnbanUserModal({ banType: 'unban', conversationId, pubkey })); - }; -} diff --git a/ts/interactions/conversationInteractions.ts b/ts/interactions/conversationInteractions.ts index a4a9f9dd90..1a3be8668e 100644 --- a/ts/interactions/conversationInteractions.ts +++ b/ts/interactions/conversationInteractions.ts @@ -24,15 +24,9 @@ import { resetConversationExternal, } from '../state/ducks/conversations'; import { - updateAddModeratorsModal, - updateBanOrUnbanUserModal, updateConfirmModal, updateConversationSettingsModal, updateGroupMembersModal, - updateGroupPermissionsModal, - updateInviteContactModal, - updateRemoveModeratorsModal, - updateServerBanOrUnbanUserModal, updateConversationDetailsModal, } from '../state/ducks/modalDialog'; import { Storage } from '../util/storage'; @@ -285,13 +279,6 @@ export async function showUpdateGroupOrCommunityDetailsByConvoId(conversationId: window.inboxStore?.dispatch(updateConversationDetailsModal({ conversationId })); } -export async function showUpdateGroupPermissionsByConvoId(conversationId: string) { - const conversation = ConvoHub.use().get(conversationId); - if (conversation.isOpenGroupV2()) { - window.inboxStore?.dispatch(updateGroupPermissionsModal({ conversationId })); - } -} - export async function showUpdateGroupMembersByConvoId(conversationId: string) { const conversation = ConvoHub.use().get(conversationId); if (conversation.isClosedGroup()) { @@ -464,42 +451,6 @@ export async function showDeleteGroupByConvoId(conversationId: string, name: str ); } -export function showInviteContactByConvoId(conversationId: string) { - window.inboxStore?.dispatch(updateInviteContactModal({ conversationId })); -} - -export function showAddModeratorsByConvoId(conversationId: string) { - window.inboxStore?.dispatch(updateAddModeratorsModal({ conversationId })); -} - -export function showRemoveModeratorsByConvoId(conversationId: string) { - window.inboxStore?.dispatch(updateRemoveModeratorsModal({ conversationId })); -} - -export function showBanUserByConvoId(conversationId: string, pubkey?: string) { - window.inboxStore?.dispatch( - updateBanOrUnbanUserModal({ banType: 'ban', conversationId, pubkey }) - ); -} - -export function showUnbanUserByConvoId(conversationId: string, pubkey?: string) { - window.inboxStore?.dispatch( - updateBanOrUnbanUserModal({ banType: 'unban', conversationId, pubkey }) - ); -} - -export function showServerBanUserByConvoId(conversationId: string, pubkey?: string) { - window.inboxStore?.dispatch( - updateServerBanOrUnbanUserModal({ banType: 'ban', conversationId, pubkey }) - ); -} - -export function showServerUnbanUserByConvoId(conversationId: string, pubkey?: string) { - window.inboxStore?.dispatch( - updateServerBanOrUnbanUserModal({ banType: 'unban', conversationId, pubkey }) - ); -} - export async function markAllReadByConvoId(conversationId: string) { const conversation = ConvoHub.use().get(conversationId); perfStart(`markAllReadByConvoId-${conversationId}`); diff --git a/ts/interactions/messageInteractions.ts b/ts/interactions/messageInteractions.ts index a47316aa97..7f8589b069 100644 --- a/ts/interactions/messageInteractions.ts +++ b/ts/interactions/messageInteractions.ts @@ -1,113 +1,9 @@ import { tr } from '../localization/localeTools'; import { joinOpenGroupV2WithUIEvents } from '../session/apis/open_group_api/opengroupV2/JoinOpenGroupV2'; -import { - sogsV3AddAdmin, - sogsV3RemoveAdmins, -} from '../session/apis/open_group_api/sogsv3/sogsV3AddRemoveMods'; -import { - OpenGroupPermissionType, - sogsV3AddPermissions, - sogsV3ClearPermissions, -} from '../session/apis/open_group_api/sogsv3/sogsV3UserPermissions'; -import { - isOpenGroupV2, - openGroupV2CompleteURLRegex, -} from '../session/apis/open_group_api/utils/OpenGroupUtils'; -import { ConvoHub } from '../session/conversations'; -import { PubKey } from '../session/types'; +import { openGroupV2CompleteURLRegex } from '../session/apis/open_group_api/utils/OpenGroupUtils'; import { ToastUtils } from '../session/utils'; -import { - updateBanOrUnbanUserModal, - updateConfirmModal, - updateServerBanOrUnbanUserModal, -} from '../state/ducks/modalDialog'; - -export function banUser(userToBan: string, conversationId: string) { - let pubKeyToBan: PubKey; - try { - pubKeyToBan = PubKey.cast(userToBan); - } catch (e) { - window?.log?.warn(e.message); - ToastUtils.pushUserBanFailure(); - return; - } - if (!isOpenGroupV2(conversationId)) { - window.log.warn(`Conversation ${conversationId} is not an open group`); - ToastUtils.pushUserBanFailure(); - - return; - } - - window.inboxStore?.dispatch( - updateBanOrUnbanUserModal({ banType: 'ban', conversationId, pubkey: pubKeyToBan.key }) - ); -} - -/** - * There is no way to unban on an opengroupv1 server. - * This function only works for opengroupv2 server - */ -export function unbanUser(userToUnBan: string, conversationId: string) { - let pubKeyToUnban: PubKey; - try { - pubKeyToUnban = PubKey.cast(userToUnBan); - } catch (e) { - window?.log?.warn(e.message); - ToastUtils.pushUserBanFailure(); - return; - } - if (!isOpenGroupV2(conversationId)) { - window.log.warn(`Conversation ${conversationId} is not an open group`); - ToastUtils.pushUserUnbanFailure(); - - return; - } - window.inboxStore?.dispatch( - updateBanOrUnbanUserModal({ banType: 'unban', conversationId, pubkey: pubKeyToUnban.key }) - ); -} - -export function serverBanUser(userToBan: string, conversationId: string) { - let pubKeyToBan: PubKey; - try { - pubKeyToBan = PubKey.cast(userToBan); - } catch (e) { - window?.log?.warn(e); - ToastUtils.pushUserBanFailure(); - return; - } - if (!isOpenGroupV2(conversationId)) { - window.log.warn(`Conversation ${conversationId} is not an open group`); - ToastUtils.pushUserBanFailure(); - - return; - } - - window.inboxStore?.dispatch( - updateServerBanOrUnbanUserModal({ banType: 'ban', conversationId, pubkey: pubKeyToBan.key }) - ); -} - -export function serverUnbanUser(userToUnBan: string, conversationId: string) { - let pubKeyToUnban: PubKey; - try { - pubKeyToUnban = PubKey.cast(userToUnBan); - } catch (e) { - window?.log?.warn(e); - ToastUtils.pushUserBanFailure(); - return; - } - if (!isOpenGroupV2(conversationId)) { - window.log.warn(`Conversation ${conversationId} is not an open group`); - ToastUtils.pushUserUnbanFailure(); - - return; - } - window.inboxStore?.dispatch( - updateServerBanOrUnbanUserModal({ banType: 'unban', conversationId, pubkey: pubKeyToUnban.key }) - ); -} +import { updateConfirmModal } from '../state/ducks/modalDialog'; export function copyBodyToClipboard(body?: string | null) { if (body) { @@ -117,109 +13,6 @@ export function copyBodyToClipboard(body?: string | null) { } } -export async function removeSenderFromModerator(sender: string, convoId: string) { - try { - const pubKeyToRemove = PubKey.cast(sender); - const convo = ConvoHub.use().getOrThrow(convoId); - - const userDisplayName = - ConvoHub.use().get(sender)?.getNicknameOrRealUsernameOrPlaceholder() || tr('unknown'); - - const roomInfo = convo.toOpenGroupV2(); - const res = await sogsV3RemoveAdmins([pubKeyToRemove], roomInfo); - if (!res) { - window?.log?.warn('failed to remove moderator:', res); - - ToastUtils.pushFailedToRemoveFromModerator([userDisplayName]); - } else { - window?.log?.info(`${pubKeyToRemove.key} removed from moderators...`); - ToastUtils.pushUserRemovedFromModerators([userDisplayName]); - } - } catch (e) { - window?.log?.error('Got error while removing moderator:', e); - } -} - -export async function addSenderAsModerator(sender: string, convoId: string) { - try { - const pubKeyToAdd = PubKey.cast(sender); - const convo = ConvoHub.use().getOrThrow(convoId); - - const roomInfo = convo.toOpenGroupV2(); - const res = await sogsV3AddAdmin([pubKeyToAdd], roomInfo); - if (!res) { - window?.log?.warn('failed to add moderator:', res); - - ToastUtils.pushFailedToAddAsModerator(); - } else { - window?.log?.info(`${pubKeyToAdd.key} added to moderators...`); - const userDisplayName = - ConvoHub.use().get(sender)?.getNicknameOrRealUsernameOrPlaceholder() || tr('unknown'); - ToastUtils.pushUserAddedToModerators([userDisplayName]); - } - } catch (e) { - window?.log?.error('Got error while adding moderator:', e); - } -} - -export async function addUserPermissions( - sender: string | undefined, - convoId: string | undefined, - permissions: Array -) { - try { - if (typeof convoId === 'undefined') { - window?.log?.warn('undefined convo passed to clearUserPermissions'); - return; - } - const user = PubKey.cast(sender); - const convo = ConvoHub.use().getOrThrow(convoId); - - const roomInfo = convo.toOpenGroupV2(); - const res = await sogsV3AddPermissions([user], roomInfo, permissions); - if (!res) { - window?.log?.warn('failed to add user permissions:', res); - - ToastUtils.pushFailedToChangeUserPermissions(); - } else { - window?.log?.info(`${user.key} given permissions ${permissions.join(', ')}...`); - ToastUtils.pushUserPermissionsChanged(); - } - } catch (e) { - window?.log?.error('Got error while adding user permissions:', e); - ToastUtils.pushFailedToChangeUserPermissions(); - } -} - -export async function clearUserPermissions( - sender: string | undefined, - convoId: string | undefined, - permissions: Array -) { - try { - if (typeof convoId === 'undefined') { - window?.log?.warn('undefined convo passed to clearUserPermissions'); - return; - } - const user = PubKey.cast(sender); - const convo = ConvoHub.use().getOrThrow(convoId); - - const roomInfo = convo.toOpenGroupV2(); - const res = await sogsV3ClearPermissions([user], roomInfo, permissions); - if (!res) { - window?.log?.warn('failed to add user permissions:', res); - - ToastUtils.pushFailedToChangeUserPermissions(); - } else { - window?.log?.info(`${user.key} given permissions ${permissions.join(', ')}...`); - ToastUtils.pushUserPermissionsChanged(); - } - } catch (e) { - window?.log?.error('Got error while clearing user permissions:', e); - ToastUtils.pushFailedToChangeUserPermissions(); - } -} - const acceptOpenGroupInvitationV2 = (completeUrl: string, roomName?: string) => { const onClickClose = () => { window.inboxStore?.dispatch(updateConfirmModal(null)); diff --git a/ts/models/message.ts b/ts/models/message.ts index a8219ba7bb..dc1b0ea435 100644 --- a/ts/models/message.ts +++ b/ts/models/message.ts @@ -818,7 +818,6 @@ export class MessageModel extends Model { // we can only send a single preview const firstPreviewWithData = previewWithData?.[0] || null; - // we want to go for the v1, if this is an OpenGroupV1 or not an open group at all if (conversation?.isOpenGroupV2()) { const openGroupV2 = conversation.toOpenGroupV2(); attachmentPromise = uploadAttachmentsV3(finalAttachments, openGroupV2); diff --git a/ts/react.d.ts b/ts/react.d.ts index a9b4dfb75b..0f84c1c36b 100644 --- a/ts/react.d.ts +++ b/ts/react.d.ts @@ -324,6 +324,7 @@ declare module 'react' { | 'disappearing-messages' | 'group-members' | 'edit-group-name' + | 'edit-community-permissions' // SessionRadioGroup & SessionRadio | 'password-input-confirm' @@ -434,7 +435,6 @@ declare module 'react' { | 'empty-msg-view-welcome' | 'last-updated-timestamp' | 'account-id-pill' - | 'test-ignore' // Once the whole app have datatestId when required, this `invalid-data-testid` will be removed | 'invalid-data-testid'; diff --git a/ts/session/apis/open_group_api/sogsv3/sogsV3AddRemoveMods.ts b/ts/session/apis/open_group_api/sogsv3/sogsV3AddRemoveMods.ts index 443e2850f3..1006a16dc6 100644 --- a/ts/session/apis/open_group_api/sogsv3/sogsV3AddRemoveMods.ts +++ b/ts/session/apis/open_group_api/sogsv3/sogsV3AddRemoveMods.ts @@ -2,7 +2,7 @@ import AbortController from 'abort-controller'; import { PubKey } from '../../../types'; -import { batchFirstSubIsSuccess, sogsBatchSend } from './sogsV3BatchPoll'; +import { batchEverySubIsSuccess, batchFirstSubIsSuccess, sogsBatchSend } from './sogsV3BatchPoll'; import { OpenGroupRequestCommonType } from '../../../../data/types'; import { DURATION } from '../../../constants'; @@ -63,7 +63,7 @@ export const sogsV3RemoveAdmins = async ( 'batch', 10 * DURATION.SECONDS ); - const isSuccess = batchSendResponse?.body?.every(m => m?.code === 200) || false; + const isSuccess = batchEverySubIsSuccess(batchSendResponse); if (!isSuccess) { window.log.warn('remove mods failed with body', batchSendResponse?.body); } diff --git a/ts/session/apis/open_group_api/sogsv3/sogsV3BanUnban.ts b/ts/session/apis/open_group_api/sogsv3/sogsV3BanUnban.ts index 9cf7813657..d81283b279 100644 --- a/ts/session/apis/open_group_api/sogsv3/sogsV3BanUnban.ts +++ b/ts/session/apis/open_group_api/sogsv3/sogsV3BanUnban.ts @@ -3,123 +3,93 @@ import { PubKey } from '../../../types'; import { batchFirstSubIsSuccess, OpenGroupBatchRow, sogsBatchSend } from './sogsV3BatchPoll'; import { OpenGroupRequestCommonType } from '../../../../data/types'; import { DURATION } from '../../../constants'; +import { + isServerBanUnban, + type BanServerWideOrNot, + type UnbanServerWideOrNot, +} from '../../../../state/ducks/modalDialog'; -export const sogsV3BanUser = async ( - userToBan: PubKey, - roomInfos: OpenGroupRequestCommonType, - deleteAllMessages: boolean -): Promise => { +export const sogsV3BanUser = async (args: { + roomInfos: OpenGroupRequestCommonType; + userToBan: PubKey; + deleteAllMessages: boolean; + banType: BanServerWideOrNot; +}): Promise => { const sequence: Array = [ { type: 'banUnbanUser', banUnbanUser: { - sessionId: userToBan.key, - roomId: roomInfos.roomId, - type: 'ban', - isGlobal: false, + sessionId: args.userToBan.key, + type: args.banType, + roomId: args.roomInfos.roomId, }, }, ]; - if (deleteAllMessages) { - sequence.push({ - type: 'deleteAllPosts', - deleteAllPosts: { sessionId: userToBan.key, roomId: roomInfos.roomId }, - }); + if (args.deleteAllMessages) { + sequence.push( + isServerBanUnban(args.banType) + ? { + type: 'deleteAllUserPosts', + deleteAllUserPosts: { sessionId: args.userToBan.key }, + } + : { + type: 'deleteAllPosts', + deleteAllPosts: { sessionId: args.userToBan.key, roomId: args.roomInfos.roomId }, + } + ); } const batchSendResponse = await sogsBatchSend( - roomInfos.serverUrl, - new Set([roomInfos.roomId]), + args.roomInfos.serverUrl, + new Set([args.roomInfos.roomId]), new AbortController().signal, sequence, 'sequence', 10 * DURATION.SECONDS ); - return batchFirstSubIsSuccess(batchSendResponse); -}; - -export const sogsV3UnbanUser = async ( - userToBan: PubKey, - roomInfos: OpenGroupRequestCommonType -): Promise => { - const batchSendResponse = await sogsBatchSend( - roomInfos.serverUrl, - new Set([roomInfos.roomId]), - new AbortController().signal, - [ - { - type: 'banUnbanUser', - banUnbanUser: { - sessionId: userToBan.key, - roomId: roomInfos.roomId, - type: 'unban', - isGlobal: false, - }, - }, - ], - 'batch', - 10 * DURATION.SECONDS - ); - return batchFirstSubIsSuccess(batchSendResponse); -}; - -export const sogsV3ServerBanUser = async ( - userToBan: PubKey, - roomInfos: OpenGroupRequestCommonType, - deleteAllMessages: boolean -): Promise => { - const sequence: Array = [ - { - type: 'banUnbanUser', - banUnbanUser: { - sessionId: userToBan.key, - roomId: roomInfos.roomId, - type: 'ban', - isGlobal: true, - }, - }, - ]; + const ret = batchFirstSubIsSuccess(batchSendResponse); - if (deleteAllMessages) { - sequence.push({ - type: 'deleteAllUserPosts', - deleteAllUserPosts: { sessionId: userToBan.key }, - }); + if (!ret) { + window.log.warn( + `sogsV3BanUser failed with statuses:`, + batchSendResponse?.body?.map(m => m.code) + ); } - const batchSendResponse = await sogsBatchSend( - roomInfos.serverUrl, - new Set([roomInfos.roomId]), - new AbortController().signal, - sequence, - 'sequence', - 10 * DURATION.SECONDS - ); - return batchFirstSubIsSuccess(batchSendResponse); + return ret; }; -export const sogsV3ServerUnbanUser = async ( - userToBan: PubKey, - roomInfos: OpenGroupRequestCommonType -): Promise => { +export const sogsV3UnbanUser = async (args: { + userToUnban: PubKey; + roomInfos: OpenGroupRequestCommonType; + banType: UnbanServerWideOrNot; +}): Promise => { const batchSendResponse = await sogsBatchSend( - roomInfos.serverUrl, - new Set([roomInfos.roomId]), + args.roomInfos.serverUrl, + new Set([args.roomInfos.roomId]), new AbortController().signal, [ { type: 'banUnbanUser', banUnbanUser: { - sessionId: userToBan.key, - roomId: roomInfos.roomId, - type: 'unban', - isGlobal: true, + sessionId: args.userToUnban.key, + type: args.banType, + roomId: args.roomInfos.roomId, }, }, ], 'batch', 10 * DURATION.SECONDS ); - return batchFirstSubIsSuccess(batchSendResponse); + const ret = batchFirstSubIsSuccess(batchSendResponse); + + if (!ret) { + window.log.warn( + `sogsV3UnbanUser failed with statuses:`, + batchSendResponse?.body?.map(m => m.code) + ); + } + + return ret; }; diff --git a/ts/session/apis/open_group_api/sogsv3/sogsV3BatchPoll.ts b/ts/session/apis/open_group_api/sogsv3/sogsV3BatchPoll.ts index 85d698fa02..6b5f24b25b 100644 --- a/ts/session/apis/open_group_api/sogsv3/sogsV3BatchPoll.ts +++ b/ts/session/apis/open_group_api/sogsv3/sogsV3BatchPoll.ts @@ -22,6 +22,13 @@ import type { WithSessionIds, } from './sogsWith'; import { FetchDestination } from '../../../utils/InsecureNodeFetch'; +import { + isBan, + isServerBanUnban, + type BanUnbanRoomWideOnly, + type BanUnbanServerWideOnly, +} from '../../../../state/ducks/modalDialog'; +import { ed25519Str } from '../../../utils/String'; type BatchFetchRequestOptions = { method: 'POST' | 'PUT' | 'GET' | 'DELETE'; @@ -133,6 +140,10 @@ export function batchFirstSubIsSuccess(response?: BatchSogsResponse | null): boo return Boolean(status && isNumber(status) && status >= 200 && status <= 300); } +export function batchEverySubIsSuccess(response?: BatchSogsResponse | null): boolean { + return response?.body?.every(m => isNumber(m.code) && m?.code >= 200 && m?.code <= 300) ?? false; +} + export type SubRequestCapabilitiesType = { type: 'capabilities' }; export type SubRequestMessagesObjectType = @@ -192,13 +203,22 @@ export type SubRequestAddRemoveModeratorType = { export type SubRequestBanUnbanUserType = { type: 'banUnbanUser'; banUnbanUser: { - type: 'ban' | 'unban'; sessionId: string; // can be blinded id or not - roomId: string; - isGlobal: boolean; - }; + } & ( + | { + roomId: string; + type: BanUnbanRoomWideOnly; + } + | { type: BanUnbanServerWideOnly } + ); }; +export function isServerBanUnbanAction( + action: SubRequestBanUnbanUserType['banUnbanUser'] +): action is Extract { + return isServerBanUnban(action.type); +} + export type SubRequestDeleteAllUserPostsType = { type: 'deleteAllPosts'; deleteAllPosts: { @@ -274,20 +294,9 @@ export type OpenGroupBatchRow = | SubRequestUpdateUserRoomPermissionsType | SubRequestUpdateRoomPermsType; -type OpenGroupPermissionSelection = { - [permission in `${Prefix}${OpenGroupPermissionType}`]?: boolean; -}; - -function makePermissionSelection( - permissions: Array | undefined, - choice: boolean, - prefix: Prefix -): OpenGroupPermissionSelection; - -function makePermissionSelection( - permissions: Array | undefined, - choice: boolean -): OpenGroupPermissionSelection; +type OpenGroupPermissionSelection = Partial< + Record<`${Prefix}${OpenGroupPermissionType}`, boolean> +>; function makePermissionSelection( permissions: Array | undefined, @@ -387,32 +396,31 @@ const makeBatchRequestPayload = ( }, })); case 'banUnbanUser': - const isBan = Boolean(options.banUnbanUser.type === 'ban'); - const isGlobal = options.banUnbanUser.isGlobal; + const details = options.banUnbanUser; + const isBanAction = isBan(details.type); + const isServerWideAction = isServerBanUnbanAction(details); window?.log?.info( - `BAN: ${options.banUnbanUser.sessionId}, global: ${options.banUnbanUser.isGlobal}` + `banUnbanUser: ${ed25519Str(details.sessionId)}, server-wide: ${isServerWideAction}` ); - if (isGlobal) { + const path = `/user/${details.sessionId}/${isBanAction ? 'ban' : 'unban'}`; + if (isServerWideAction) { // Issue server-wide (un)ban. return { method: 'POST', - path: `/user/${options.banUnbanUser.sessionId}/${isBan ? 'ban' : 'unban'}`, + path, json: { global: true, - // timeout: null, // for now we do not support the timeout argument }, }; } + // Issue room-wide (un)ban. return { method: 'POST', - path: `/user/${options.banUnbanUser.sessionId}/${isBan ? 'ban' : 'unban'}`, + path, json: { - rooms: [options.banUnbanUser.roomId], - + rooms: [details.roomId], // watch out ban and unban user do not allow the same args - // global: false, // for now we do not support the global argument, rooms cannot be set if we use it - // timeout: null, // for now we do not support the timeout argument }, }; case 'deleteAllPosts': diff --git a/ts/session/apis/open_group_api/sogsv3/sogsV3RoomPermissions.ts b/ts/session/apis/open_group_api/sogsv3/sogsV3RoomPermissions.ts index 10afce29ec..09e50317dc 100644 --- a/ts/session/apis/open_group_api/sogsv3/sogsV3RoomPermissions.ts +++ b/ts/session/apis/open_group_api/sogsv3/sogsV3RoomPermissions.ts @@ -5,16 +5,16 @@ import AbortController from 'abort-controller'; import { OpenGroupRequestCommonType } from '../../../../data/types'; -import { sogsBatchSend } from './sogsV3BatchPoll'; +import { batchEverySubIsSuccess, sogsBatchSend } from './sogsV3BatchPoll'; import { DURATION } from '../../../constants'; -export type OpenGroupRoomPermissionType = +export type CommunityRoomPermissionType = | 'default_read' | 'default_write' | 'default_accessible' | 'default_upload'; -export type OpenGroupRoomPermissionSetType = Record; +export type OpenGroupRoomPermissionSetType = Record; type PermsToSet = Partial; @@ -24,7 +24,7 @@ export const sogsV3SetRoomPermissions = async ( ): Promise => { const permsToSet: PermsToSet = {}; Object.entries(permissions).forEach(([permission, value]) => { - permsToSet[permission as OpenGroupRoomPermissionType] = value; + permsToSet[permission as CommunityRoomPermissionType] = value; }); const batchSendResponse = await sogsBatchSend( roomInfos.serverUrl, @@ -42,7 +42,7 @@ export const sogsV3SetRoomPermissions = async ( 'batch', 10 * DURATION.SECONDS ); - const isSuccess = batchSendResponse?.body?.every(m => m?.code === 200) || false; + const isSuccess = batchEverySubIsSuccess(batchSendResponse); if (!isSuccess) { window.log.warn('set permissions failed with body', batchSendResponse?.body); } diff --git a/ts/session/apis/open_group_api/sogsv3/sogsV3UserPermissions.ts b/ts/session/apis/open_group_api/sogsv3/sogsV3UserPermissions.ts index 3e66753d0b..24d122e0b9 100644 --- a/ts/session/apis/open_group_api/sogsv3/sogsV3UserPermissions.ts +++ b/ts/session/apis/open_group_api/sogsv3/sogsV3UserPermissions.ts @@ -6,7 +6,7 @@ import AbortController from 'abort-controller'; import { PubKey } from '../../../types'; import { OpenGroupRequestCommonType } from '../../../../data/types'; -import { sogsBatchSend } from './sogsV3BatchPoll'; +import { batchEverySubIsSuccess, sogsBatchSend } from './sogsV3BatchPoll'; import { DURATION } from '../../../constants'; export type OpenGroupPermissionType = 'access' | 'read' | 'upload' | 'write'; @@ -31,7 +31,7 @@ export const sogsV3AddPermissions = async ( 'batch', 10 * DURATION.SECONDS ); - const isSuccess = batchSendResponse?.body?.every(m => m?.code === 200) || false; + const isSuccess = batchEverySubIsSuccess(batchSendResponse); if (!isSuccess) { window.log.warn('add permissions failed with body', batchSendResponse?.body); } @@ -58,7 +58,7 @@ export const sogsV3ClearPermissions = async ( 'batch', 10 * DURATION.SECONDS ); - const isSuccess = batchSendResponse?.body?.every(m => m?.code === 200) || false; + const isSuccess = batchEverySubIsSuccess(batchSendResponse); if (!isSuccess) { window.log.warn('add permissions failed with body', batchSendResponse?.body); } diff --git a/ts/state/ducks/modalDialog.tsx b/ts/state/ducks/modalDialog.tsx index 641060931f..7bcb55e436 100644 --- a/ts/state/ducks/modalDialog.tsx +++ b/ts/state/ducks/modalDialog.tsx @@ -17,7 +17,24 @@ import { SessionButtonType } from '../../components/basic/SessionButton'; import { CTAVariant } from '../../components/dialog/cta/types'; import { CTAInteraction, registerCtaInteraction } from '../../util/ctaHistory'; -export type BanType = 'ban' | 'unban'; +export type BanType = 'ban' | 'unban' | 'server-ban' | 'server-unban'; + +export type BanUnbanRoomWideOnly = Extract; +export type BanServerWideOrNot = Extract; +export type UnbanServerWideOrNot = Extract; +export type BanUnbanServerWideOnly = Extract; + +export function isBan(banType: BanType): banType is BanServerWideOrNot { + return ['ban', 'server-ban'].includes(banType); +} + +export function isUnban(banType: BanType): banType is UnbanServerWideOrNot { + return ['unban', 'server-unban'].includes(banType); +} + +export function isServerBanUnban(banType: BanType): banType is BanUnbanServerWideOnly { + return ['server-ban', 'server-unban'].includes(banType); +} export type UserSettingsPage = | 'default' @@ -68,17 +85,12 @@ export type BanOrUnbanUserModalState = pubkey?: string; }) | null; -export type ServerBanOrUnbanUserModalState = - | (WithConvoId & { - banType: BanType; - pubkey?: string; - }) - | null; + export type AddModeratorsModalState = InviteContactModalState; export type RemoveModeratorsModalState = InviteContactModalState; export type UpdateGroupMembersModalState = InviteContactModalState; // export type UpdateGroupNameModalState = WithConvoId | null; -export type UpdateGroupPermissionsModalState = InviteContactModalState; +export type UpdateCommunityPermissionsModalState = InviteContactModalState; type UpdateConversationDetailsModalState = WithConvoId | null; export type ChangeNickNameModalState = InviteContactModalState; export type UserSettingsModalState = WithUserSettingsPage | null; @@ -151,13 +163,12 @@ export type ModalId = | 'confirmModal' | 'inviteContactModal' | 'banOrUnbanUserModal' - | 'serverBanOrUnbanUserModal' | 'blockOrUnblockModal' | 'removeModeratorsModal' | 'addModeratorsModal' | 'updateConversationDetailsModal' | 'groupMembersModal' - | 'groupPermissionsModal' + | 'communityPermissionsModal' | 'userProfileModal' | 'nickNameModal' | 'userSettingsModal' @@ -179,13 +190,12 @@ export type ModalState = { confirmModal: ConfirmModalState; inviteContactModal: InviteContactModalState; banOrUnbanUserModal: BanOrUnbanUserModalState; - serverBanOrUnbanUserModal: ServerBanOrUnbanUserModalState; blockOrUnblockModal: BlockOrUnblockModalState; removeModeratorsModal: RemoveModeratorsModalState; addModeratorsModal: AddModeratorsModalState; updateConversationDetailsModal: UpdateConversationDetailsModalState; groupMembersModal: UpdateGroupMembersModalState; - groupPermissionsModal: UpdateGroupPermissionsModalState; + communityPermissionsModal: UpdateCommunityPermissionsModalState; userProfileModal: UserProfileModalState; nickNameModal: ChangeNickNameModalState; userSettingsModal: UserSettingsModalState; @@ -212,11 +222,10 @@ export const initialModalState: ModalState = { addModeratorsModal: null, removeModeratorsModal: null, banOrUnbanUserModal: null, - serverBanOrUnbanUserModal: null, blockOrUnblockModal: null, updateConversationDetailsModal: null, groupMembersModal: null, - groupPermissionsModal: null, + communityPermissionsModal: null, userProfileModal: null, nickNameModal: null, userSettingsModal: null, @@ -284,12 +293,7 @@ const ModalSlice = createSlice({ updateBanOrUnbanUserModal(state, action: PayloadAction) { return pushOrPopModal(state, 'banOrUnbanUserModal', action.payload); }, - updateServerBanOrUnbanUserModal( - state, - action: PayloadAction - ) { - return { ...state, serverBanOrUnbanUserModal: action.payload }; - }, + updateBlockOrUnblockModal(state, action: PayloadAction) { return pushOrPopModal(state, 'blockOrUnblockModal', action.payload); }, @@ -308,11 +312,11 @@ const ModalSlice = createSlice({ updateGroupMembersModal(state, action: PayloadAction) { return pushOrPopModal(state, 'groupMembersModal', action.payload); }, - updateGroupPermissionsModal( + updateCommunityPermissionsModal( state, - action: PayloadAction + action: PayloadAction ) { - return pushOrPopModal(state, 'groupPermissionsModal', action.payload); + return pushOrPopModal(state, 'communityPermissionsModal', action.payload); }, updateUserProfileModal(state, action: PayloadAction) { return pushOrPopModal(state, 'userProfileModal', action.payload); @@ -389,7 +393,7 @@ export const { updateRemoveModeratorsModal, updateConversationDetailsModal, updateGroupMembersModal, - updateGroupPermissionsModal, + updateCommunityPermissionsModal, updateUserProfileModal, changeNickNameModal, userSettingsModal, @@ -397,7 +401,6 @@ export const { updateEnterPasswordModal, updateDeleteAccountModal, updateBanOrUnbanUserModal, - updateServerBanOrUnbanUserModal, updateBlockOrUnblockModal, updateReactListModal, updateReactClearAllModal, diff --git a/ts/state/ducks/types/defaultFeatureFlags.ts b/ts/state/ducks/types/defaultFeatureFlags.ts index 4ca8916b32..8533bab5ae 100644 --- a/ts/state/ducks/types/defaultFeatureFlags.ts +++ b/ts/state/ducks/types/defaultFeatureFlags.ts @@ -9,6 +9,7 @@ export const defaultProBooleanFeatureFlags = { proAvailable: !isEmpty(process.env.SESSION_PRO), proGroupsAvailable: !isEmpty(process.env.SESSION_PRO_GROUPS), useTestProBackend: !isEmpty(process.env.TEST_PRO_BACKEND), + useDevCommunityActions: !isEmpty(process.env.DEV_COMMUNITY_ACTIONS), mockCurrentUserHasProPlatformRefundExpired: !isEmpty( process.env.SESSION_USER_HAS_PRO_PLATFORM_REFUND_EXPIRED ), diff --git a/ts/state/ducks/types/releasedFeaturesReduxTypes.ts b/ts/state/ducks/types/releasedFeaturesReduxTypes.ts index c599bdf6c7..414ec585aa 100644 --- a/ts/state/ducks/types/releasedFeaturesReduxTypes.ts +++ b/ts/state/ducks/types/releasedFeaturesReduxTypes.ts @@ -14,6 +14,7 @@ type SessionBaseBooleanFeatureFlags = { useDeterministicEncryption: boolean; useTestNet: boolean; useTestProBackend: boolean; + useDevCommunityActions: boolean; useClosedGroupV2QAButtons: boolean; alwaysShowRemainingChars: boolean; showPopoverAnchors: boolean; diff --git a/ts/state/selectors/modal.ts b/ts/state/selectors/modal.ts index a3200e4174..0647b64fcd 100644 --- a/ts/state/selectors/modal.ts +++ b/ts/state/selectors/modal.ts @@ -36,10 +36,6 @@ export function useUpdateConversationDetailsModal() { return useSelector((state: StateType) => getModal(state).updateConversationDetailsModal); } -export function useServerBanOrUnbanUserModalState() { - return useSelector((state: StateType) => getModal(state).serverBanOrUnbanUserModal); -} - export const getBlockOrUnblockUserModalState = (state: StateType) => getModal(state).blockOrUnblockModal; @@ -55,8 +51,8 @@ export function useChangeNickNameDialog() { return useSelector((state: StateType) => getModal(state).nickNameModal); } -export function useUpdateGroupPermissionsModalState() { - return useSelector((state: StateType) => getModal(state).groupPermissionsModal); +export function useUpdateCommunityPermissionsModalState() { + return useSelector((state: StateType) => getModal(state).communityPermissionsModal); } export function useUserSettingsModal() { From c5feb5e50f6fb3de8f7412f42f4ee237d4dd9a39 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Wed, 4 Feb 2026 10:31:47 +1100 Subject: [PATCH 94/97] chore: manual string update --- ts/localization | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ts/localization b/ts/localization index c0714a8916..1b1337602c 160000 --- a/ts/localization +++ b/ts/localization @@ -1 +1 @@ -Subproject commit c0714a8916a38672584323e6084e8cedc36d7243 +Subproject commit 1b1337602c88edef62e33b201177a7cd2b0fb215 From f40b931ed0065d926152fe5e1e44fa836eddc70a Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Tue, 10 Feb 2026 12:01:53 +1100 Subject: [PATCH 95/97] fix: use dev strings for now as they are not on crowdin --- .../message-content/MessageContextMenu.tsx | 10 +++++---- .../message-info/components/MessageInfo.tsx | 21 ++++++++++--------- ts/components/dialog/BanOrUnbanUserDialog.tsx | 6 +++--- .../UpdateCommunityPermissionsDialog.tsx | 20 +++++++++--------- .../conversationSettingsItems.tsx | 2 +- ts/components/menu/Menu.tsx | 4 ++-- ts/localization | 2 +- ts/session/utils/Toast.tsx | 8 +++---- .../browser/libsession_worker_interface.ts | 4 ---- 9 files changed, 38 insertions(+), 39 deletions(-) diff --git a/ts/components/conversation/message/message-content/MessageContextMenu.tsx b/ts/components/conversation/message/message-content/MessageContextMenu.tsx index e699bcf056..458701dc8e 100644 --- a/ts/components/conversation/message/message-content/MessageContextMenu.tsx +++ b/ts/components/conversation/message/message-content/MessageContextMenu.tsx @@ -162,21 +162,23 @@ const CommunityAdminActionItems = ({ messageId }: WithMessageId) => { ) : null} {serverBanUser ? ( - {tr('serverBanUser')} + {tr('serverBanUserDev')} ) : null} {serverUnbanUser ? ( - {tr('serverUnbanUser')} + + {tr('serverUnbanUserDev')} + ) : null} {!isSenderAdmin && isRoomUploadRestricted && ( <> {canSenderUpload && addUploadPermissionCb ? ( - {tr('addUploadPermission')} + {tr('addUploadPermissionDev')} ) : null} {canSenderNotUpload && clearUploadPermissionCb ? ( - {tr('clearUploadPermission')} + {tr('clearUploadPermissionDev')} ) : null} diff --git a/ts/components/conversation/right-panel/overlay/message-info/components/MessageInfo.tsx b/ts/components/conversation/right-panel/overlay/message-info/components/MessageInfo.tsx index 79e45ef65a..aa26e39f0b 100644 --- a/ts/components/conversation/right-panel/overlay/message-info/components/MessageInfo.tsx +++ b/ts/components/conversation/right-panel/overlay/message-info/components/MessageInfo.tsx @@ -103,31 +103,32 @@ const DebugMessageInfo = ({ messageId }: { messageId: string }) => { if (!isDevProd()) { return null; } - // Note: the strings here are hardcoded because we do not share them with other platforms through crowdin return ( <> - {convoId ? : null} - {messageHash ? : null} - {serverId ? : null} - {timestamp ? : null} + {convoId ? : null} + {messageHash ? : null} + {serverId ? : null} + {timestamp ? : null} {serverTimestamp ? ( - + + ) : null} + {expirationType ? ( + ) : null} - {expirationType ? : null} {expirationDurationMs ? ( ) : null} {expirationTimestamp ? ( ) : null} {message ? ( - + ) : null} ); diff --git a/ts/components/dialog/BanOrUnbanUserDialog.tsx b/ts/components/dialog/BanOrUnbanUserDialog.tsx index d5e23a06d7..484d7fdf05 100644 --- a/ts/components/dialog/BanOrUnbanUserDialog.tsx +++ b/ts/components/dialog/BanOrUnbanUserDialog.tsx @@ -164,9 +164,9 @@ export const BanOrUnBanUserDialog = (props: { if (isServerWide) { if (isBanAction) { - buttonText = tr('serverBanUser'); + buttonText = tr('serverBanUserDev'); } else { - buttonText = tr('serverUnbanUser'); + buttonText = tr('serverUnbanUserDev'); } } else if (isBanAction) { buttonText = tr('banUser'); @@ -206,7 +206,7 @@ export const BanOrUnBanUserDialog = (props: { buttonType={SessionButtonType.Simple} buttonColor={SessionButtonColor.Danger} onClick={startBanAndDeleteAllSequence} - text={isServerWide ? tr('serverBanUserAndDeleteAll') : tr('banDeleteAll')} + text={isServerWide ? tr('serverBanUserAndDeleteAllDev') : tr('banDeleteAll')} disabled={inProgress} dataTestId="ban-user-delete-all-confirm-button" /> diff --git a/ts/components/dialog/UpdateCommunityPermissionsDialog.tsx b/ts/components/dialog/UpdateCommunityPermissionsDialog.tsx index 66b6cf56b5..512ad629ac 100644 --- a/ts/components/dialog/UpdateCommunityPermissionsDialog.tsx +++ b/ts/components/dialog/UpdateCommunityPermissionsDialog.tsx @@ -53,7 +53,7 @@ export function UpdateCommunityPermissionsDialog(props: WithConvoId) { return ( } + headerChildren={} onClose={closeDialog} buttonChildren={ @@ -75,15 +75,15 @@ export function UpdateCommunityPermissionsDialog(props: WithConvoId) { @@ -96,8 +96,8 @@ export function UpdateCommunityPermissionsDialog(props: WithConvoId) { @@ -110,8 +110,8 @@ export function UpdateCommunityPermissionsDialog(props: WithConvoId) { @@ -124,8 +124,8 @@ export function UpdateCommunityPermissionsDialog(props: WithConvoId) { diff --git a/ts/components/dialog/conversationSettings/conversationSettingsItems.tsx b/ts/components/dialog/conversationSettings/conversationSettingsItems.tsx index b18e66fdf7..1be0517cfb 100644 --- a/ts/components/dialog/conversationSettings/conversationSettingsItems.tsx +++ b/ts/components/dialog/conversationSettings/conversationSettingsItems.tsx @@ -285,7 +285,7 @@ export function ChangeCommunityPermissionsButton({ conversationId }: WithConvoId return ( } - text={{ token: 'communityChangePermissions' }} + text={{ token: 'communityChangePermissionsDev' }} onClick={cb} dataTestId="edit-community-permissions" /> diff --git a/ts/components/menu/Menu.tsx b/ts/components/menu/Menu.tsx index 35fd90c43c..e9e9ece963 100644 --- a/ts/components/menu/Menu.tsx +++ b/ts/components/menu/Menu.tsx @@ -168,7 +168,7 @@ export const ServerUnbanMenuItem = (): JSX.Element | null => { if (showUnbanUserCb) { return ( - + ); } @@ -185,7 +185,7 @@ export const ServerBanMenuItem = (): JSX.Element | null => { if (showUnbanUserCb) { return ( - + ); } diff --git a/ts/localization b/ts/localization index 1b1337602c..f2620de9c8 160000 --- a/ts/localization +++ b/ts/localization @@ -1 +1 @@ -Subproject commit 1b1337602c88edef62e33b201177a7cd2b0fb215 +Subproject commit f2620de9c8dc757ae7a131c55f60cdfd0074f47f diff --git a/ts/session/utils/Toast.tsx b/ts/session/utils/Toast.tsx index ea12165401..4846df133b 100644 --- a/ts/session/utils/Toast.tsx +++ b/ts/session/utils/Toast.tsx @@ -91,7 +91,7 @@ export function pushUserBanFailure() { } export function pushGlobalUserBanFailure() { - pushToastError('globalUserBanFailed', tStripped('globalUserBanFailed')); + pushToastError('globalUserBanFailed', tStripped('globalUserBanFailedDev')); } export function pushUserUnbanSuccess() { @@ -103,7 +103,7 @@ export function pushUserUnbanFailure() { } export function pushGlobalUserUnbanFailure() { - pushToastError('globalUserUnbanFailed', tStripped('globalUserUnbanFailed')); + pushToastError('globalUserUnbanFailed', tStripped('globalUserUnbanFailedDev')); } export function pushMessageDeleteForbidden() { @@ -250,11 +250,11 @@ export function pushUserRemovedFromModerators(names: Array) { } export function pushFailedToChangeUserPermissions() { - pushToastWarning('failedToChangeUserPermissions', tStripped('failedToChangeUserPermissions')); + pushToastWarning('failedToChangeUserPermissions', tStripped('failedToChangeUserPermissionsDev')); } export function pushUserPermissionsChanged() { - pushToastSuccess('userPermissionsChanged', tStripped('userPermissionsChanged')); + pushToastSuccess('userPermissionsChanged', tStripped('userPermissionsChangedDev')); } export function pushInvalidPubKey() { diff --git a/ts/webworker/workers/browser/libsession_worker_interface.ts b/ts/webworker/workers/browser/libsession_worker_interface.ts index 326e923c73..f77556449a 100644 --- a/ts/webworker/workers/browser/libsession_worker_interface.ts +++ b/ts/webworker/workers/browser/libsession_worker_interface.ts @@ -794,10 +794,6 @@ export const BlindingActions: BlindingActionsCalls = { callLibSessionWorker(['Blinding', 'blindVersionPubkey', opts]) as Promise< ReturnType >, - blindVersionSign: async (opts: Parameters[0]) => - callLibSessionWorker(['Blinding', 'blindVersionSign', opts]) as Promise< - ReturnType - >, blindVersionSignRequest: async ( opts: Parameters[0] ) => From 56f41d479fd51bf729004b4b7041e683585abff4 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Tue, 10 Feb 2026 12:13:10 +1100 Subject: [PATCH 96/97] fix: qa issues fixes --- ts/components/dialog/BanOrUnbanUserDialog.tsx | 4 ++-- ts/components/menu/Menu.tsx | 2 +- ts/components/menuAndSettingsHooks/useCopyAccountId.ts | 8 +++++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/ts/components/dialog/BanOrUnbanUserDialog.tsx b/ts/components/dialog/BanOrUnbanUserDialog.tsx index 484d7fdf05..8da375adbf 100644 --- a/ts/components/dialog/BanOrUnbanUserDialog.tsx +++ b/ts/components/dialog/BanOrUnbanUserDialog.tsx @@ -70,10 +70,10 @@ async function banOrUnBanUserCall( ToastUtils.pushUserBanFailure(); break; case 'unban': - ToastUtils.pushGlobalUserBanFailure(); + ToastUtils.pushUserUnbanFailure(); break; case 'server-ban': - ToastUtils.pushUserUnbanFailure(); + ToastUtils.pushGlobalUserBanFailure(); break; case 'server-unban': ToastUtils.pushGlobalUserUnbanFailure(); diff --git a/ts/components/menu/Menu.tsx b/ts/components/menu/Menu.tsx index e9e9ece963..f9359ef416 100644 --- a/ts/components/menu/Menu.tsx +++ b/ts/components/menu/Menu.tsx @@ -185,7 +185,7 @@ export const ServerBanMenuItem = (): JSX.Element | null => { if (showUnbanUserCb) { return ( - + ); } diff --git a/ts/components/menuAndSettingsHooks/useCopyAccountId.ts b/ts/components/menuAndSettingsHooks/useCopyAccountId.ts index 2ceaa00ceb..2e59b0d748 100644 --- a/ts/components/menuAndSettingsHooks/useCopyAccountId.ts +++ b/ts/components/menuAndSettingsHooks/useCopyAccountId.ts @@ -1,11 +1,17 @@ import { useIsPrivate } from '../../hooks/useParamSelector'; import { PubKey } from '../../session/types'; import { ToastUtils } from '../../session/utils'; +import { getFeatureFlag } from '../../state/ducks/types/releasedFeaturesReduxTypes'; function useShowCopyAccountId(conversationId?: string) { const isPrivate = useIsPrivate(conversationId); - return conversationId && isPrivate && !PubKey.isBlinded(conversationId); + return ( + conversationId && + isPrivate && + (!PubKey.isBlinded(conversationId) || + (PubKey.isBlinded(conversationId) && getFeatureFlag('useDevCommunityActions'))) + ); } export function useShowCopyAccountIdCb(conversationId?: string) { From 280452ad0501aa478a3ca909e8c9419d509f7a80 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Tue, 10 Feb 2026 13:43:17 +1100 Subject: [PATCH 97/97] chore: lint for now --- ts/webworker/workers/browser/libsession_worker_interface.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ts/webworker/workers/browser/libsession_worker_interface.ts b/ts/webworker/workers/browser/libsession_worker_interface.ts index f77556449a..80bed4d28c 100644 --- a/ts/webworker/workers/browser/libsession_worker_interface.ts +++ b/ts/webworker/workers/browser/libsession_worker_interface.ts @@ -800,6 +800,10 @@ export const BlindingActions: BlindingActionsCalls = { callLibSessionWorker(['Blinding', 'blindVersionSignRequest', opts]) as Promise< ReturnType >, + blindVersionSign: async (opts: Parameters[0]) => + callLibSessionWorker(['Blinding', 'blindVersionSign', opts]) as Promise< + ReturnType + >, }; export const UtilitiesActions: UtilitiesWrapperActionsCalls = {