Skip to content

Commit

Permalink
fix(capabilities): fetch remote capabilities for unknown server
Browse files Browse the repository at this point in the history
Signed-off-by: Maksim Sukharev <antreesy.web@gmail.com>
  • Loading branch information
Antreesy committed Feb 10, 2025
1 parent 1fff52a commit 660aeec
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 2 deletions.
27 changes: 26 additions & 1 deletion src/services/CapabilitiesManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { getCapabilities as _getCapabilities } from '@nextcloud/capabilities'
import { getRemoteCapabilities } from './federationService.ts'
import BrowserStorage from '../services/BrowserStorage.js'
import { useTalkHashStore } from '../stores/talkHash.js'
import type { Capabilities, Conversation, JoinRoomFullResponse } from '../types/index.ts'
import type { acceptShareResponse, Capabilities, Conversation, JoinRoomFullResponse } from '../types/index.ts'

type Config = Capabilities['spreed']['config']
type RemoteCapability = Capabilities & { hash?: string }
Expand Down Expand Up @@ -149,6 +149,31 @@ export async function setRemoteCapabilities(joinRoomResponse: JoinRoomFullRespon
}
}

/**
* Fetch new capabilities if remote server is not yet known
* @param acceptShareResponse server response
*/
export async function setRemoteCapabilitiesIfEmpty(acceptShareResponse: Awaited<acceptShareResponse>): Promise<void> {
const token = acceptShareResponse.data.ocs.data.token
const remoteServer = acceptShareResponse.data.ocs.data.remoteServer!

// Check if remote capabilities already exists
if (remoteCapabilities[remoteServer]) {
return
}

const response = await getRemoteCapabilities(token)
const newRemoteCapabilities = response.data.ocs.data as Capabilities['spreed']
if (!Object.keys(newRemoteCapabilities).length) {
// data: {} received from server, nothing to update with
return
}

remoteCapabilities[remoteServer] = { spreed: newRemoteCapabilities }
BrowserStorage.setItem('remoteCapabilities', JSON.stringify(remoteCapabilities))
patchTokenMap(acceptShareResponse.data.ocs.data)
}

/**
* Deep comparison of remote capabilities, whether there are actual changes that require reload
* @param newObject new remote capabilities
Expand Down
36 changes: 36 additions & 0 deletions src/services/__tests__/CapabilitiesManager.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
hasTalkFeature,
getTalkConfig,
setRemoteCapabilities,
setRemoteCapabilitiesIfEmpty,
} from '../CapabilitiesManager.ts'
import { getRemoteCapabilities } from '../federationService.ts'

Expand Down Expand Up @@ -209,4 +210,39 @@ describe('CapabilitiesManager', () => {
expect(BrowserStorage.setItem).toHaveBeenCalledTimes(2)
})
})

describe('setRemoteCapabilitiesIfEmpty', () => {
const token = 'TOKEN8FED4'
const remoteServer = 'https://nextcloud4.local'

it('should early return if already has capabilities', async () => {
const [remoteServer, remoteCapabilities] = Object.entries(mockedRemotes)[0]
const token = remoteCapabilities.tokens[0]
const acceptShareResponseMock = generateOCSResponse({
payload: { token, remoteServer },
})
await setRemoteCapabilitiesIfEmpty(acceptShareResponseMock)
expect(BrowserStorage.setItem).toHaveBeenCalledTimes(0)
})

it('should early return if no capabilities received from server', async () => {
const acceptShareResponseMock = generateOCSResponse({
payload: { token, remoteServer },
})
const responseMock = generateOCSResponse({ payload: {} })
getRemoteCapabilities.mockReturnValue(responseMock)
await setRemoteCapabilitiesIfEmpty(acceptShareResponseMock)
expect(BrowserStorage.setItem).toHaveBeenCalledTimes(0)
})

it('should set capabilities for new server', async () => {
const acceptShareResponseMock = generateOCSResponse({
payload: { token, remoteServer },
})
const responseMock = generateOCSResponse({ payload: mockedCapabilities.spreed })
getRemoteCapabilities.mockReturnValue(responseMock)
await setRemoteCapabilitiesIfEmpty(acceptShareResponseMock)
expect(BrowserStorage.setItem).toHaveBeenCalledTimes(1)
})
})
})
7 changes: 6 additions & 1 deletion src/stores/__tests__/federation.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@
*/
import { setActivePinia, createPinia } from 'pinia'

import { getShares, acceptShare, rejectShare } from '../../services/federationService.ts'
import { mockedCapabilities } from '../../__mocks__/capabilities.ts'
import { getShares, acceptShare, rejectShare, getRemoteCapabilities } from '../../services/federationService.ts'
import { generateOCSErrorResponse, generateOCSResponse } from '../../test-helpers.js'
import { useFederationStore } from '../federation.ts'

jest.mock('../../services/federationService', () => ({
getShares: jest.fn(),
acceptShare: jest.fn(),
rejectShare: jest.fn(),
getRemoteCapabilities: jest.fn(),
}))

describe('federationStore', () => {
Expand Down Expand Up @@ -187,6 +189,9 @@ describe('federationStore', () => {
const acceptResponse = generateOCSResponse({ payload: room })
acceptShare.mockResolvedValueOnce(acceptResponse)

const responseMock = generateOCSResponse({ payload: mockedCapabilities.spreed })
getRemoteCapabilities.mockReturnValue(responseMock)

// Act: accept invite
const conversation = await federationStore.acceptShare(invites[0].id)

Expand Down
3 changes: 3 additions & 0 deletions src/stores/federation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { t } from '@nextcloud/l10n'
import { getBaseUrl } from '@nextcloud/router'

import { FEDERATION } from '../constants.ts'
import { setRemoteCapabilitiesIfEmpty } from '../services/CapabilitiesManager.ts'
import { getShares, acceptShare, rejectShare } from '../services/federationService.ts'
import type { Conversation, FederationInvite, NotificationInvite } from '../types/index.ts'

Expand Down Expand Up @@ -109,6 +110,8 @@ export const useFederationStore = defineStore('federation', {
try {
Vue.set(this.pendingShares[id], 'loading', 'accept')
const response = await acceptShare(id)
// Fetch remote capabilities for unknown federation server
await setRemoteCapabilitiesIfEmpty(response)
this.markInvitationAccepted(id, response.data.ocs.data)
this.updatePendingSharesCount(Object.keys(this.pendingShares).length)
return response.data.ocs.data
Expand Down

0 comments on commit 660aeec

Please sign in to comment.