feat(plugins): add 2 new methods : user.getAccounts and user.getIdentities
This commit is contained in:
@@ -87,6 +87,7 @@ const PERMISSION_LABELS: Record<string, { title: string; body: string }> = {
|
|||||||
'http:fetch': { title: 'Talk to external services', body: 'Make uncredentialled requests to the third-party origins listed in the manifest.' },
|
'http:fetch': { title: 'Talk to external services', body: 'Make uncredentialled requests to the third-party origins listed in the manifest.' },
|
||||||
'admin:config': { title: 'Read/write admin config', body: 'Access this plugin\'s admin-supplied configuration values.' },
|
'admin:config': { title: 'Read/write admin config', body: 'Access this plugin\'s admin-supplied configuration values.' },
|
||||||
'ui:download-file': { title: 'Download files', body: 'Download custom files generated by the plugin.' },
|
'ui:download-file': { title: 'Download files', body: 'Download custom files generated by the plugin.' },
|
||||||
|
'account:read': { title: 'Read your accounts', body: 'Access the list of accounts you have configured in the app.' },
|
||||||
};
|
};
|
||||||
|
|
||||||
export function describePermission(perm: string): { title: string; body: string } {
|
export function describePermission(perm: string): { title: string; body: string } {
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import type { InstalledPlugin, Permission } from '../plugin-types';
|
|||||||
import { IMPLICIT_PERMISSIONS } from '../plugin-types';
|
import { IMPLICIT_PERMISSIONS } from '../plugin-types';
|
||||||
import { toast as appToast } from '@/stores/toast-store';
|
import { toast as appToast } from '@/stores/toast-store';
|
||||||
import { useAuthStore } from '@/stores/auth-store';
|
import { useAuthStore } from '@/stores/auth-store';
|
||||||
|
import { useAccountStore } from '@/stores/account-store';
|
||||||
|
import { useIdentityStore } from '@/stores/identity-store';
|
||||||
import { useEmailStore } from '@/stores/email-store';
|
import { useEmailStore } from '@/stores/email-store';
|
||||||
import { useFilterStore } from '@/stores/filter-store';
|
import { useFilterStore } from '@/stores/filter-store';
|
||||||
import { useMessageListTabsStore } from '@/stores/message-list-tabs-store';
|
import { useMessageListTabsStore } from '@/stores/message-list-tabs-store';
|
||||||
@@ -14,7 +16,7 @@ import { apiFetch } from '../browser-navigation';
|
|||||||
import { awaitDialog, awaitPrompt, type PromptField } from './host-dialog';
|
import { awaitDialog, awaitPrompt, type PromptField } from './host-dialog';
|
||||||
import { fileStorage } from '../plugin-storage';
|
import { fileStorage } from '../plugin-storage';
|
||||||
import { generateUUID } from '../utils';
|
import { generateUUID } from '../utils';
|
||||||
import { ContactCard } from '../jmap/types';
|
import { ContactCard, Identity } from '../jmap/types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Methods only callable from the privileged (same-origin) tier. These expose
|
* Methods only callable from the privileged (same-origin) tier. These expose
|
||||||
@@ -62,6 +64,9 @@ const PERM_PER_METHOD: Record<string, Permission | null> = {
|
|||||||
'contact.update': 'contacts:write',
|
'contact.update': 'contacts:write',
|
||||||
'contact.create': 'contacts:write',
|
'contact.create': 'contacts:write',
|
||||||
'contact.search': 'contacts:read',
|
'contact.search': 'contacts:read',
|
||||||
|
// user
|
||||||
|
'user.getAccounts': 'account:read',
|
||||||
|
'user.getIdentities': 'identity:read',
|
||||||
// admin
|
// admin
|
||||||
'admin.getConfig': 'admin:config',
|
'admin.getConfig': 'admin:config',
|
||||||
'admin.getAllConfig': 'admin:config',
|
'admin.getAllConfig': 'admin:config',
|
||||||
@@ -157,6 +162,41 @@ function storageKeys(pluginId: string): string[] {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── user ─────────────────────────────────────────────────────
|
||||||
|
interface AccountResponse {
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
serverUrl: string;
|
||||||
|
username: string;
|
||||||
|
displayName: string;
|
||||||
|
email: string;
|
||||||
|
avatarColor: string;
|
||||||
|
isConnected: boolean;
|
||||||
|
isDefault: boolean;
|
||||||
|
}
|
||||||
|
function doUserGetAccounts(): AccountResponse[] {
|
||||||
|
const state = useAccountStore.getState();
|
||||||
|
|
||||||
|
// ws remove sensitive fields from the account entries before returning to the plugin
|
||||||
|
const accounts = state.accounts.map((account) => ({
|
||||||
|
id: account.id,
|
||||||
|
label: account.label,
|
||||||
|
serverUrl: account.serverUrl,
|
||||||
|
username: account.username,
|
||||||
|
displayName: account.displayName,
|
||||||
|
email: account.email,
|
||||||
|
avatarColor: account.avatarColor,
|
||||||
|
isConnected: account.isConnected,
|
||||||
|
isDefault: account.isDefault,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return accounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
function doUserGetIdentities(): Identity[] {
|
||||||
|
return useIdentityStore.getState().identities;
|
||||||
|
}
|
||||||
|
|
||||||
// ─── http.post (same-origin /api/*) ───────────────────────────
|
// ─── http.post (same-origin /api/*) ───────────────────────────
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -745,6 +785,9 @@ export async function dispatchApiCall(
|
|||||||
case 'contact.create': return doContactCreate(args[0] as ContactCard);
|
case 'contact.create': return doContactCreate(args[0] as ContactCard);
|
||||||
case 'contact.search': return doContactSearch(args[0] as string);
|
case 'contact.search': return doContactSearch(args[0] as string);
|
||||||
|
|
||||||
|
case 'user.getAccounts': return doUserGetAccounts();
|
||||||
|
case 'user.getIdentities': return doUserGetIdentities();
|
||||||
|
|
||||||
case 'admin.getConfig': return adminGet(plugin.id, args[0] as string);
|
case 'admin.getConfig': return adminGet(plugin.id, args[0] as string);
|
||||||
case 'admin.getAllConfig': return adminGetAll(plugin.id);
|
case 'admin.getAllConfig': return adminGetAll(plugin.id);
|
||||||
case 'admin.setConfig': await adminSet(plugin.id, args[0] as string, args[1]); return undefined;
|
case 'admin.setConfig': await adminSet(plugin.id, args[0] as string, args[1]); return undefined;
|
||||||
|
|||||||
@@ -175,6 +175,10 @@ function buildPluginApi(manifest: PluginManifest) {
|
|||||||
remove: (key: string) => callApi('storage.remove', [key]),
|
remove: (key: string) => callApi('storage.remove', [key]),
|
||||||
keys: () => callApi('storage.keys', []),
|
keys: () => callApi('storage.keys', []),
|
||||||
},
|
},
|
||||||
|
user: {
|
||||||
|
getAccounts: () => callApi('user.getAccounts', []),
|
||||||
|
getIdentities: () => callApi('user.getIdentities', []),
|
||||||
|
},
|
||||||
http: {
|
http: {
|
||||||
post: (path: string, body: Record<string, unknown>) => callApi('http.post', [path, body]),
|
post: (path: string, body: Record<string, unknown>) => callApi('http.post', [path, body]),
|
||||||
fetch: (url: string, init?: unknown) => callApi('http.fetch', [url, init]),
|
fetch: (url: string, init?: unknown) => callApi('http.fetch', [url, init]),
|
||||||
|
|||||||
@@ -1035,6 +1035,7 @@ export const ALL_PERMISSIONS = [
|
|||||||
'settings:read', 'settings:write',
|
'settings:read', 'settings:write',
|
||||||
'security:read',
|
'security:read',
|
||||||
'auth:observe',
|
'auth:observe',
|
||||||
|
'account:read',
|
||||||
'http:post', 'http:fetch',
|
'http:post', 'http:fetch',
|
||||||
'ui:observe', 'ui:toolbar', 'ui:app-top-banner', 'ui:email-banner', 'ui:email-footer',
|
'ui:observe', 'ui:toolbar', 'ui:app-top-banner', 'ui:email-banner', 'ui:email-footer',
|
||||||
'ui:email-details',
|
'ui:email-details',
|
||||||
|
|||||||
Reference in New Issue
Block a user