import type { ApiOrgPolicy, ApiOrgSettingsResponse } from "@/lib/api/admin-org-types" import type { OrgPolicySectionKey } from "@/lib/api/admin-org-types" import type { IntegrationEntry, OrgSettingsState, FilePolicySettings, IdentityProvidersPolicy, IdentityProvider } from "@/lib/admin-settings/org-settings-types" const INTEGRATION_HREFS: Record = { authentik: "/admin/settings/authentication", nextcloud: "/admin/settings/nextcloud", onlyoffice: "/admin/settings/onlyoffice", smtp: "/admin/settings/mailing", } function mergeIntegrations( fromApi: IntegrationEntry[] | undefined ): IntegrationEntry[] { if (!fromApi?.length) return [] return fromApi.map((item) => ({ ...item, href: INTEGRATION_HREFS[item.id] ?? item.href, })) } const DEFAULT_IDENTITY_PROVIDERS: IdentityProvidersPolicy = { allow_self_enrollment: true, default_login_source: "", providers: [], } function mergeIdentityProviders( fromApi: Partial | undefined ): IdentityProvidersPolicy { return { ...DEFAULT_IDENTITY_PROVIDERS, ...fromApi, providers: (fromApi?.providers ?? []).map((provider) => ({ ...provider, allowed_email_domains: provider.allowed_email_domains ?? [], allowed_identities: provider.allowed_identities ?? [], allowed_organizations: provider.allowed_organizations ?? [], default_groups: provider.default_groups ?? [], sync_status: provider.sync_status ?? "pending", oauth: provider.oauth ? { ...provider.oauth, client_secret: provider.oauth.client_secret ?? "" } : undefined, ldap: provider.ldap ? { ...provider.ldap, bind_password: provider.ldap.bind_password ?? "" } : undefined, saml: provider.saml ? { ...provider.saml, signing_cert: provider.saml.signing_cert ?? "" } : undefined, })), } } function mapProviderToApi(provider: IdentityProvider) { return { id: provider.id, name: provider.name, slug: provider.slug, type: provider.type, enabled: provider.enabled, authentik_pk: provider.authentik_pk, sync_status: provider.sync_status, sync_error: provider.sync_error, last_synced_at: provider.last_synced_at, allowed_email_domains: provider.allowed_email_domains, allowed_identities: provider.allowed_identities, allowed_organizations: provider.allowed_organizations, default_groups: provider.default_groups, oauth: provider.oauth, saml: provider.saml, ldap: provider.ldap, } } const DEFAULT_FILE_POLICIES: FilePolicySettings = { max_upload_mib: 512, allowed_extensions: "", block_executable: true, external_sharing: "authenticated", default_link_expiry_days: 30, virus_scan_enabled: false, virustotal_api_key: "", retention_trash_days: 30, } function mergeFilePolicies(fromApi: Partial | undefined): FilePolicySettings { return { ...DEFAULT_FILE_POLICIES, ...fromApi, virustotal_api_key: fromApi?.virustotal_api_key ?? "", } } export function apiOrgPolicyToStore(policy: ApiOrgPolicy): Partial { return { authentik: { enabled: policy.authentik.enabled, api_url: policy.authentik.api_url, slug: policy.authentik.slug, client_id: policy.authentik.client_id, enforce_sso: policy.authentik.enforce_sso, allow_password_fallback: policy.authentik.allow_password_fallback, default_groups: policy.authentik.default_groups, }, identityProviders: mergeIdentityProviders(policy.identity_providers), twoFactor: { required_for_all: policy.two_factor.required_for_all, required_for_admins: policy.two_factor.required_for_admins, allowed_methods: policy.two_factor.allowed_methods, grace_period_days: policy.two_factor.grace_period_days, remember_device_days: policy.two_factor.remember_device_days, }, storageQuotas: { ...policy.storage_quotas }, usageQuotas: { ...policy.usage_quotas }, filePolicies: mergeFilePolicies(policy.file_policies), llm: { ...policy.llm, providers: policy.llm.providers ?? [], }, search: { ...policy.search, web_search: policy.search.web_search ?? { default_provider_id: "brave-default", providers: [], }, }, administrators: policy.administrators ?? [], nextcloud: { ...policy.nextcloud }, mailing: { ...policy.mailing }, onlyoffice: { ...policy.onlyoffice }, richtext: { enabled: policy.richtext?.enabled ?? true, storage_mode: policy.richtext?.storage_mode ?? "sidecar", export_mirror_format: policy.richtext?.export_mirror_format ?? "", hocuspocus_url: policy.richtext?.hocuspocus_url ?? "", }, aiAssistant: { enabled: policy.ai_assistant?.enabled ?? false, openwebui_internal_url: policy.ai_assistant?.openwebui_internal_url ?? "", public_path: policy.ai_assistant?.public_path ?? "/ai", embed_default_temporary: policy.ai_assistant?.embed_default_temporary ?? true, default_model: policy.ai_assistant?.default_model ?? "", enabled_tools: policy.ai_assistant?.enabled_tools ?? ["mail", "drive", "contacts", "search"], chat_sync_enabled: policy.ai_assistant?.chat_sync_enabled ?? true, chat_nc_path: policy.ai_assistant?.chat_nc_path ?? "/.ultimail/ai/chats", }, plugins: policy.plugins ?? [], integrations: mergeIntegrations(policy.integrations as IntegrationEntry[]), } } export function storeToApiOrgPolicy(state: OrgSettingsState): ApiOrgPolicy { return { authentik: { enabled: state.authentik.enabled, api_url: state.authentik.api_url, slug: state.authentik.slug, client_id: state.authentik.client_id, enforce_sso: state.authentik.enforce_sso, allow_password_fallback: state.authentik.allow_password_fallback, default_groups: state.authentik.default_groups, }, identity_providers: { allow_self_enrollment: state.identityProviders.allow_self_enrollment, default_login_source: state.identityProviders.default_login_source, providers: state.identityProviders.providers.map(mapProviderToApi), }, two_factor: { required_for_all: state.twoFactor.required_for_all, required_for_admins: state.twoFactor.required_for_admins, allowed_methods: state.twoFactor.allowed_methods, grace_period_days: state.twoFactor.grace_period_days, remember_device_days: state.twoFactor.remember_device_days, }, storage_quotas: { ...state.storageQuotas }, usage_quotas: { ...state.usageQuotas }, file_policies: { ...state.filePolicies }, llm: { default_provider_id: state.llm.default_provider_id, providers: state.llm.providers, contact_discovery_model: state.llm.contact_discovery_model, contact_discovery_provider_id: state.llm.contact_discovery_provider_id, enforce_org_providers: state.llm.enforce_org_providers, allow_user_override: state.llm.allow_user_override, }, search: { suite_engine: state.search.suite_engine, meilisearch_url: state.search.meilisearch_url, meilisearch_api_key: state.search.meilisearch_api_key, typesense_url: state.search.typesense_url, typesense_api_key: state.search.typesense_api_key, web_search: state.search.web_search, enforce_org_search: state.search.enforce_org_search, }, administrators: state.administrators, nextcloud: { ...state.nextcloud }, mailing: { ...state.mailing }, onlyoffice: { ...state.onlyoffice }, richtext: { ...state.richtext }, ai_assistant: { ...state.aiAssistant }, plugins: state.plugins.map(({ id, name, description, enabled, version }) => ({ id, name, description, enabled, version, })), integrations: state.integrations.map(({ id, name, description, enabled, configured }) => ({ id, name, description, enabled, configured, })), } } export function pickApiOrgPolicySections( state: OrgSettingsState, sections: OrgPolicySectionKey[] ): Partial { const full = storeToApiOrgPolicy(state) const patch: Partial = {} for (const key of sections) { patch[key] = full[key] as never } return patch } export type OrgSettingsMeta = { effective: ApiOrgSettingsResponse["effective"] secrets: ApiOrgSettingsResponse["secrets"] envVars: ApiOrgSettingsResponse["env_vars"] deployLocked: ApiOrgSettingsResponse["deploy_locked"] updatedAt: string updatedBy: string } export function apiOrgSettingsMeta(data: ApiOrgSettingsResponse): OrgSettingsMeta { return { effective: data.effective, secrets: data.secrets, envVars: data.env_vars ?? [], deployLocked: data.deploy_locked ?? {}, updatedAt: data.updated_at, updatedBy: data.updated_by, } }