fix: offer a plugin the invitation and settings calls only once it was granted their permission

This commit is contained in:
Linus Rath
2026-11-03 00:55:50 +01:00
parent 8034b005b8
commit 989cfc64a4
2 changed files with 42 additions and 4 deletions
@@ -0,0 +1,32 @@
import { describe, expect, it, vi } from 'vitest';
import type { InstalledPlugin } from '../plugin-types';
vi.mock('@/stores/toast-store', () => ({
toast: { success: vi.fn(), error: vi.fn(), info: vi.fn(), warning: vi.fn() },
}));
const { snapshotHostFeatures } = await import('../plugin-sandbox/host-features');
// A plugin sees answerInvitation and changeSettings only once it was granted
// the optional permission behind them: one enabled before the update that
// added them doesn't have it until the user turns it off and on.
function plugin(granted: string[]): InstalledPlugin {
return {
id: 'ai-assistant', name: 'AI', version: '2.2.0', author: 'test', description: '', type: 'hook',
permissions: ['calendar:respond', 'settings:change'], grantedPermissions: granted,
entrypoint: 'index.js', enabled: true, status: 'running', settings: {},
} as InstalledPlugin;
}
describe('the area c flags for one plugin', () => {
it('follow what the plugin was granted', () => {
expect(snapshotHostFeatures(plugin([]))).toMatchObject({ answerInvitation: false, changeSettings: false, batchMail: true });
expect(snapshotHostFeatures(plugin(['calendar:respond']))).toMatchObject({ answerInvitation: true, changeSettings: false });
expect(snapshotHostFeatures(plugin(['calendar:respond', 'settings:change']))).toMatchObject({ answerInvitation: true, changeSettings: true });
});
it('say what the webmail offers when no plugin is named', () => {
expect(snapshotHostFeatures()).toMatchObject({ answerInvitation: true, changeSettings: true });
});
});
+10 -4
View File
@@ -14,6 +14,7 @@ import { useVacationStore } from '@/stores/vacation-store';
import { doVacationGet, doVacationSet } from '../host-api-settings';
import { isPlainRecord, sessionClient } from '../host-api-input';
import { NOT_MINE } from './not-mine';
import { pluginHasPermission } from '../permissions';
import { doCalendarDeleteWithUndo, doCalendarRespond, doCalendarUndoDelete } from './c.calendar';
import { doFiltersCreate, doFiltersList, doFiltersUndo } from './c.filters';
import { doEmailBatch, doEmailUndoBatch } from './c.batch';
@@ -94,13 +95,18 @@ export async function dispatch(plugin: InstalledPlugin, method: string, args: un
}
}
/** This area's flags in api.host.features, right now. */
export function features(): AreaHostFeaturesC {
/**
* This area's flags in api.host.features, right now. For one plugin, the
* calls behind a new optional permission count only once it was granted (a
* plugin enabled before an update lacks them until turned off and on).
*/
export function features(plugin?: InstalledPlugin): AreaHostFeaturesC {
const client = useAuthStore.getState().client;
const granted = (permission: Permission) => !plugin || pluginHasPermission(plugin, permission);
return {
answerInvitation: true,
answerInvitation: granted('calendar:respond'),
filterRules: client?.supportsSieve?.() === true,
batchMail: true,
changeSettings: true,
changeSettings: granted('settings:change'),
};
}