UNPKG

studiocms

Version:

Astro Native CMS for AstroDB. Built from the ground up by the Astro community.

191 lines (177 loc) 7.07 kB
import { UserPermissionLevel } from '@withstudiocms/auth-kit/types'; import { getLevel } from '@withstudiocms/auth-kit/utils/user'; import type { APIContext } from 'astro'; import { deepmerge, Effect, genLogger } from '../effect.js'; import type { UserSessionData } from '../virtuals/auth/types.js'; import { CURRENT_CONFIG_VERSION } from '../virtuals/sdk/consts.js'; import type { SiteConfigCacheObject } from '../virtuals/sdk/types/index.js'; export const getUserPermissionLevel = Effect.fn( '@withstudiocms/AuthKit/modules/user.getUserPermissionLevel' )(function* (userData: UserSessionData) { const level = yield* getLevel(userData); switch (level) { case 'owner': return UserPermissionLevel.owner; case 'admin': return UserPermissionLevel.admin; case 'editor': return UserPermissionLevel.editor; case 'visitor': return UserPermissionLevel.visitor; default: return UserPermissionLevel.unknown; } }); /** * Retrieves the user's permission levels based on their session data. * * @param userData - The session data of the user. * @returns An object containing boolean flags indicating the user's permission levels: * - `isVisitor`: True if the user has at least visitor-level permissions. * - `isEditor`: True if the user has at least editor-level permissions. * - `isAdmin`: True if the user has at least admin-level permissions. * - `isOwner`: True if the user has owner-level permissions. */ export const getUserPermissions = (userData: UserSessionData) => genLogger('studiocms/middleware/utils/getUserPermissions')(function* () { const userPermissionLevel = yield* getUserPermissionLevel(userData); return { isVisitor: userPermissionLevel >= UserPermissionLevel.visitor, isEditor: userPermissionLevel >= UserPermissionLevel.editor, isAdmin: userPermissionLevel >= UserPermissionLevel.admin, isOwner: userPermissionLevel >= UserPermissionLevel.owner, }; }); /** * Creates a fallback site configuration object with default values. * * This function is typically used when no site configuration is available, * providing sensible defaults for the StudioCMS project. * * @returns {SiteConfigCacheObject} The fallback site configuration object. */ export const makeFallbackSiteConfig = (): SiteConfigCacheObject => ({ lastCacheUpdate: new Date(), data: { defaultOgImage: null, description: 'A StudioCMS Project', diffPerPage: 10, enableDiffs: false, enableMailer: false, gridItems: [], hideDefaultIndex: false, loginPageBackground: 'studiocms-curves', loginPageCustomImage: null, siteIcon: null, title: 'StudioCMS-Setup', _config_version: CURRENT_CONFIG_VERSION, }, }); /** * Represents the structure for setting local values in the StudioCMS context. * * @property general - Contains general StudioCMS local values, excluding 'security' and 'plugins'. * @property security - Contains security-related StudioCMS local values. * @property plugins - Contains plugin-related StudioCMS local values. */ export type SetLocalValues = { general: Omit<APIContext['locals']['StudioCMS'], 'security' | 'plugins'>; security: APIContext['locals']['StudioCMS']['security']; plugins: APIContext['locals']['StudioCMS']['plugins']; }; /** * Represents the keys of the {@link SetLocalValues} type. * Useful for extracting valid property names from the {@link SetLocalValues} object type. */ export type SetLocalValuesKeys = keyof SetLocalValues; /** * Enum representing different local settings categories. * * @remarks * Used to specify the context for local configuration, such as general settings, * security-related settings, or plugin-specific settings. * * @enum {string} * @property {string} general - Represents general settings. * @property {string} security - Represents security-related settings. * @property {string} plugins - Represents plugin-specific settings. */ export enum SetLocal { GENERAL = 'general', SECURITY = 'security', PLUGINS = 'plugins', } function getGeneralLocals(StudioCMS: APIContext['locals']['StudioCMS']): SetLocalValues['general'] { const { security: _s, plugins: _p, ...general } = StudioCMS || {}; return general; } const sharedOpts = { mergeArrays: false } as const; /** * Updates the `locals.StudioCMS` property of the given API context with new values for a specified key. * * Depending on the provided `key`, merges the new `values` into the corresponding section of `locals.StudioCMS`: * - `'general'`: Merges into the root of `StudioCMS`. * - `'security'`: Merges into the `security` property of `StudioCMS`. * - `'plugins'`: Merges into the `plugins` property of `StudioCMS`. * * Uses a deep merge strategy to combine existing and new values. * * @template T - The key of the section to update (`'general'`, `'security'`, or `'plugins'`). * @template V - The type of values to merge, corresponding to the section specified by `T`. * @param context - The API context containing the `locals.StudioCMS` object to update. * @param key - The section of `StudioCMS` to update. * @param values - The new values to merge into the specified section. */ export const setLocals = Effect.fn(function* < T extends SetLocalValuesKeys, V extends SetLocalValues[T], >(context: APIContext, key: T, values: V) { switch (key) { case SetLocal.GENERAL: { // Merge general values into the root of StudioCMS // Exclude 'security' and 'plugins' to avoid overwriting them const generalValues = getGeneralLocals(context.locals.StudioCMS); const updatedValues = (yield* deepmerge( (merge) => merge(generalValues, values), sharedOpts )) as SetLocalValues[SetLocal.GENERAL]; // Update the locals with the merged values // This will not overwrite 'security' or 'plugins' const { security, plugins } = context.locals.StudioCMS ?? {}; context.locals.StudioCMS = { ...updatedValues, security, plugins }; break; } case SetLocal.SECURITY: { // Merge security values into the 'security' property of StudioCMS // This will not overwrite 'general' or 'plugins' const currentValues = context.locals.StudioCMS?.security ?? {}; const updatedValues = (yield* deepmerge( (merge) => merge(currentValues, values), sharedOpts )) as SetLocalValues[SetLocal.SECURITY]; // Update the locals with the merged security values context.locals.StudioCMS = { ...(context.locals.StudioCMS ?? {}), security: updatedValues, }; break; } case SetLocal.PLUGINS: { // Merge plugin values into the 'plugins' property of StudioCMS // This will not overwrite 'general' or 'security' const currentValues = context.locals.StudioCMS?.plugins ?? {}; const updatedValues = (yield* deepmerge( (merge) => merge(currentValues, values), sharedOpts )) as SetLocalValues[SetLocal.PLUGINS]; // Update the locals with the merged plugin values context.locals.StudioCMS = { ...(context.locals.StudioCMS ?? {}), plugins: updatedValues, }; break; } default: return yield* Effect.fail(new Error(`Unknown key: ${key}`)); } });