UNPKG

@lucidcms/core

Version:

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

1 lines 12.4 kB
{"version":3,"file":"update-single.mjs","names":["roleServices.validatePermissions","formatter"],"sources":["../../../src/services/roles/update-single.ts"],"sourcesContent":["import formatter from \"../../libs/formatters/index.js\";\nimport { copy } from \"../../libs/i18n/index.js\";\nimport { isCorePermission } from \"../../libs/permission/registry.js\";\nimport {\n\tRolePermissionsRepository,\n\tRolesRepository,\n\tRoleTranslationsRepository,\n} from \"../../libs/repositories/index.js\";\nimport { getTenantConfig } from \"../../utils/helpers/index.js\";\nimport type { ServiceFn } from \"../../utils/services/types.js\";\nimport { invalidateAuthCache } from \"../auth/helpers/auth-cache.js\";\nimport { roleServices } from \"../index.js\";\nimport checkRoleAccess from \"./checks/check-role-access.js\";\nimport {\n\tgetTranslationValue,\n\tprepareRoleTranslations,\n\ttype RoleTranslationInput,\n} from \"./helpers/role-translations.js\";\n\nconst updateSingle: ServiceFn<\n\t[\n\t\t{\n\t\t\tid: number;\n\t\t\tname?: RoleTranslationInput;\n\t\t\tdescription?: RoleTranslationInput;\n\t\t\tpermissions?: string[];\n\t\t\ttenantKey?: string | null;\n\t\t\tauthSuperAdmin: boolean;\n\t\t},\n\t],\n\tundefined\n> = async (context, data) => {\n\tconst Roles = new RolesRepository(context.db.client, context.config.db);\n\tconst RoleTranslations = new RoleTranslationsRepository(\n\t\tcontext.db.client,\n\t\tcontext.config.db,\n\t);\n\tconst defaultRoleLocale = context.config.i18n.defaultLocale;\n\tconst roleLocaleCodes = new Set(\n\t\tcontext.config.i18n.locales.map((locale) => locale.code),\n\t);\n\n\tconst defaultName = getTranslationValue(data.name, defaultRoleLocale);\n\tconst defaultDescription = getTranslationValue(\n\t\tdata.description,\n\t\tdefaultRoleLocale,\n\t);\n\n\tconst [roleRes, validatePermsRes] = await Promise.all([\n\t\tcheckRoleAccess(context, {\n\t\t\tid: data.id,\n\t\t}),\n\t\tdata.permissions !== undefined\n\t\t\t? roleServices.validatePermissions(context, {\n\t\t\t\t\tpermissions: data.permissions,\n\t\t\t\t})\n\t\t\t: undefined,\n\t]);\n\tif (roleRes.error) return roleRes;\n\tif (validatePermsRes?.error) return validatePermsRes;\n\n\tif (formatter.formatBoolean(roleRes.data.locked)) {\n\t\treturn {\n\t\t\terror: {\n\t\t\t\ttype: \"basic\",\n\t\t\t\tmessage: copy(\"server:core.permissions.denied\"),\n\t\t\t\tstatus: 403,\n\t\t\t},\n\t\t\tdata: undefined,\n\t\t};\n\t}\n\n\tconst tenantKey =\n\t\tdata.tenantKey === undefined ? roleRes.data.tenant_key : data.tenantKey;\n\n\t/**\n\t * Explicit tenant assignment can move a role across tenant boundaries, so it is super-admin only.\n\t */\n\tif (data.tenantKey !== undefined && !data.authSuperAdmin) {\n\t\treturn {\n\t\t\terror: {\n\t\t\t\ttype: \"basic\",\n\t\t\t\tmessage: copy(\"server:core.permissions.denied\"),\n\t\t\t\tstatus: 403,\n\t\t\t},\n\t\t\tdata: undefined,\n\t\t};\n\t}\n\n\tif (\n\t\tcontext.request.tenantKey != null &&\n\t\troleRes.data.tenant_key !== null &&\n\t\troleRes.data.tenant_key !== context.request.tenantKey &&\n\t\t!data.authSuperAdmin\n\t) {\n\t\treturn {\n\t\t\terror: {\n\t\t\t\ttype: \"basic\",\n\t\t\t\tmessage: copy(\"server:core.permissions.denied\"),\n\t\t\t\tstatus: 403,\n\t\t\t},\n\t\t\tdata: undefined,\n\t\t};\n\t}\n\n\tif (data.name !== undefined && (!defaultName || defaultName.length < 2)) {\n\t\treturn {\n\t\t\terror: {\n\t\t\t\ttype: \"basic\",\n\t\t\t\tmessage: copy(\"server:core.errors.validation.message\"),\n\t\t\t\tstatus: 400,\n\t\t\t\terrors: {\n\t\t\t\t\tname: {\n\t\t\t\t\t\tcode: \"invalid\",\n\t\t\t\t\t\tmessage: copy(\"server:core.fields.validation.required\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tdata: undefined,\n\t\t};\n\t}\n\n\tif (\n\t\ttenantKey !== null &&\n\t\tgetTenantConfig(context.config, tenantKey) === undefined\n\t) {\n\t\treturn {\n\t\t\terror: {\n\t\t\t\ttype: \"basic\",\n\t\t\t\tmessage: copy(\"server:core.tenants.unknown\", {\n\t\t\t\t\tdata: { key: tenantKey },\n\t\t\t\t}),\n\t\t\t\tstatus: 400,\n\t\t\t},\n\t\t\tdata: undefined,\n\t\t};\n\t}\n\n\tconst checkNameIsUniqueRes =\n\t\tdefaultName != null\n\t\t\t? await Roles.selectRoleIdByTranslationName({\n\t\t\t\t\tname: defaultName,\n\t\t\t\t\tlocaleCode: defaultRoleLocale,\n\t\t\t\t\ttenantKey,\n\t\t\t\t\texcludeRoleId: data.id,\n\t\t\t\t})\n\t\t\t: undefined;\n\tif (checkNameIsUniqueRes?.error) return checkNameIsUniqueRes;\n\n\tif (defaultName != null && checkNameIsUniqueRes?.data !== undefined) {\n\t\treturn {\n\t\t\terror: {\n\t\t\t\ttype: \"basic\",\n\t\t\t\tmessage: copy(\"server:core.validation.unique.message\"),\n\t\t\t\tstatus: 400,\n\t\t\t\terrors: {\n\t\t\t\t\tname: {\n\t\t\t\t\t\tcode: \"invalid\",\n\t\t\t\t\t\tmessage: copy(\"server:core.validation.unique.message\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tdata: undefined,\n\t\t};\n\t}\n\tconst updateData: {\n\t\tupdated_at: string;\n\t\ttenant_key?: string | null;\n\t} = {\n\t\tupdated_at: new Date().toISOString(),\n\t};\n\tif (data.tenantKey !== undefined) {\n\t\tupdateData.tenant_key = data.tenantKey;\n\t}\n\tconst updateRoleRes = await Roles.updateSingle({\n\t\tdata: updateData,\n\t\twhere: [\n\t\t\t{\n\t\t\t\tkey: \"id\",\n\t\t\t\toperator: \"=\",\n\t\t\t\tvalue: data.id,\n\t\t\t},\n\t\t],\n\t\treturning: [\"id\"],\n\t\tvalidation: {\n\t\t\tenabled: true,\n\t\t},\n\t});\n\tif (updateRoleRes.error) return updateRoleRes;\n\n\tawait invalidateAuthCache(context);\n\n\tif (data.name !== undefined || data.description !== undefined) {\n\t\tconst existingNameTranslations: RoleTranslationInput =\n\t\t\troleRes.data.translations\n\t\t\t\t?.filter(\n\t\t\t\t\t(translation) =>\n\t\t\t\t\t\ttranslation.locale_code !== null &&\n\t\t\t\t\t\troleLocaleCodes.has(translation.locale_code),\n\t\t\t\t)\n\t\t\t\t.map((translation) => ({\n\t\t\t\t\tlocaleCode: translation.locale_code,\n\t\t\t\t\tvalue: translation.name,\n\t\t\t\t})) ?? [];\n\t\tconst existingDescriptionTranslations: RoleTranslationInput =\n\t\t\troleRes.data.translations\n\t\t\t\t?.filter(\n\t\t\t\t\t(translation) =>\n\t\t\t\t\t\ttranslation.locale_code !== null &&\n\t\t\t\t\t\troleLocaleCodes.has(translation.locale_code),\n\t\t\t\t)\n\t\t\t\t.map((translation) => ({\n\t\t\t\t\tlocaleCode: translation.locale_code,\n\t\t\t\t\tvalue: translation.description,\n\t\t\t\t})) ?? [];\n\t\tconst existingDefaultName = getTranslationValue(\n\t\t\texistingNameTranslations,\n\t\t\tdefaultRoleLocale,\n\t\t);\n\t\tconst existingDefaultDescription = getTranslationValue(\n\t\t\texistingDescriptionTranslations,\n\t\t\tdefaultRoleLocale,\n\t\t);\n\t\tconst translations = prepareRoleTranslations({\n\t\t\tname: data.name ?? existingNameTranslations,\n\t\t\tdescription: data.description ?? existingDescriptionTranslations,\n\t\t\troleId: data.id,\n\t\t});\n\t\tif (\n\t\t\ttranslations.every(\n\t\t\t\t(translation) => translation.locale_code !== defaultRoleLocale,\n\t\t\t)\n\t\t) {\n\t\t\ttranslations.push({\n\t\t\t\trole_id: data.id,\n\t\t\t\tlocale_code: defaultRoleLocale,\n\t\t\t\tname:\n\t\t\t\t\tdata.name !== undefined\n\t\t\t\t\t\t? (defaultName ?? null)\n\t\t\t\t\t\t: (existingDefaultName ?? null),\n\t\t\t\tdescription:\n\t\t\t\t\tdata.description !== undefined\n\t\t\t\t\t\t? (defaultDescription ?? null)\n\t\t\t\t\t\t: (existingDefaultDescription ?? null),\n\t\t\t});\n\t\t}\n\t\tconst deleteTranslationsRes = await RoleTranslations.deleteMultiple({\n\t\t\twhere: [\n\t\t\t\t{\n\t\t\t\t\tkey: \"role_id\",\n\t\t\t\t\toperator: \"=\",\n\t\t\t\t\tvalue: data.id,\n\t\t\t\t},\n\t\t\t],\n\t\t\treturning: [\"id\"],\n\t\t});\n\t\tif (deleteTranslationsRes.error) return deleteTranslationsRes;\n\n\t\tif (translations.length > 0) {\n\t\t\tconst roleTranslationsRes = await RoleTranslations.upsertMultiple({\n\t\t\t\tdata: translations,\n\t\t\t\treturning: [\"id\"],\n\t\t\t\tvalidation: {\n\t\t\t\t\tenabled: true,\n\t\t\t\t},\n\t\t\t});\n\t\t\tif (roleTranslationsRes.error) return roleTranslationsRes;\n\t\t}\n\t}\n\n\tif (validatePermsRes?.data !== undefined) {\n\t\tconst RolePermissions = new RolePermissionsRepository(\n\t\t\tcontext.db.client,\n\t\t\tcontext.config.db,\n\t\t);\n\n\t\tconst deletePermsRes = await RolePermissions.deleteMultiple({\n\t\t\twhere: [\n\t\t\t\t{\n\t\t\t\t\tkey: \"role_id\",\n\t\t\t\t\toperator: \"=\",\n\t\t\t\t\tvalue: data.id,\n\t\t\t\t},\n\t\t\t],\n\t\t\treturning: [\"id\"],\n\t\t\tvalidation: {\n\t\t\t\tenabled: true,\n\t\t\t},\n\t\t});\n\t\tif (deletePermsRes.error) return deletePermsRes;\n\n\t\tif (validatePermsRes.data.length > 0) {\n\t\t\tconst rolePermsRes = await RolePermissions.createMultiple({\n\t\t\t\tdata: validatePermsRes.data.map((p) => ({\n\t\t\t\t\trole_id: data.id,\n\t\t\t\t\tpermission: p.permission,\n\t\t\t\t\tcore: isCorePermission(p.permission),\n\t\t\t\t})),\n\t\t\t});\n\t\t\tif (rolePermsRes.error) return rolePermsRes;\n\t\t}\n\t}\n\n\tawait invalidateAuthCache(context);\n\n\treturn {\n\t\terror: undefined,\n\t\tdata: undefined,\n\t};\n};\n\nexport default updateSingle;\n"],"mappings":"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"}