diff --git a/frontend/controller/actions/chatroom.js b/frontend/controller/actions/chatroom.js index f24c447dd..e105201df 100644 --- a/frontend/controller/actions/chatroom.js +++ b/frontend/controller/actions/chatroom.js @@ -242,6 +242,44 @@ export default (sbp('sbp/selectors/register', { } })) }, + 'gi.actions/chatroom/_ondeleted': async (contractID: string, state: Object) => { + const rootGetters = sbp('state/vuex/getters') + const identityState = rootGetters.currentIdentityState + if (identityState.chatRooms?.[contractID]) { + // TODO + // Currently missing the ability to leave a DM + } else { + // This is a group chatroom. To determine which group the chatroom + // belongs to, we need to go over each group, since there isn't a + // chatroom->group relationship stored. + const cIDs = Object.entries(identityState.groups || {}).filter(([cID, state]) => { + return !state.hasLeft + }).map(([cID]) => { + return cID + }) + + for (const cID of cIDs) { + const groupState = await sbp('chelonia/contract/state', cID).catch(() => {}) + // If the chatroom isn't part of this group, continue + if (!groupState?.chatRooms?.[contractID]) continue + + if (!groupState.chatRooms[contractID].deletedDate) { + // If the chatroom hasn't been 'deleted' in the group, attempt to do + // so now. + await sbp('gi.actions/group/deleteChatRoom', { + contractID: cID, + data: { chatRoomID: contractID } + }).catch(e => { + console.warn(`[handleDeletedContract] ${e.name} thrown by gi.actions/group/deleteChatRoom ${cID} for ${contractID}:`, e) + }) + } + + // No need to continue in the loop, as chatrooms belong to a single + // group + break + } + } + }, ...encryptedNotification('gi.actions/chatroom/user-typing-event', L('Failed to send typing notification')), ...encryptedNotification('gi.actions/chatroom/user-stop-typing-event', L('Failed to send stopped typing notification')), ...encryptedAction('gi.actions/chatroom/addMessage', L('Failed to add message.')), diff --git a/frontend/controller/actions/group.js b/frontend/controller/actions/group.js index 3e56857e5..4f2cbd57e 100644 --- a/frontend/controller/actions/group.js +++ b/frontend/controller/actions/group.js @@ -1163,6 +1163,23 @@ export default (sbp('sbp/selectors/register', { const response = await sendMessage(params) return response }), + 'gi.actions/group/_ondeleted': async (contractID: string, state: Object) => { + const rootGetters = sbp('state/vuex/getters') + const identityContractID = rootGetters.ourIdentityContractId + const currentIdentityState = rootGetters.currentIdentityState + + if (!!currentIdentityState.groups[contractID] && !currentIdentityState.groups[contractID]?.hasLeft) { + await sbp('gi.actions/identity/leaveGroup', { + contractID: identityContractID, + data: { + groupContractID: contractID, + reference: state.profiles?.[identityContractID]?.reference + } + }).catch(e => { + console.warn(`[handleDeletedContract] ${e.name} thrown by gi.actions/identity/leaveGroup ${identityContractID} for ${contractID}:`, e) + }) + } + }, ...encryptedAction('gi.actions/group/updateSettings', L('Failed to update group settings.')), ...encryptedAction('gi.actions/group/updateAllVotingRules', (params, e) => L('Failed to update voting rules. {codeError}', { codeError: e.message })), ...encryptedAction('gi.actions/group/updateDistributionDate', L('Failed to update group distribution date.')), diff --git a/frontend/controller/actions/identity.js b/frontend/controller/actions/identity.js index cd9b975a5..88c5d3c82 100644 --- a/frontend/controller/actions/identity.js +++ b/frontend/controller/actions/identity.js @@ -1012,6 +1012,13 @@ export default (sbp('sbp/selectors/register', { [contractID]: { token: new Secret(token.valueOf()) } }) }, + 'gi.actions/identity/_ondeleted': async (contractID: string, state: Object) => { + const ourIdentityContractId = sbp('state/vuex/getters').ourIdentityContractId + + if (contractID === ourIdentityContractId) { + await sbp('gi.actions/identity/logout') + } + }, ...encryptedAction('gi.actions/identity/saveFileDeleteToken', L('Failed to save delete tokens for the attachments.')), ...encryptedAction('gi.actions/identity/removeFileDeleteToken', L('Failed to remove delete tokens for the attachments.')), ...encryptedAction('gi.actions/identity/setGroupAttributes', L('Failed to set group attributes.')) diff --git a/frontend/setupChelonia.js b/frontend/setupChelonia.js index acde7a493..49f5dc19e 100644 --- a/frontend/setupChelonia.js +++ b/frontend/setupChelonia.js @@ -18,76 +18,14 @@ const handleDeletedContract = async (contractID: string) => { await sbp('chelonia/contract/remove', contractID) - const rootGetters = sbp('state/vuex/getters') - - switch (cheloniaState.type) { - case 'gi.contracts/chatroom': { - const identityState = rootGetters.currentIdentityState - if (identityState.chatRooms?.[contractID]) { - // TODO - // Currently missing the ability to leave a DM - } else { - // This is a group chatroom. To determine which group the chatroom - // belongs to, we need to go over each group, since there isn't a - // chatroom->group relationship stored. - const cIDs = Object.entries(identityState.groups || {}).filter(([cID, state]) => { - return !state.hasLeft - }).map(([cID]) => { - return cID - }) - - for (const cID of cIDs) { - const groupState = await sbp('chelonia/contract/state', cID).catch(() => {}) - // If the chatroom isn't part of this group, continue - if (!groupState?.chatRooms?.[contractID]) continue - - if (!groupState.chatRooms[contractID].deletedDate) { - // If the chatroom hasn't been 'deleted' in the group, attempt to do - // so now. - await sbp('gi.actions/group/deleteChatRoom', { - contractID: cID, - data: { chatRoomID: contractID } - }).catch(e => { - console.warn(`[handleDeletedContract] ${e.name} thrown by gi.actions/group/deleteChatRoom ${cID} for ${contractID}:`, e) - }) - } - - // No need to continue in the loop, as chatrooms belong to a single - // group - break - } - } - break - } - case 'gi.contracts/group': { - const identityContractID = rootGetters.ourIdentityContractId - const currentIdentityState = rootGetters.currentIdentityState - - if (!!currentIdentityState.groups[contractID] && !currentIdentityState.groups[contractID]?.hasLeft) { - await sbp('gi.actions/identity/leaveGroup', { - contractID: identityContractID, - data: { - groupContractID: contractID, - reference: contractState.profiles?.[identityContractID]?.reference - } - }).catch(e => { - console.warn(`[handleDeletedContract] ${e.name} thrown by gi.actions/identity/leaveGroup ${identityContractID} for ${contractID}:`, e) - }) - } - - break - } - case 'gi.contracts/identity': { - const ourIdentityContractId = sbp('state/vuex/getters').ourIdentityContractId - - if (contractID === ourIdentityContractId) { - await sbp('gi.actions/identity/logout') - } - - break - } - default: - console.warn('[handleDeletedContract] Received contract deletion notification for contract ID of unknown type', contractID, cheloniaState.type) + const type = cheloniaState.type?.replace(/^gi\.contracts\//, 'gi.actions') + const handler = type && sbp('sbp/selectors/fn', `${type}/_ondeleted`) + if (typeof handler === 'function') { + await handler(contractID, contractState).catch(e => { + console.error('Error handling deletion of contract', contractID) + }) + } else { + console.warn('[handleDeletedContract] Received contract deletion notification for contract without a declared deletion handler', contractID, cheloniaState.type) } }