From 695e8672212badaaa15680af06f5f2ae9d6e0f22 Mon Sep 17 00:00:00 2001 From: Ian Macdonald Date: Sat, 14 May 2022 18:23:51 +0200 Subject: [PATCH 1/3] Add setting to specify minimum age of open group messages to prune. When an open group has more than 2000 messages, those older than the specified number of months will be pruned on application start-up. Fixes #2310. --- _locales/en/messages.json | 4 + .../settings/PruningSessionSlider.tsx | 36 +++++++++ .../settings/section/CategoryAppearance.tsx | 2 + ts/mains/main_node.ts | 13 ++++ ts/node/sql.ts | 78 ++++++++++--------- ts/types/LocalizerKeys.ts | 4 + 6 files changed, 100 insertions(+), 37 deletions(-) create mode 100644 ts/components/settings/PruningSessionSlider.tsx diff --git a/_locales/en/messages.json b/_locales/en/messages.json index af3f62d7d..6750a6e39 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -137,6 +137,10 @@ "typingIndicatorsSettingDescription": "See and share when messages are being typed (applies to all sessions).", "typingIndicatorsSettingTitle": "Typing Indicators", "zoomFactorSettingTitle": "Zoom Factor", + "pruneSettingTitle": "Prune Old Open Group Messages", + "pruneSettingDescription": "When Session starts, prune messages older than this from groups with > 2000 messages (0 = no pruning)", + "pruneSettingUnit": "month", + "pruneSettingUnits": "months", "notificationSettingsDialog": "When messages arrive, display notifications that reveal...", "disableNotifications": "Mute notifications", "nameAndMessage": "Name and content", diff --git a/ts/components/settings/PruningSessionSlider.tsx b/ts/components/settings/PruningSessionSlider.tsx new file mode 100644 index 000000000..fad195771 --- /dev/null +++ b/ts/components/settings/PruningSessionSlider.tsx @@ -0,0 +1,36 @@ +import Slider from 'rc-slider'; +import React from 'react'; +// tslint:disable-next-line: no-submodule-imports +import useUpdate from 'react-use/lib/useUpdate'; +import { SessionSettingsItemWrapper } from './SessionSettingListItem'; +import { ToastUtils } from '../../session/utils'; + +export const PruningSessionSlider = (props: { onSliderChange?: (value: number) => void }) => { + const forceUpdate = useUpdate(); + const handleSlider = (valueToForward: number) => { + props?.onSliderChange?.(valueToForward); + window.setSettingValue('prune-setting', valueToForward); + ToastUtils.pushRestartNeeded(); + forceUpdate(); + }; + const currentValueFromSettings = window.getSettingValue('prune-setting') || 0; + + return ( + +
+ + +
+

{currentValueFromSettings} {currentValueFromSettings === 1 ? window.i18n('pruneSettingUnit') : window.i18n('pruneSettingUnits')}

+
+
+
+ ); +}; diff --git a/ts/components/settings/section/CategoryAppearance.tsx b/ts/components/settings/section/CategoryAppearance.tsx index 39e1b237b..d14b21d6d 100644 --- a/ts/components/settings/section/CategoryAppearance.tsx +++ b/ts/components/settings/section/CategoryAppearance.tsx @@ -13,6 +13,7 @@ import { SessionButtonColor } from '../../basic/SessionButton'; import { SessionSettingButtonItem, SessionToggleWithDescription } from '../SessionSettingListItem'; import { ZoomingSessionSlider } from '../ZoomingSessionSlider'; +import { PruningSessionSlider } from '../PruningSessionSlider'; async function toggleLinkPreviews() { const newValue = !window.getSettingValue('link-preview-setting'); @@ -119,6 +120,7 @@ export const SettingsCategoryAppearance = (props: { hasPassword: boolean | null description={window.i18n('audioMessageAutoplayDescription')} active={audioAutoPlay} /> + { dropFtsAndTriggers(db); - v2Convos.forEach(convo => { - const convoId = convo.id; - const messagesInConvoBefore = getMessagesCountByConversation(convoId); - - if (messagesInConvoBefore >= maxMessagePerOpengroupConvo) { - const minute = 1000 * 60; - const sixMonths = minute * 60 * 24 * 30 * 6; - const messagesTimestampToRemove = Date.now() - sixMonths; - const countToRemove = assertGlobalInstance() - .prepare( - `SELECT count(*) from ${MESSAGES_TABLE} WHERE serverTimestamp <= $serverTimestamp AND conversationId = $conversationId;` - ) - .get({ conversationId: convoId, serverTimestamp: Date.now() - sixMonths })['count(*)']; - const start = Date.now(); - - assertGlobalInstance() - .prepare( - ` - DELETE FROM ${MESSAGES_TABLE} WHERE serverTimestamp <= $serverTimestamp AND conversationId = $conversationId` - ) - .run({ conversationId: convoId, serverTimestamp: messagesTimestampToRemove }); // delete messages older than sixMonths - const messagesInConvoAfter = getMessagesCountByConversation(convoId); - - console.info( - `Cleaning ${countToRemove} messages older than 6 months in public convo: ${convoId} took ${Date.now() - - start}ms. Old message count: ${messagesInConvoBefore}, new message count: ${messagesInConvoAfter}` - ); - - const unreadCount = getUnreadCountByConversation(convoId); - const convoProps = getConversationById(convoId); - if (convoProps) { - convoProps.unreadCount = unreadCount; - updateConversation(convoProps); + if (pruneSetting !== 0) { + v2Convos.forEach(convo => { + const convoId = convo.id; + const messagesInConvoBefore = getMessagesCountByConversation(convoId); + + if (messagesInConvoBefore >= maxMessagePerOpengroupConvo) { + const minute = 1000 * 60; + const userDefinedMonths = minute * 60 * 24 * 30 * pruneSetting; + const messagesTimestampToRemove = Date.now() - userDefinedMonths; + const countToRemove = assertGlobalInstance() + .prepare( + `SELECT count(*) from ${MESSAGES_TABLE} WHERE serverTimestamp <= $serverTimestamp AND conversationId = $conversationId;` + ) + .get({ conversationId: convoId, serverTimestamp: Date.now() - userDefinedMonths })['count(*)']; + const start = Date.now(); + + assertGlobalInstance() + .prepare( + ` + DELETE FROM ${MESSAGES_TABLE} WHERE serverTimestamp <= $serverTimestamp AND conversationId = $conversationId` + ) + .run({ conversationId: convoId, serverTimestamp: messagesTimestampToRemove }); // delete messages older than the user-specified age. + const messagesInConvoAfter = getMessagesCountByConversation(convoId); + + console.info( + `Cleaning ${countToRemove} messages older than ${pruneSetting} months in public convo: ${convoId} took ${Date.now() - + start}ms. Old message count: ${messagesInConvoBefore}, new message count: ${messagesInConvoAfter}` + ); + + const unreadCount = getUnreadCountByConversation(convoId); + const convoProps = getConversationById(convoId); + if (convoProps) { + convoProps.unreadCount = unreadCount; + updateConversation(convoProps); + } } - } - }); + }); + } else { + console.info('Skipping cleaning messages in public convos.'); + }; // now, we might have a bunch of private conversation, without any interaction and no messages // those are the conversation of the old members in the opengroups we just cleaned. @@ -3680,6 +3683,7 @@ export const sqlNode = { getPubkeysInPublicConversation, getAllGroupsInvolvingId, removeAllConversations, + cleanUpOldOpengroups, searchConversations, searchMessages, diff --git a/ts/types/LocalizerKeys.ts b/ts/types/LocalizerKeys.ts index 412e6c60d..ebbf75f96 100644 --- a/ts/types/LocalizerKeys.ts +++ b/ts/types/LocalizerKeys.ts @@ -162,6 +162,10 @@ export type LocalizerKeys = | 'copySessionID' | 'timerOption_0_seconds' | 'zoomFactorSettingTitle' + | 'pruneSettingTitle' + | 'pruneSettingDescription' + | 'pruneSettingUnit' + | 'pruneSettingUnits' | 'unableToCall' | 'callMissedTitle' | 'done' From 3713e95a9f79af5975bc282c9a0196e2d29b29ca Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Wed, 18 May 2022 11:47:42 +1000 Subject: [PATCH 2/3] feat: ask user for opengroup pruning on/off --- _locales/en/messages.json | 9 +- preload.js | 22 +++++ stylesheets/_session.scss | 2 + ts/components/leftpane/ActionsPanel.tsx | 41 ++++++++- .../settings/PruningSessionSlider.tsx | 36 -------- .../settings/section/CategoryAppearance.tsx | 27 +++--- .../settings/section/CategoryPrivacy.tsx | 28 +++++- ts/data/settings-key.ts | 17 +++- ts/mains/main_node.ts | 32 ++++--- ts/node/sql.ts | 91 +++++++++++-------- ts/types/LocalizerKeys.ts | 54 ++++++----- ts/util/accountManager.ts | 4 + ts/window.d.ts | 2 + 13 files changed, 227 insertions(+), 138 deletions(-) delete mode 100644 ts/components/settings/PruningSessionSlider.tsx diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 6750a6e39..064a5460a 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -138,9 +138,12 @@ "typingIndicatorsSettingTitle": "Typing Indicators", "zoomFactorSettingTitle": "Zoom Factor", "pruneSettingTitle": "Prune Old Open Group Messages", - "pruneSettingDescription": "When Session starts, prune messages older than this from groups with > 2000 messages (0 = no pruning)", - "pruneSettingUnit": "month", - "pruneSettingUnits": "months", + "pruneSettingDescription": "Prune messages older than 6 months from Open Groups on start", + "pruningOpengroupDialogTitle": "Open group pruning", + "pruningOpengroupDialogMessage": "Pruning old open group messages improves performance. Enable pruning for open group messages older than 6 months?", + "pruningOpengroupDialogSubMessage": "You can change this setting in the Session settings menu", + "enable": "Enable", + "keepDisabled": "Keep disabled", "notificationSettingsDialog": "When messages arrive, display notifications that reveal...", "disableNotifications": "Mute notifications", "nameAndMessage": "Name and content", diff --git a/preload.js b/preload.js index 7fafda6e7..abae0e161 100644 --- a/preload.js +++ b/preload.js @@ -86,6 +86,28 @@ window.getStartInTray = async () => { }); }; +window.getOpengroupPruning = async () => { + return new Promise(resolve => { + ipc.once('get-opengroup-pruning-response', (_event, value) => { + resolve(value); + }); + ipc.send('get-opengroup-pruning'); + }); +}; + +window.setOpengroupPruning = async opengroupPruning => + new Promise((resolve, reject) => { + ipc.once('set-opengroup-pruning-response', (_event, error) => { + if (error) { + reject(error); + return; + } + resolve(); + return; + }); + ipc.send('set-opengroup-pruning', opengroupPruning); + }); + window._ = require('lodash'); // We never do these in our code, so we'll prevent it everywhere diff --git a/stylesheets/_session.scss b/stylesheets/_session.scss index 53f23bd74..2ace0f7db 100644 --- a/stylesheets/_session.scss +++ b/stylesheets/_session.scss @@ -551,7 +551,9 @@ label { &-main-message { font-size: $session-font-md; + line-height: 1.5; } + &-sub-message { text-align: center; margin-top: 20px; diff --git a/ts/components/leftpane/ActionsPanel.tsx b/ts/components/leftpane/ActionsPanel.tsx index da6b67108..dceb78031 100644 --- a/ts/components/leftpane/ActionsPanel.tsx +++ b/ts/components/leftpane/ActionsPanel.tsx @@ -30,7 +30,11 @@ import { cleanUpOldDecryptedMedias } from '../../session/crypto/DecryptedAttachm import { DURATION } from '../../session/constants'; import { conversationChanged, conversationRemoved } from '../../state/ducks/conversations'; -import { editProfileModal, onionPathModal } from '../../state/ducks/modalDialog'; +import { + editProfileModal, + onionPathModal, + updateConfirmModal, +} from '../../state/ducks/modalDialog'; import { uploadOurAvatar } from '../../interactions/conversationInteractions'; import { ModalContainer } from '../dialog/ModalContainer'; import { debounce, isEmpty, isString } from 'lodash'; @@ -54,6 +58,9 @@ import { getLatestDesktopReleaseFileToFsV2 } from '../../session/apis/file_serve import { ipcRenderer } from 'electron'; import { UserUtils } from '../../session/utils'; +import { Storage } from '../../util/storage'; +import { SettingsKey } from '../../data/settings-key'; + const Section = (props: { type: SectionType }) => { const ourNumber = useSelector(getOurNumber); const unreadMessageCount = useSelector(getUnreadMessageCount); @@ -251,6 +258,8 @@ const doAppStartUp = () => { void loadDefaultRooms(); debounce(triggerAvatarReUploadIfNeeded, 200); + + void askEnablingOpengroupPruningIfNeeded(); }; const CallContainer = () => { @@ -279,6 +288,36 @@ async function fetchReleaseFromFSAndUpdateMain() { } } +async function askEnablingOpengroupPruningIfNeeded() { + if (Storage.get(SettingsKey.settingsOpengroupPruning) === undefined) { + const setSettingsAndCloseDialog = async (valueToSetPruningTo: boolean) => { + window.setSettingValue(SettingsKey.settingsOpengroupPruning, valueToSetPruningTo); + await window.setOpengroupPruning(valueToSetPruningTo); + window.inboxStore?.dispatch(updateConfirmModal(null)); + }; + window.inboxStore?.dispatch( + updateConfirmModal({ + onClickOk: async () => { + await setSettingsAndCloseDialog(true); + }, + onClickClose: async () => { + await setSettingsAndCloseDialog(false); + }, + onClickCancel: async () => { + await setSettingsAndCloseDialog(false); + }, + title: window.i18n('pruningOpengroupDialogTitle'), + message: window.i18n('pruningOpengroupDialogMessage'), + messageSub: window.i18n('pruningOpengroupDialogSubMessage'), + okText: window.i18n('enable'), + cancelText: window.i18n('keepDisabled'), + }) + ); + return; + } + // otherwise nothing to do. the settings is already on or off, but as expected by the user +} + /** * ActionsPanel is the far left banner (not the left pane). * The panel with buttons to switch between the message/contact/settings/theme views diff --git a/ts/components/settings/PruningSessionSlider.tsx b/ts/components/settings/PruningSessionSlider.tsx deleted file mode 100644 index fad195771..000000000 --- a/ts/components/settings/PruningSessionSlider.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import Slider from 'rc-slider'; -import React from 'react'; -// tslint:disable-next-line: no-submodule-imports -import useUpdate from 'react-use/lib/useUpdate'; -import { SessionSettingsItemWrapper } from './SessionSettingListItem'; -import { ToastUtils } from '../../session/utils'; - -export const PruningSessionSlider = (props: { onSliderChange?: (value: number) => void }) => { - const forceUpdate = useUpdate(); - const handleSlider = (valueToForward: number) => { - props?.onSliderChange?.(valueToForward); - window.setSettingValue('prune-setting', valueToForward); - ToastUtils.pushRestartNeeded(); - forceUpdate(); - }; - const currentValueFromSettings = window.getSettingValue('prune-setting') || 0; - - return ( - -
- - -
-

{currentValueFromSettings} {currentValueFromSettings === 1 ? window.i18n('pruneSettingUnit') : window.i18n('pruneSettingUnits')}

-
-
-
- ); -}; diff --git a/ts/components/settings/section/CategoryAppearance.tsx b/ts/components/settings/section/CategoryAppearance.tsx index d14b21d6d..31a3fffd0 100644 --- a/ts/components/settings/section/CategoryAppearance.tsx +++ b/ts/components/settings/section/CategoryAppearance.tsx @@ -4,6 +4,7 @@ import { useDispatch, useSelector } from 'react-redux'; // tslint:disable-next-line: no-submodule-imports import useUpdate from 'react-use/lib/useUpdate'; import { createOrUpdateItem, hasLinkPreviewPopupBeenDisplayed } from '../../../data/data'; +import { SettingsKey } from '../../../data/settings-key'; import { ToastUtils } from '../../../session/utils'; import { updateConfirmModal } from '../../../state/ducks/modalDialog'; import { toggleAudioAutoplay } from '../../../state/ducks/userConfig'; @@ -13,11 +14,10 @@ import { SessionButtonColor } from '../../basic/SessionButton'; import { SessionSettingButtonItem, SessionToggleWithDescription } from '../SessionSettingListItem'; import { ZoomingSessionSlider } from '../ZoomingSessionSlider'; -import { PruningSessionSlider } from '../PruningSessionSlider'; async function toggleLinkPreviews() { - const newValue = !window.getSettingValue('link-preview-setting'); - window.setSettingValue('link-preview-setting', newValue); + const newValue = !window.getSettingValue(SettingsKey.settingsLinkPreview); + window.setSettingValue(SettingsKey.settingsLinkPreview, newValue); if (!newValue) { await createOrUpdateItem({ id: hasLinkPreviewPopupBeenDisplayed, value: false }); } else { @@ -36,7 +36,7 @@ async function toggleStartInTray() { const newValue = !(await window.getStartInTray()); // make sure to write it here too, as this is the value used on the UI to mark the toggle as true/false - window.setSettingValue('start-in-tray-setting', newValue); + window.setSettingValue(SettingsKey.settingsStartInTray, newValue); await window.setStartInTray(newValue); if (!newValue) { ToastUtils.pushRestartNeeded(); @@ -46,11 +46,6 @@ async function toggleStartInTray() { } } -const settingsMenuBar = 'hide-menu-bar'; -const settingsSpellCheck = 'spell-check'; -const settingsLinkPreview = 'link-preview-setting'; -const settingsStartInTray = 'start-in-tray-setting'; - export const SettingsCategoryAppearance = (props: { hasPassword: boolean | null }) => { const dispatch = useDispatch(); const forceUpdate = useUpdate(); @@ -58,17 +53,17 @@ export const SettingsCategoryAppearance = (props: { hasPassword: boolean | null if (props.hasPassword !== null) { const isHideMenuBarActive = - window.getSettingValue(settingsMenuBar) === undefined + window.getSettingValue(SettingsKey.settingsMenuBar) === undefined ? true - : window.getSettingValue(settingsMenuBar); + : window.getSettingValue(SettingsKey.settingsMenuBar); const isSpellCheckActive = - window.getSettingValue(settingsSpellCheck) === undefined + window.getSettingValue(SettingsKey.settingsSpellCheck) === undefined ? true - : window.getSettingValue(settingsSpellCheck); + : window.getSettingValue(SettingsKey.settingsSpellCheck); - const isLinkPreviewsOn = Boolean(window.getSettingValue(settingsLinkPreview)); - const isStartInTrayActive = Boolean(window.getSettingValue(settingsStartInTray)); + const isLinkPreviewsOn = Boolean(window.getSettingValue(SettingsKey.settingsLinkPreview)); + const isStartInTrayActive = Boolean(window.getSettingValue(SettingsKey.settingsStartInTray)); return ( <> @@ -120,7 +115,7 @@ export const SettingsCategoryAppearance = (props: { hasPassword: boolean | null description={window.i18n('audioMessageAutoplayDescription')} active={audioAutoPlay} /> - + void; }) => { const forceUpdate = useUpdate(); const dispatch = useDispatch(); - + const isOpengroupPruningEnabled = Boolean( + window.getSettingValue(SettingsKey.settingsOpengroupPruning) + ); if (props.hasPassword !== null) { return ( <> @@ -117,6 +132,15 @@ export const SettingsCategoryPrivacy = (props: { description={window.i18n('hideRequestBannerDescription')} active={useSelector(getHideMessageRequestBanner)} /> + { + await toggleOpengroupPruning(); + forceUpdate(); + }} + title={window.i18n('pruneSettingTitle')} + description={window.i18n('pruneSettingDescription')} + active={isOpengroupPruningEnabled} + /> {!props.hasPassword && ( { sendResponse(localisedError || 'Invalid password'); } }); + ipc.on('start-in-tray-on-start', (event, newValue) => { try { userConfig.set('startInTray', newValue); @@ -967,6 +957,24 @@ ipc.on('get-start-in-tray', event => { } }); +ipc.on('get-opengroup-pruning', event => { + try { + const val = userConfig.get('opengroupPruning'); + event.sender.send('get-opengroup-pruning-response', val); + } catch (e) { + event.sender.send('get-opengroup-pruning-response', false); + } +}); + +ipc.on('set-opengroup-pruning', (event, newValue) => { + try { + userConfig.set('opengroupPruning', newValue); + event.sender.send('set-opengroup-pruning-response', null); + } catch (e) { + event.sender.send('set-opengroup-pruning-response', e); + } +}); + ipc.on('set-password', async (event, passPhrase, oldPhrase) => { const sendResponse = (response: string | undefined) => { event.sender.send('set-password-response', response); diff --git a/ts/node/sql.ts b/ts/node/sql.ts index a37c8805a..0a0edb60c 100644 --- a/ts/node/sql.ts +++ b/ts/node/sql.ts @@ -1550,6 +1550,8 @@ async function initializeSql({ console.info('total message count before cleaning: ', getMessageCount()); console.info('total conversation count before cleaning: ', getConversationCount()); + cleanUpOldOpengroups(); + cleanUpUnusedNodeForKeyEntries(); printDbStats(); @@ -3404,17 +3406,32 @@ function cleanUpMessagesJson() { console.info(`cleanUpMessagesJson took ${Date.now() - start}ms`); } -function cleanUpOldOpengroups(pruneSetting: number) { +function cleanUpOldOpengroups() { const ourNumber = getItemById('number_id'); if (!ourNumber || !ourNumber.value) { console.info('cleanUpOldOpengroups: ourNumber is not set'); return; } + const pruneSetting = getItemById('prune-setting')?.value; + + if (pruneSetting === undefined) { + console.info( + 'Prune settings is undefined, skipping cleanUpOldOpengroups but we will need to ask user' + ); + return; + } + + if (!pruneSetting) { + console.info('Prune setting not enabled, skipping cleanUpOldOpengroups'); + return; + } + const v2Convos = getAllOpenGroupV2Conversations(); if (!v2Convos || !v2Convos.length) { console.info('cleanUpOldOpengroups: v2Convos is empty'); return; } + // For each opengroups, if it has more than 1000 messages, we remove all the messages older than 2 months. // So this does not limit the size of opengroup history to 1000 messages but to 2 months. // This is the only way we can cleanup conversations objects from users which just sent messages a while ago and with whom we never interacted. @@ -3428,46 +3445,42 @@ function cleanUpOldOpengroups(pruneSetting: number) { db.transaction(() => { dropFtsAndTriggers(db); - if (pruneSetting !== 0) { - v2Convos.forEach(convo => { - const convoId = convo.id; - const messagesInConvoBefore = getMessagesCountByConversation(convoId); - - if (messagesInConvoBefore >= maxMessagePerOpengroupConvo) { - const minute = 1000 * 60; - const userDefinedMonths = minute * 60 * 24 * 30 * pruneSetting; - const messagesTimestampToRemove = Date.now() - userDefinedMonths; - const countToRemove = assertGlobalInstance() - .prepare( - `SELECT count(*) from ${MESSAGES_TABLE} WHERE serverTimestamp <= $serverTimestamp AND conversationId = $conversationId;` - ) - .get({ conversationId: convoId, serverTimestamp: Date.now() - userDefinedMonths })['count(*)']; - const start = Date.now(); - - assertGlobalInstance() - .prepare( - ` + v2Convos.forEach(convo => { + const convoId = convo.id; + const messagesInConvoBefore = getMessagesCountByConversation(convoId); + + if (messagesInConvoBefore >= maxMessagePerOpengroupConvo) { + const minute = 1000 * 60; + const sixMonths = minute * 60 * 24 * 30 * 6; + const limitTimestamp = Date.now() - sixMonths; + const countToRemove = assertGlobalInstance() + .prepare( + `SELECT count(*) from ${MESSAGES_TABLE} WHERE serverTimestamp <= $serverTimestamp AND conversationId = $conversationId;` + ) + .get({ conversationId: convoId, serverTimestamp: limitTimestamp })['count(*)']; + const start = Date.now(); + + assertGlobalInstance() + .prepare( + ` DELETE FROM ${MESSAGES_TABLE} WHERE serverTimestamp <= $serverTimestamp AND conversationId = $conversationId` - ) - .run({ conversationId: convoId, serverTimestamp: messagesTimestampToRemove }); // delete messages older than the user-specified age. - const messagesInConvoAfter = getMessagesCountByConversation(convoId); - - console.info( - `Cleaning ${countToRemove} messages older than ${pruneSetting} months in public convo: ${convoId} took ${Date.now() - - start}ms. Old message count: ${messagesInConvoBefore}, new message count: ${messagesInConvoAfter}` - ); - - const unreadCount = getUnreadCountByConversation(convoId); - const convoProps = getConversationById(convoId); - if (convoProps) { - convoProps.unreadCount = unreadCount; - updateConversation(convoProps); - } + ) + .run({ conversationId: convoId, serverTimestamp: limitTimestamp }); // delete messages older than 6 months ago. + const messagesInConvoAfter = getMessagesCountByConversation(convoId); + + console.info( + `Cleaning ${countToRemove} messages older than 6 months in public convo: ${convoId} took ${Date.now() - + start}ms. Old message count: ${messagesInConvoBefore}, new message count: ${messagesInConvoAfter}` + ); + + const unreadCount = getUnreadCountByConversation(convoId); + const convoProps = getConversationById(convoId); + if (convoProps) { + convoProps.unreadCount = unreadCount; + updateConversation(convoProps); } - }); - } else { - console.info('Skipping cleaning messages in public convos.'); - }; + } + }); // now, we might have a bunch of private conversation, without any interaction and no messages // those are the conversation of the old members in the opengroups we just cleaned. diff --git a/ts/types/LocalizerKeys.ts b/ts/types/LocalizerKeys.ts index ebbf75f96..46e26d227 100644 --- a/ts/types/LocalizerKeys.ts +++ b/ts/types/LocalizerKeys.ts @@ -7,6 +7,7 @@ export type LocalizerKeys = | 'startedACall' | 'mainMenuWindow' | 'unblocked' + | 'keepDisabled' | 'userAddedToModerators' | 'to' | 'sent' @@ -14,7 +15,9 @@ export type LocalizerKeys = | 'closedGroupInviteFailMessage' | 'noContactsForGroup' | 'linkVisitWarningMessage' + | 'messageRequestAcceptedOurs' | 'anonymous' + | 'youHaveANewFriendRequest' | 'viewMenuZoomOut' | 'dialogClearAllDataDeletionFailedDesc' | 'timerOption_10_seconds_abbreviated' @@ -22,9 +25,11 @@ export type LocalizerKeys = | 'connectToServerFail' | 'disableNotifications' | 'publicChatExists' + | 'noMediaUntilApproved' | 'passwordViewTitle' | 'joinOpenGroupAfterInvitationConfirmationTitle' | 'notificationMostRecentFrom' + | 'messageRequestAccepted' | 'timerOption_5_minutes' | 'linkPreviewsConfirmMessage' | 'notificationMostRecent' @@ -44,7 +49,6 @@ export type LocalizerKeys = | 'viewMenuToggleDevTools' | 'fileSizeWarning' | 'openGroupURL' - | 'hideRequestBannerDescription' | 'hideMenuBarDescription' | 'pickClosedGroupMember' | 'ByUsingThisService...' @@ -54,6 +58,7 @@ export type LocalizerKeys = | 'typingAlt' | 'orJoinOneOfThese' | 'members' + | 'noMessageRequestsPending' | 'sendRecoveryPhraseMessage' | 'timerOption_1_hour' | 'youGotKickedFromGroup' @@ -68,8 +73,10 @@ export type LocalizerKeys = | 'addModerators' | 'sessionMessenger' | 'today' + | 'mustBeApproved' | 'appMenuHideOthers' | 'sendFailed' + | 'openMessageRequestInbox' | 'enterPassword' | 'enterSessionIDOfRecipient' | 'dialogClearAllDataDeletionFailedMultiple' @@ -81,6 +88,7 @@ export type LocalizerKeys = | 'requestsSubtitle' | 'closedGroupInviteSuccessTitle' | 'accept' + | 'hideBanner' | 'setPasswordTitle' | 'editMenuUndo' | 'pinConversation' @@ -94,6 +102,7 @@ export type LocalizerKeys = | 'autoUpdateNewVersionInstructions' | 'appMenuUnhide' | 'timerOption_30_minutes_abbreviated' + | 'pruneSettingDescription' | 'voiceMessage' | 'changePasswordTitle' | 'copyMessage' @@ -101,12 +110,11 @@ export type LocalizerKeys = | 'deleteJustForMe' | 'changeAccountPasswordTitle' | 'onionPathIndicatorDescription' - | 'timestamp_s' + | 'pruningOpengroupDialogSubMessage' | 'mediaPermissionsTitle' | 'replyingToMessage' | 'welcomeToYourSession' | 'editMenuCopy' - | 'timestamp_m' | 'leftTheGroup' | 'timerOption_30_minutes' | 'nameOnly' @@ -116,6 +124,7 @@ export type LocalizerKeys = | 'inviteContacts' | 'callMediaPermissionsTitle' | 'blocked' + | 'hideRequestBannerDescription' | 'noBlockedContacts' | 'leaveGroupConfirmation' | 'banUserAndDeleteAll' @@ -162,10 +171,6 @@ export type LocalizerKeys = | 'copySessionID' | 'timerOption_0_seconds' | 'zoomFactorSettingTitle' - | 'pruneSettingTitle' - | 'pruneSettingDescription' - | 'pruneSettingUnit' - | 'pruneSettingUnits' | 'unableToCall' | 'callMissedTitle' | 'done' @@ -201,6 +206,7 @@ export type LocalizerKeys = | 'viewMenuResetZoom' | 'startInTrayDescription' | 'groupNamePlaceholder' + | 'messageRequestPending' | 'stagedPreviewThumbnail' | 'helpUsTranslateSession' | 'editMenuDeleteGroup' @@ -212,6 +218,7 @@ export type LocalizerKeys = | 'closedGroupInviteFailMessagePlural' | 'noAudioInputFound' | 'timerOption_10_seconds' + | 'openMessageRequestInboxDescription' | 'noteToSelf' | 'failedToAddAsModerator' | 'disabledDisappearingMessages' @@ -223,7 +230,6 @@ export type LocalizerKeys = | 'displayName' | 'invalidSessionId' | 'audioPermissionNeeded' - | 'timestamp_h' | 'add' | 'messageRequests' | 'show' @@ -232,6 +238,7 @@ export type LocalizerKeys = | 'goToSupportPage' | 'passwordsDoNotMatch' | 'createClosedGroupNamePrompt' + | 'pruningOpengroupDialogMessage' | 'audioMessageAutoplayDescription' | 'leaveAndRemoveForEveryone' | 'previewThumbnail' @@ -240,9 +247,9 @@ export type LocalizerKeys = | 'editMenuDeleteContact' | 'hideMenuBarTitle' | 'imageCaptionIconAlt' - | 'clearAll' | 'sendRecoveryPhraseTitle' | 'multipleJoinedTheGroup' + | 'messageRequestAcceptedOursNoName' | 'databaseError' | 'resend' | 'copiedToClipboard' @@ -252,6 +259,7 @@ export type LocalizerKeys = | 'unableToLoadAttachment' | 'cameraPermissionNeededTitle' | 'editMenuRedo' + | 'hideRequestBanner' | 'changeNicknameMessage' | 'close' | 'deleteMessageQuestion' @@ -262,6 +270,7 @@ export type LocalizerKeys = | 'getStarted' | 'unblockUser' | 'blockUser' + | 'clearAllConfirmationTitle' | 'trustThisContactDialogTitle' | 'received' | 'trimDatabaseConfirmationBody' @@ -280,6 +289,7 @@ export type LocalizerKeys = | 'timerOption_6_hours_abbreviated' | 'timerOption_1_week_abbreviated' | 'timerSetTo' + | 'enable' | 'notificationSubtitle' | 'youChangedTheTimer' | 'updatedTheGroup' @@ -292,8 +302,10 @@ export type LocalizerKeys = | 'noSearchResults' | 'changeNickname' | 'userUnbanned' + | 'respondingToRequestWarning' | 'error' | 'clearAllData' + | 'pruningOpengroupDialogTitle' | 'contactAvatarAlt' | 'disappearingMessages' | 'autoUpdateNewVersionTitle' @@ -332,6 +344,7 @@ export type LocalizerKeys = | 'markAllAsRead' | 'failedResolveOns' | 'showDebugLog' + | 'declineRequestMessage' | 'autoUpdateDownloadButtonLabel' | 'dialogClearAllDataDeletionFailedTitleQuestion' | 'autoUpdateDownloadInstructions' @@ -357,6 +370,7 @@ export type LocalizerKeys = | 'learnMore' | 'passwordCharacterError' | 'autoUpdateSettingTitle' + | 'documentsEmptyState' | 'deleteForEveryone' | 'createSessionID' | 'multipleLeftTheGroup' @@ -380,9 +394,11 @@ export type LocalizerKeys = | 'callMediaPermissionsDialogContent' | 'timerOption_1_day_abbreviated' | 'about' + | 'clearAllConfirmationBody' | 'ok' | 'multipleKickedFromTheGroup' | 'trimDatabase' + | 'clearAll' | 'recoveryPhraseSavePromptMain' | 'editMenuPaste' | 'areYouSureDeleteDeviceOnly' @@ -425,7 +441,7 @@ export type LocalizerKeys = | 'recoveryPhrase' | 'newMessages' | 'you' - | 'documentsEmptyState' + | 'pruneSettingTitle' | 'unbanUser' | 'notificationForConvo_mentions_only' | 'trustThisContactDialogDescription' @@ -433,22 +449,4 @@ export type LocalizerKeys = | 'searchFor...' | 'joinedTheGroup' | 'editGroupName' - | 'trimDatabase' - | 'trimDatabaseDescription' - | 'trimDatabaseConfirmationBody' - | 'respondingToRequestWarning' - | 'messageRequestPending' - | 'messageRequestAccepted' - | 'messageRequestAcceptedOurs' - | 'messageRequestAcceptedOursNoName' - | 'declineRequestMessage' - | 'openMessageRequestInbox' - | 'hideRequestBanner' - | 'noMessageRequestsPending' - | 'noMediaUntilApproved' - | 'mustBeApproved' - | 'youHaveANewFriendRequest' - | 'clearAllConfirmationTitle' - | 'clearAllConfirmationBody' - | 'hideBanner' | 'reportIssue'; diff --git a/ts/util/accountManager.ts b/ts/util/accountManager.ts index c662b86cb..a24d74732 100644 --- a/ts/util/accountManager.ts +++ b/ts/util/accountManager.ts @@ -164,6 +164,10 @@ async function createAccount(identityKeyPair: any) { // Enable typing indicators by default await Storage.put(SettingsKey.settingsTypingIndicator, false); + // opengroups pruning in ON by default on new accounts, but you can change that from the settings + await Storage.put(SettingsKey.settingsOpengroupPruning, true); + await window.setOpengroupPruning(true); + await setLocalPubKey(pubKeyString); } diff --git a/ts/window.d.ts b/ts/window.d.ts index df99dc20e..a9a8e82b0 100644 --- a/ts/window.d.ts +++ b/ts/window.d.ts @@ -91,6 +91,8 @@ declare global { confirmationDialog: any; setStartInTray: (val: boolean) => Promise; getStartInTray: () => Promise; + getOpengroupPruning: () => Promise; + setOpengroupPruning: (val: boolean) => Promise; closeAbout: () => void; getAutoUpdateEnabled: () => boolean; setAutoUpdateEnabled: (enabled: boolean) => void; From 55869fbe37de80a5d9fc13b9c0aa1b67551aa93a Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Wed, 18 May 2022 11:58:11 +1000 Subject: [PATCH 3/3] fix: swap confirm and cancel buttons in the confirmDialog --- ts/components/dialog/SessionConfirm.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ts/components/dialog/SessionConfirm.tsx b/ts/components/dialog/SessionConfirm.tsx index b0b9534d0..805d1e042 100644 --- a/ts/components/dialog/SessionConfirm.tsx +++ b/ts/components/dialog/SessionConfirm.tsx @@ -127,6 +127,12 @@ export const SessionConfirm = (props: SessionConfirmDialogProps) => {
+ {!hideCancel && ( { dataTestId="session-confirm-cancel-button" /> )} -
);