UNPKG

@lucidcms/core

Version:

The core of the Lucid CMS. It's responsible for spinning up the API and serving the CMS.

1 lines 7.57 kB
{"version":3,"file":"users.mjs","names":["userPermissionsFormatter","formatter","mediaFormatter"],"sources":["../../../src/libs/formatters/users.ts"],"sourcesContent":["import type { Config } from \"../../types/config.js\";\nimport type { LucidAuth } from \"../../types/hono.js\";\nimport type { Tenant, User } from \"../../types/response.js\";\nimport type { BooleanInt } from \"../db/types.js\";\nimport { normalizeCopy } from \"../i18n/index.js\";\nimport { Permissions } from \"../permission/definitions.js\";\nimport hasAccess from \"../permission/has-access.js\";\nimport formatter from \"./index.js\";\nimport type { MediaPosterPropsT } from \"./media.js\";\nimport mediaFormatter from \"./media.js\";\nimport userPermissionsFormatter from \"./user-permissions.js\";\n\nexport interface UserPropT {\n\tcreated_at: Date | string | null;\n\temail: string;\n\tfirst_name: string | null;\n\tsuper_admin: BooleanInt | null;\n\tid: number;\n\tlast_name: string | null;\n\tupdated_at: Date | string | null;\n\tusername: string;\n\ttriggered_password_reset?: BooleanInt;\n\tinvitation_accepted: BooleanInt;\n\tis_locked: BooleanInt;\n\tis_deleted: BooleanInt | null;\n\tis_deleted_at: Date | string | null;\n\tpassword?: string | null;\n\tprofile_picture?: MediaPosterPropsT[];\n\tauth_providers?: {\n\t\tid: number;\n\t\tprovider_key: string;\n\t\tprovider_user_id: string;\n\t\tlinked_at: Date | string | null;\n\t}[];\n\troles?: {\n\t\tid: number;\n\t\tname?: string | null;\n\t\ttranslations?: {\n\t\t\tname: string | null;\n\t\t\tlocale_code: string | null;\n\t\t}[];\n\t\tpermissions?: {\n\t\t\tpermission: string;\n\t\t}[];\n\t}[];\n\ttenants?: {\n\t\ttenant_key: string;\n\t}[];\n}\n\nconst formatMultiple = (props: {\n\tusers: UserPropT[];\n\tauthUser?: LucidAuth;\n\thost: string;\n\tlocales: string[];\n\tdefaultLocale: string;\n\ttenants?: Config[\"tenants\"];\n}) => {\n\treturn props.users.map((u) =>\n\t\tformatSingle({\n\t\t\tuser: u,\n\t\t\tauthUser: props.authUser,\n\t\t\thost: props.host,\n\t\t\tlocales: props.locales,\n\t\t\tdefaultLocale: props.defaultLocale,\n\t\t\ttenants: props.tenants,\n\t\t}),\n\t);\n};\n\nconst formatSingle = (props: {\n\tuser: UserPropT;\n\tauthUser?: LucidAuth;\n\thost: string;\n\tlocales: string[];\n\tdefaultLocale: string;\n\ttenants?: Config[\"tenants\"];\n\t/**\n\t * Uses a pre-resolved tenant list when the response should show accessible tenants,\n\t * not only memberships loaded on the user row.\n\t */\n\ttenantOverride?: Tenant[];\n\tpendingEmailChange?: {\n\t\temail: string;\n\t\trequestedAt: Date | string | null;\n\t\texpiresAt: Date | string | null;\n\t} | null;\n}): User => {\n\tconst { roles, permissions } = userPermissionsFormatter.formatMultiple({\n\t\troles: props.user.roles || [],\n\t\tdefaultLocale: props.defaultLocale,\n\t});\n\n\tconst canViewDetails = hasAccess({\n\t\tuser: props.authUser,\n\t\trequiredPermissions: [Permissions.UsersRead],\n\t\tresourceOwnerId: props.user.id,\n\t});\n\n\tconst canViewSensitive = hasAccess({\n\t\tuser: props.authUser,\n\t\trequiredPermissions: [Permissions.UsersUpdate],\n\t\tresourceOwnerId: props.user.id,\n\t});\n\n\tconst response: User = {\n\t\tid: props.user.id,\n\t\temail: props.user.email,\n\t\tusername: props.user.username,\n\t\tfirstName: props.user.first_name,\n\t\tlastName: props.user.last_name,\n\t\tisDeleted: formatter.formatBoolean(props.user.is_deleted ?? false),\n\t\tprofilePicture: mediaFormatter.formatProfilePicture({\n\t\t\tposter: props.user.profile_picture?.[0],\n\t\t\thost: props.host,\n\t\t}),\n\t};\n\n\tif (canViewDetails) {\n\t\tresponse.deletedAt = formatter.formatDate(props.user.is_deleted_at);\n\t\tresponse.createdAt = formatter.formatDate(props.user.created_at);\n\t\tresponse.updatedAt = formatter.formatDate(props.user.updated_at);\n\t}\n\n\tif (canViewSensitive) {\n\t\tresponse.isLocked = formatter.formatBoolean(props.user.is_locked);\n\t\tresponse.superAdmin = formatter.formatBoolean(\n\t\t\tprops.user.super_admin ?? false,\n\t\t);\n\t\tresponse.triggerPasswordReset = formatter.formatBoolean(\n\t\t\tprops.user.triggered_password_reset,\n\t\t);\n\t\tresponse.invitationAccepted = formatter.formatBoolean(\n\t\t\tprops.user.invitation_accepted,\n\t\t);\n\t\tresponse.roles = roles;\n\t\tresponse.permissions = permissions;\n\t\tresponse.hasPassword = Boolean(props.user.password);\n\t\tresponse.authProviders = (props.user.auth_providers || []).map((p) => {\n\t\t\treturn {\n\t\t\t\tid: p.id,\n\t\t\t\tproviderKey: p.provider_key,\n\t\t\t\tproviderUserId: p.provider_user_id,\n\t\t\t\tlinkedAt: formatter.formatDate(p.linked_at),\n\t\t\t};\n\t\t});\n\n\t\tif (props.tenantOverride !== undefined) {\n\t\t\tresponse.tenants = props.tenantOverride;\n\t\t} else if (props.tenants !== undefined) {\n\t\t\t/**\n\t\t\t * Filters out stored memberships for tenants that are no longer configured.\n\t\t\t */\n\t\t\tresponse.tenants =\n\t\t\t\tprops.user.tenants?.flatMap((membership) => {\n\t\t\t\t\tconst tenant = props.tenants?.find(\n\t\t\t\t\t\t(t) => t.key === membership.tenant_key,\n\t\t\t\t\t);\n\t\t\t\t\tif (tenant === undefined) return [];\n\n\t\t\t\t\treturn [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tkey: tenant.key,\n\t\t\t\t\t\t\tname: normalizeCopy(tenant.name),\n\t\t\t\t\t\t\tdefault: tenant.default ?? false,\n\t\t\t\t\t\t},\n\t\t\t\t\t];\n\t\t\t\t}) ?? [];\n\t\t}\n\t}\n\n\tif (props.pendingEmailChange !== undefined) {\n\t\tresponse.pendingEmailChange = props.pendingEmailChange\n\t\t\t? {\n\t\t\t\t\temail: props.pendingEmailChange.email,\n\t\t\t\t\trequestedAt: formatter.formatDate(\n\t\t\t\t\t\tprops.pendingEmailChange.requestedAt,\n\t\t\t\t\t),\n\t\t\t\t\texpiresAt: formatter.formatDate(props.pendingEmailChange.expiresAt),\n\t\t\t\t}\n\t\t\t: null;\n\t}\n\n\treturn response;\n};\n\nexport default {\n\tformatMultiple,\n\tformatSingle,\n};\n"],"mappings":"qPAkDA,MAAM,EAAkB,GAQhB,EAAM,MAAM,IAAK,GACvB,EAAa,CACZ,KAAM,EACN,SAAU,EAAM,SAChB,KAAM,EAAM,KACZ,QAAS,EAAM,QACf,cAAe,EAAM,cACrB,QAAS,EAAM,OAChB,CAAC,CACF,EAGK,EAAgB,GAiBV,CACX,GAAM,CAAE,QAAO,eAAgBA,EAAyB,eAAe,CACtE,MAAO,EAAM,KAAK,OAAS,CAAC,EAC5B,cAAe,EAAM,aACtB,CAAC,EAEK,EAAiB,EAAU,CAChC,KAAM,EAAM,SACZ,oBAAqB,CAAC,EAAY,SAAS,EAC3C,gBAAiB,EAAM,KAAK,EAC7B,CAAC,EAEK,EAAmB,EAAU,CAClC,KAAM,EAAM,SACZ,oBAAqB,CAAC,EAAY,WAAW,EAC7C,gBAAiB,EAAM,KAAK,EAC7B,CAAC,EAEK,EAAiB,CACtB,GAAI,EAAM,KAAK,GACf,MAAO,EAAM,KAAK,MAClB,SAAU,EAAM,KAAK,SACrB,UAAW,EAAM,KAAK,WACtB,SAAU,EAAM,KAAK,UACrB,UAAWC,EAAU,cAAc,EAAM,KAAK,YAAc,EAAK,EACjE,eAAgBC,EAAe,qBAAqB,CACnD,OAAQ,EAAM,KAAK,kBAAkB,GACrC,KAAM,EAAM,IACb,CAAC,CACF,EAmEA,OAjEI,IACH,EAAS,UAAYD,EAAU,WAAW,EAAM,KAAK,aAAa,EAClE,EAAS,UAAYA,EAAU,WAAW,EAAM,KAAK,UAAU,EAC/D,EAAS,UAAYA,EAAU,WAAW,EAAM,KAAK,UAAU,GAG5D,IACH,EAAS,SAAWA,EAAU,cAAc,EAAM,KAAK,SAAS,EAChE,EAAS,WAAaA,EAAU,cAC/B,EAAM,KAAK,aAAe,EAC3B,EACA,EAAS,qBAAuBA,EAAU,cACzC,EAAM,KAAK,wBACZ,EACA,EAAS,mBAAqBA,EAAU,cACvC,EAAM,KAAK,mBACZ,EACA,EAAS,MAAQ,EACjB,EAAS,YAAc,EACvB,EAAS,YAAc,EAAQ,EAAM,KAAK,SAC1C,EAAS,eAAiB,EAAM,KAAK,gBAAkB,CAAC,EAAA,CAAG,IAAK,IACxD,CACN,GAAI,EAAE,GACN,YAAa,EAAE,aACf,eAAgB,EAAE,iBAClB,SAAUA,EAAU,WAAW,EAAE,SAAS,CAC3C,EACA,EAEG,EAAM,iBAAmB,IAAA,GAElB,EAAM,UAAY,IAAA,KAI5B,EAAS,QACR,EAAM,KAAK,SAAS,QAAS,GAAe,CAC3C,IAAM,EAAS,EAAM,SAAS,KAC5B,GAAM,EAAE,MAAQ,EAAW,UAC7B,EAGA,OAFI,IAAW,IAAA,GAAkB,CAAC,EAE3B,CACN,CACC,IAAK,EAAO,IACZ,KAAM,EAAc,EAAO,IAAI,EAC/B,QAAS,EAAO,SAAW,EAC5B,CACD,CACD,CAAC,GAAK,CAAC,GAnBR,EAAS,QAAU,EAAM,gBAuBvB,EAAM,qBAAuB,IAAA,KAChC,EAAS,mBAAqB,EAAM,mBACjC,CACA,MAAO,EAAM,mBAAmB,MAChC,YAAaA,EAAU,WACtB,EAAM,mBAAmB,WAC1B,EACA,UAAWA,EAAU,WAAW,EAAM,mBAAmB,SAAS,CACnE,EACC,MAGG,CACR,EAEA,IAAA,EAAe,CACd,iBACA,cACD"}