Skip to content

Commit

Permalink
Move preSendChecks to actions. Fix: group-chat fails
Browse files Browse the repository at this point in the history
  • Loading branch information
corrideat committed Dec 18, 2023
1 parent 77a10a2 commit 4e2546e
Show file tree
Hide file tree
Showing 9 changed files with 200 additions and 80 deletions.
46 changes: 44 additions & 2 deletions frontend/controller/actions/chatroom.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,10 @@ export default (sbp('sbp/selectors/register', {
hooks: {
...params?.hooks,
preSendCheck (msg, state) {
if (state?.users?.[params.data.username]) return false
console.error('cJ', params.contractID, params.data.username, state.users?.[params.data.username])
// Avoid sending a duplicate action if the person is already a
// chatroom member
if (state.users?.[params.data.username]) return false
if (params?.hooks?.preSendCheck) {
return params?.hooks?.preSendCheck(msg, state)
}
Expand All @@ -252,7 +255,46 @@ export default (sbp('sbp/selectors/register', {
}),
...encryptedAction('gi.actions/chatroom/rename', L('Failed to rename chat channel.')),
...encryptedAction('gi.actions/chatroom/changeDescription', L('Failed to change chat channel description.')),
...encryptedAction('gi.actions/chatroom/leave', L('Failed to leave chat channel.')),
...encryptedAction('gi.actions/chatroom/leave', L('Failed to leave chat channel.'), async (sendMessage, params, signingKeyId) => {
const hooks = {
...params?.hooks,
preSendCheck (msg, state) {
console.error('cL', params.contractID, params.data.member, state.users?.[params.data.member])
// Avoid sending a duplicate action if the person isn't a
// chatroom member
if (!state.users?.[params.data.member]) return false
if (params?.hooks?.preSendCheck) {
return params?.hooks?.preSendCheck(msg, state)
}
return true
}
}

const rootGetters = sbp('state/vuex/getters')
const userID = rootGetters.ourContactProfiles[params.data.member]?.contractID

const keyIds = userID && sbp('chelonia/contract/foreignKeysByContractID', params.contractID, userID)

if (keyIds?.length) {
return await sbp('chelonia/out/atomic', {
...params,
contractName: 'gi.contracts/chatroom',
data: [
sendMessage({ ...params, returnInvocation: true }),
// Remove the user's CSK from the contract
[
'chelonia/out/keyDel', {
data: keyIds
}
]
],
signingKeyId,
hooks
})
}

return await sendMessage({ ...params, hooks })
}),
...encryptedAction('gi.actions/chatroom/delete', L('Failed to delete chat channel.')),
...encryptedAction('gi.actions/chatroom/voteOnPoll', L('Failed to vote on a poll.')),
...encryptedAction('gi.actions/chatroom/changeVoteOnPoll', L('Failed to change vote on a poll.')),
Expand Down
88 changes: 74 additions & 14 deletions frontend/controller/actions/group.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,11 +252,6 @@ export default (sbp('sbp/selectors/register', {
groupContractID: contractID,
inviteSecret: serializeKey(CSK, true),
creator: true
},
hooks: {
preSendCheck: (_, state) => {
return !state.groups?.[contractID]
}
}
})

Expand Down Expand Up @@ -433,10 +428,7 @@ export default (sbp('sbp/selectors/register', {
...omit(params, ['options', 'action', 'hooks', 'encryptionKeyId', 'signingKeyId']),
hooks: {
prepublish: params.hooks?.prepublish,
postpublish: null,
preSendCheck: (_, state) => {
return state?.profiles?.[username]?.status !== PROFILE_STATUS.ACTIVE
}
postpublish: null
}
})

Expand Down Expand Up @@ -625,7 +617,21 @@ export default (sbp('sbp/selectors/register', {
})
}

return await sendMessage(omit(params, ['options', 'action']))
return await sendMessage({
...omit(params, ['options', 'action']),
hooks: {
...params.hooks,
preSendCheck (msg, state) {
console.error('gJC', params.data.chatRoomID, username, state.chatRooms[params.data.chatRoomID]?.users?.[username]?.status)
// Don't send if the member has already been added
if (state.chatRooms[params.data.chatRoomID]?.users?.[username]?.status === PROFILE_STATUS.ACTIVE) return false
if (params?.hooks?.preSendCheck) {
return params?.hooks?.preSendCheck(msg, state)
}
return true
}
}
})
}),
'gi.actions/group/addAndJoinChatRoom': async function (params: GIActionParams) {
const message = await sbp('gi.actions/group/addChatRoom', {
Expand Down Expand Up @@ -678,14 +684,37 @@ export default (sbp('sbp/selectors/register', {
(params, e) => L('Failed to remove {member}: {reportError}', { member: params.data.member, ...LError(e) }),
async function (sendMessage, params, signingKeyId) {
await sendMessage({
...omit(params, ['options', 'action'])
...omit(params, ['options', 'action']),
hooks: {
...params.hooks,
preSendCheck (msg, state) {
// Don't send if the member has already been removed
if (state?.profiles?.[params.data.member]?.status !== PROFILE_STATUS.ACTIVE) return false
if (params?.hooks?.preSendCheck) {
return params?.hooks?.preSendCheck(msg, state)
}
return true
}
}
})
}),
...encryptedAction('gi.actions/group/removeOurselves',
(e) => L('Failed to leave group. {codeError}', { codeError: e.message }),
async function (sendMessage, params) {
const rootState = sbp('state/vuex/state')
await sendMessage({
...omit(params, ['options', 'action'])
...omit(params, ['options', 'action']),
hooks: {
...params.hooks,
preSendCheck (msg, state) {
// Don't send if we've already been removed
if (state?.profiles?.[rootState.loggedIn.username]?.status !== PROFILE_STATUS.ACTIVE) return false
if (params?.hooks?.preSendCheck) {
return params?.hooks?.preSendCheck(msg, state)
}
return true
}
}
})
}),
...encryptedAction('gi.actions/group/changeChatRoomDescription',
Expand Down Expand Up @@ -877,10 +906,41 @@ export default (sbp('sbp/selectors/register', {
sbp('okTurtles.events/emit', OPEN_MODAL, 'AddMembers')
}
},
...encryptedAction('gi.actions/group/leaveChatRoom', L('Failed to leave chat channel.')),
...encryptedAction('gi.actions/group/leaveChatRoom', L('Failed to leave chat channel.'), async (sendMessage, params) => {
return await sendMessage({
...params,
hooks: {
...params.hooks,
preSendCheck (msg, state) {
// Don't send if the member isn't an active chatroom member
console.error('gLC', params.data.chatRoomID, params.data.member, state.chatRooms[params.data.chatRoomID]?.users?.[params.data.member]?.status)
if (state.chatRooms[params.data.chatRoomID]?.users?.[params.data.member]?.status !== PROFILE_STATUS.ACTIVE) return false
if (params?.hooks?.preSendCheck) {
return params?.hooks?.preSendCheck(msg, state)
}
return true
}
}
})
}),
...encryptedAction('gi.actions/group/deleteChatRoom', L('Failed to delete chat channel.')),
...encryptedAction('gi.actions/group/invite', L('Failed to create invite.')),
...encryptedAction('gi.actions/group/inviteAccept', L('Failed to accept invite.')),
...encryptedAction('gi.actions/group/inviteAccept', L('Failed to accept invite.'), async function (sendMessage, params) {
const rootState = sbp('state/vuex/state')
await sendMessage({
...omit(params, ['options', 'action']),
hooks: {
...params.hooks,
preSendCheck (msg, state) {
if (state?.profiles?.[rootState.loggedIn.username]?.status === PROFILE_STATUS.ACTIVE) return false
if (params?.hooks?.preSendCheck) {
return params?.hooks?.preSendCheck(msg, state)
}
return true
}
}
})
}),
...encryptedAction('gi.actions/group/inviteRevoke', L('Failed to revoke invite.'), async function (sendMessage, params, signingKeyId) {
await sbp('chelonia/out/keyDel', {
contractID: params.contractID,
Expand Down
48 changes: 45 additions & 3 deletions frontend/controller/actions/identity.js
Original file line number Diff line number Diff line change
Expand Up @@ -614,8 +614,50 @@ export default (sbp('sbp/selectors/register', {
})
}
}),
...encryptedAction('gi.actions/identity/joinDirectMessage', L('Failed to join a direct message.')),
...encryptedAction('gi.actions/identity/joinGroup', L('Failed to join a group.')),
...encryptedAction('gi.actions/identity/leaveGroup', L('Failed to leave a group.')),
...encryptedAction('gi.actions/identity/joinDirectMessage', L('Failed to join a direct message.'), async (sendMessage, params) => {
return await sendMessage({
...params,
hooks: {
...params.hooks,
preSendCheck (msg, state) {
if (has(state.chatRooms, params.data.contractID)) return false
if (params?.hooks?.preSendCheck) {
return params?.hooks?.preSendCheck(msg, state)
}
return true
}
}
})
}),
...encryptedAction('gi.actions/identity/joinGroup', L('Failed to join a group.'), async (sendMessage, params) => {
return await sendMessage({
...params,
hooks: {
...params.hooks,
preSendCheck (msg, state) {
if (has(state.groups, params.data.groupContractID)) return false
if (params?.hooks?.preSendCheck) {
return params?.hooks?.preSendCheck(msg, state)
}
return true
}
}
})
}),
...encryptedAction('gi.actions/identity/leaveGroup', L('Failed to leave a group.'), async (sendMessage, params) => {
return await sendMessage({
...params,
hooks: {
...params.hooks,
preSendCheck (msg, state) {
if (!has(state.groups, params.data.groupContractID)) return false
if (params?.hooks?.preSendCheck) {
return params?.hooks?.preSendCheck(msg, state)
}
return true
}
}
})
}),
...encryptedAction('gi.actions/identity/setDirectMessageVisibility', L('Failed to set direct message visibility.'))
}): string[])
2 changes: 1 addition & 1 deletion frontend/model/contracts/chatroom.js
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,7 @@ sbp('chelonia/defineContract', {
hooks: {
preSendCheck: (_, state) => {
// Only issue OP_KEY_DEL for non-members
return state && !state?.users?.[member]
return !state.users?.[member]
}
}
}).catch(e => {
Expand Down
68 changes: 24 additions & 44 deletions frontend/model/contracts/group.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
} from './shared/constants.js'
import { paymentStatusType, paymentType, PAYMENT_COMPLETED } from './shared/payments/index.js'
import { createPaymentInfo, paymentHashesFromPaymentPeriod } from './shared/functions.js'
import { cloneDeep, deepEqualJSONType, has, omit, merge } from './shared/giLodash.js'
import { cloneDeep, deepEqualJSONType, omit, merge } from './shared/giLodash.js'
import { addTimeToDate, dateToPeriodStamp, compareISOTimestamps, dateFromPeriodStamp, isPeriodStamp, comparePeriodStamps, dateIsWithinPeriod, DAYS_MILLIS, periodStampsForDate, plusOnePeriodLength } from './shared/time.js'
import { unadjustedDistribution, adjustedDistribution } from './shared/distribution/distribution.js'
import currencies from './shared/currencies.js'
Expand Down Expand Up @@ -336,14 +336,7 @@ const leaveChatRoomAction = (state, { chatRoomID, member }, meta, leavingGroup)
return sbp('gi.actions/chatroom/leave', {
contractID: chatRoomID,
data: sendingData,
...extraParams,
hooks: {
preSendCheck: (_, state) => {
// Avoid sending a duplicate action if the person has already
// left or been removed from the chatroom
return state && !!state.users?.[member]
}
}
...extraParams
}).catch((e) => {
if (
leavingGroup &&
Expand Down Expand Up @@ -1113,9 +1106,6 @@ sbp('chelonia/defineContract', {
chatRoomID: generalChatRoomId
},
hooks: {
preSendCheck: (_, state) => {
return state.chatRooms[generalChatRoomId]?.users?.[loggedIn.username]?.status !== PROFILE_STATUS.ACTIVE
},
onprocessed: () => {
sbp('state/vuex/commit', 'setCurrentChatRoomId', {
groupId: contractID,
Expand Down Expand Up @@ -1585,11 +1575,6 @@ sbp('chelonia/defineContract', {
contractID: identityContractID,
data: {
groupContractID: contractID
},
hooks: {
preSendCheck: (_, state) => {
return state && has(state.groups, contractID)
}
}
}).catch(e => {
console.error(`[gi.contracts/group/_cleanup] ${e.name} thrown by gi.contracts/identity/leaveGroup ${identityContractID} for ${contractID}:`, e)
Expand Down Expand Up @@ -1772,36 +1757,31 @@ sbp('chelonia/defineContract', {
return
}

if (username === member) {
await sbp('chelonia/contract/sync', chatRoomId)
}
try {
await sbp('chelonia/contract/sync', chatRoomId, { deferredRemove: true })

if (!sbp('chelonia/contract/hasKeysToPerformOperation', chatRoomId, 'gi.contracts/chatroom/join')) {
return
}

// Using the group's CEK allows for everyone to have an overview of the
// membership (which is also part of the group contract). This way,
// non-members can remove members when they leave the group
const encryptionKeyId = sbp('chelonia/contract/currentKeyIdByName', state, 'cek', true)

await sbp('gi.actions/chatroom/join', {
contractID: chatRoomId,
data: { username: member },
encryptionKeyId,
hooks: {
preSendCheck: (_, state) => {
// Avoid sending a duplicate action if the person is already a
// chatroom member
return !state?.users?.[member]
}
if (!sbp('chelonia/contract/hasKeysToPerformOperation', chatRoomId, 'gi.contracts/chatroom/join')) {
return
}
}).catch(e => {
console.error(`Unable to join ${member} to chatroom ${chatRoomId} for group ${contractID}`, e)
})

if (username === member) {
sbp('state/vuex/commit', 'setCurrentChatRoomId', { groupId: contractID, chatRoomId })
// Using the group's CEK allows for everyone to have an overview of the
// membership (which is also part of the group contract). This way,
// non-members can remove members when they leave the group
const encryptionKeyId = sbp('chelonia/contract/currentKeyIdByName', state, 'cek', true)

await sbp('gi.actions/chatroom/join', {
contractID: chatRoomId,
data: { username: member },
encryptionKeyId
}).catch(e => {
console.error(`Unable to join ${member} to chatroom ${chatRoomId} for group ${contractID}`, e)
})

if (username === member) {
sbp('state/vuex/commit', 'setCurrentChatRoomId', { groupId: contractID, chatRoomId })
}
} finally {
await sbp('chelonia/contract/remove', chatRoomId, { removeIfPending: true })
}
},
// eslint-disable-next-line require-await
Expand Down
9 changes: 2 additions & 7 deletions frontend/model/contracts/identity.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
noUppercase
} from './shared/validators.js'

import { IDENTITY_USERNAME_MAX_CHARS, PROFILE_STATUS } from './shared/constants.js'
import { IDENTITY_USERNAME_MAX_CHARS } from './shared/constants.js'

sbp('chelonia/defineContract', {
name: 'gi.contracts/identity',
Expand Down Expand Up @@ -230,12 +230,7 @@ sbp('chelonia/defineContract', {
if (has(rootState.contracts, groupContractID)) {
await sbp('gi.actions/group/removeOurselves', {
contractID: groupContractID,
data: {},
hooks: {
preSendCheck: (_, state) => {
return state?.profiles?.[rootState.loggedIn.username]?.status === PROFILE_STATUS.ACTIVE
}
}
data: {}
})
}

Expand Down
6 changes: 3 additions & 3 deletions frontend/model/contracts/manifests.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifests": {
"gi.contracts/chatroom": "21XWnNGPkCzrD1Az5vCnZSA8Hmms2B5dTt4gay8JF6cX73XV9E",
"gi.contracts/group": "21XWnNXvgCtnnkEgSnf2WAop9NpjpAR1AYJtxaid5JL5iptsaE",
"gi.contracts/identity": "21XWnNPXURFavPWwF5yKXUiFfKakgrAPZ2GadGEBSERgZMq9aN"
"gi.contracts/chatroom": "21XWnNHH2e67b1HMpFupf1EmSWH6ATaEN8yDL73d7nHKyduJru",
"gi.contracts/group": "21XWnNU6B4j7vVX2pYDtDmCTb6U7S3C9q4ijfZkberWfn7dMcT",
"gi.contracts/identity": "21XWnNK49ogfNcAQfanvYPyEbGHRyekriVhAegxAvnWgZyLL8b"
}
}
Loading

0 comments on commit 4e2546e

Please sign in to comment.