@drodil/backstage-plugin-qeta-backend 3.54.0 → 3.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/database/DatabaseQetaStore.cjs.js +1 -0
- package/dist/database/DatabaseQetaStore.cjs.js.map +1 -1
- package/dist/database/stores/CollectionsStore.cjs.js +262 -23
- package/dist/database/stores/CollectionsStore.cjs.js.map +1 -1
- package/dist/database/stores/PostsStore.cjs.js +6 -0
- package/dist/database/stores/PostsStore.cjs.js.map +1 -1
- package/dist/service/routes/collections.cjs.js +6 -0
- package/dist/service/routes/collections.cjs.js.map +1 -1
- package/dist/service/types.cjs.js +4 -1
- package/dist/service/types.cjs.js.map +1 -1
- package/dist/service/util.cjs.js +74 -18
- package/dist/service/util.cjs.js.map +1 -1
- package/migrations/20260109_automatic_collections.js +59 -0
- package/package.json +6 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.cjs.js","sources":["../../src/service/util.ts"],"sourcesContent":["import { Request } from 'express';\nimport { format, subDays } from 'date-fns';\nimport {\n isAnswer,\n isCollection,\n isPost,\n isTag,\n MaybeAnswer,\n MaybeCollection,\n MaybePost,\n MaybeTag,\n} from '../database/QetaStore';\nimport { Config } from '@backstage/config';\nimport { S3Client } from '@aws-sdk/client-s3';\nimport { RouteOptions } from './types';\nimport {\n Answer,\n AnswerResponse,\n CollectionResponse,\n Comment,\n PostResponse,\n qetaDeleteAnswerPermission,\n qetaDeleteCollectionPermission,\n qetaDeleteCommentPermission,\n qetaDeletePostPermission,\n qetaDeleteTagPermission,\n qetaEditAnswerPermission,\n qetaEditCollectionPermission,\n qetaEditCommentPermission,\n qetaEditPostPermission,\n qetaEditTagPermission,\n selectByPostType,\n TagResponse,\n} from '@drodil/backstage-plugin-qeta-common';\nimport { NodeHttpHandler } from '@smithy/node-http-handler';\nimport { HttpsProxyAgent } from 'hpagent';\nimport { compact } from 'lodash';\nimport {\n ConditionTransformer,\n createConditionTransformer,\n} from '@backstage/plugin-permission-node';\nimport { rules } from '@drodil/backstage-plugin-qeta-node';\nimport { BlobServiceClient } from '@azure/storage-blob';\nimport { DefaultAzureCredential } from '@azure/identity';\nimport { BackstageCredentials } from '@backstage/backend-plugin-api';\nimport { PermissionManager } from './PermissionManager.ts';\nimport { stringifyEntityRef } from '@backstage/catalog-model';\n\nexport const getResourceUrl = (\n resource: MaybePost | MaybeAnswer | MaybeTag | MaybeCollection,\n config: Config,\n absolute?: boolean,\n) => {\n if (!resource) {\n return undefined;\n }\n const basePath = (\n config.getOptionalString('qeta.route') ?? 'qeta'\n ).replaceAll(/(^\\/+)|(\\/+$)/g, '');\n const baseUrl = absolute\n ? `${config.getOptionalString('app.baseUrl') ?? ''}/${basePath}`\n : `/${basePath}`;\n\n if (isTag(resource)) {\n return `${baseUrl}/tags/${resource.tag}`;\n } else if (isCollection(resource)) {\n return `${baseUrl}/collection/${resource.id}`;\n } else if (isAnswer(resource)) {\n return `${baseUrl}/questions/${resource.postId}#answer_${resource.id}`;\n } else if (isPost(resource)) {\n const questionRoute = `${baseUrl}/questions/${resource.id}`;\n const articleRoute = `${baseUrl}/articles/${resource.id}`;\n const linkRoute = `${baseUrl}/links/${resource.id}`;\n return selectByPostType(\n resource.type,\n questionRoute,\n articleRoute,\n linkRoute,\n );\n }\n return undefined;\n};\n\n/**\n * Filter entity refs based on catalog permissions.\n * Uses catalogApi.getEntitiesByRefs which automatically filters out entities\n * the user doesn't have permission to see.\n */\nconst filterEntitiesByPermissions = async (\n entityRefs: string[] | undefined,\n routeOpts: RouteOptions,\n credentials: BackstageCredentials,\n): Promise<string[] | undefined> => {\n if (!entityRefs || entityRefs.length === 0) {\n return entityRefs;\n }\n\n try {\n // Get a plugin token on behalf of the user to call the catalog\n const { token } = await routeOpts.auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n // catalogApi.getEntitiesByRefs handles permission checks automatically\n // It only returns entities the user has permission to see\n const entities = await routeOpts.catalog.getEntitiesByRefs(\n { entityRefs },\n { token },\n );\n\n // Return only the refs of entities that were successfully retrieved\n return entities.items\n .filter(entity => entity !== undefined)\n .map(stringifyEntityRef);\n } catch (error) {\n // If there's an error, return empty array to be safe\n routeOpts.logger.warn('Error filtering entities by permissions', error);\n return [];\n }\n};\n\nexport const getCreated = async (\n req: Request<unknown>,\n options: RouteOptions,\n): Promise<Date> => {\n const allowMetadataInput = options.config.getOptionalBoolean(\n 'qeta.allowMetadataInput',\n );\n\n if (allowMetadataInput && req.body.created) {\n return new Date(req.body.created);\n }\n\n return new Date();\n};\n\nexport type QetaFilter = {\n property:\n | 'posts.id'\n | 'posts.author'\n | 'posts.type'\n | 'tags'\n | 'entityRefs'\n | 'answers.id'\n | 'answers.author'\n | 'comments.id'\n | 'comments.author'\n | 'tags.tag'\n | 'tag.experts'\n | 'collections.owner'\n | 'collections.id';\n values: Array<string | undefined>;\n};\n\nexport type QetaFilters = QetaFilter;\n\nexport const transformConditions: ConditionTransformer<QetaFilters> =\n createConditionTransformer(Object.values(rules));\n\nconst mapTagAdditionalFields = async (\n request: Request<unknown>,\n resource: TagResponse,\n permissionMgr: PermissionManager,\n credentials: BackstageCredentials,\n checkRights?: boolean,\n permissions?: Map<string, boolean>,\n) => {\n const [canEdit, canDelete] = await Promise.all([\n permissions?.get(`edit:tag:${resource.id}`) ??\n (checkRights\n ? permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaEditTagPermission, resource }],\n {\n credentials,\n },\n )\n .then(r => r[0])\n : undefined),\n permissions?.get(`delete:tag:${resource.id}`) ??\n (checkRights\n ? permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaDeleteTagPermission, resource }],\n {\n credentials,\n },\n )\n .then(r => r[0])\n : undefined),\n ]);\n\n resource.canEdit = canEdit;\n resource.canDelete = canDelete;\n return resource;\n};\n\nconst mapCollectionAdditionalFields = async (\n request: Request<unknown>,\n resource: CollectionResponse,\n permissionMgr: PermissionManager,\n credentials: BackstageCredentials,\n checkRights?: boolean,\n routeOpts?: RouteOptions,\n permissions?: Map<string, boolean>,\n) => {\n const [canEdit, canDelete, filteredEntities] = await Promise.all([\n permissions?.get(`edit:collection:${resource.id}`) ??\n (checkRights\n ? permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaEditCollectionPermission, resource }],\n {\n credentials,\n },\n )\n .then(r => r[0])\n : undefined),\n permissions?.get(`delete:collection:${resource.id}`) ??\n (checkRights\n ? permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaDeleteCollectionPermission, resource }],\n {\n credentials,\n },\n )\n .then(r => r[0])\n : undefined),\n routeOpts\n ? filterEntitiesByPermissions(resource.entities, routeOpts, credentials)\n : resource.entities,\n ]);\n\n resource.canEdit = canEdit;\n resource.canDelete = canDelete;\n resource.entities = filteredEntities;\n\n if (resource.posts && routeOpts) {\n await Promise.all(\n resource.posts.map(async post => {\n post.entities = await filterEntitiesByPermissions(\n post.entities,\n routeOpts,\n credentials,\n );\n }),\n );\n }\n\n return resource;\n};\n\nconst mapResourceComments = async (\n request: Request<unknown>,\n resource: AnswerResponse | PostResponse,\n permissionMgr: PermissionManager,\n credentials: BackstageCredentials,\n username: string,\n checkRights?: boolean,\n permissions?: Map<string, boolean>,\n) => {\n const commentArr = resource.comments ?? [];\n const comments: (Comment | null)[] = await Promise.all(\n commentArr.map(async (c: Comment) => {\n const canEdit =\n permissions?.get(`edit:comment:${c.id}`) ??\n (checkRights\n ? await permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaEditCommentPermission, resource: c }],\n { credentials },\n )\n .then(r => r[0])\n : false);\n const canDelete =\n permissions?.get(`delete:comment:${c.id}`) ??\n (checkRights\n ? await permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaDeleteCommentPermission, resource: c }],\n { credentials },\n )\n .then(r => r[0])\n : false);\n\n return {\n ...c,\n own: c.author === username,\n expert: c.experts?.includes(c.author),\n canEdit,\n canDelete,\n };\n }),\n );\n return compact(comments);\n};\n\nconst mapAnswerAdditionalFields = async (\n request: Request<unknown>,\n resource: AnswerResponse,\n permissionMgr: PermissionManager,\n credentials: BackstageCredentials,\n username: string,\n checkRights?: boolean,\n routeOpts?: RouteOptions,\n permissions?: Map<string, boolean>,\n) => {\n const [canEdit, canDelete, comments] = await Promise.all([\n permissions?.get(`edit:answer:${resource.id}`) ??\n (checkRights\n ? permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaEditAnswerPermission, resource }],\n {\n credentials,\n },\n )\n .then(r => r[0])\n : undefined),\n permissions?.get(`delete:answer:${resource.id}`) ??\n (checkRights\n ? permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaDeleteAnswerPermission, resource }],\n {\n credentials,\n },\n )\n .then(r => r[0])\n : undefined),\n mapResourceComments(\n request,\n resource,\n permissionMgr,\n credentials,\n username,\n checkRights,\n permissions,\n ),\n ]);\n\n resource.ownVote = resource.votes?.find(v => v.author === username)?.score;\n resource.own = resource.author === username;\n resource.canEdit = canEdit;\n resource.canDelete = canDelete;\n resource.expert = resource.experts?.includes(resource.author);\n resource.comments = comments;\n\n // Filter entities on the associated post if present\n if (resource.post && routeOpts) {\n resource.post.entities = await filterEntitiesByPermissions(\n resource.post.entities,\n routeOpts,\n credentials,\n );\n }\n\n return resource;\n};\n\nconst mapPostAnswers = async (\n request: Request<unknown>,\n resource: PostResponse,\n permissionMgr: PermissionManager,\n credentials: BackstageCredentials,\n username: string,\n checkRights?: boolean,\n permissions?: Map<string, boolean>,\n) => {\n const answersArray = resource.answers ?? [];\n const comments = await Promise.all(\n answersArray.map(async (a: Answer) => {\n return mapResourceComments(\n request,\n a,\n permissionMgr,\n credentials,\n username,\n checkRights,\n permissions,\n );\n }),\n );\n\n return Promise.all(\n answersArray.map(async (a: Answer, index: number) => {\n const canEdit =\n permissions?.get(`edit:answer:${a.id}`) ??\n (checkRights\n ? await permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaEditAnswerPermission, resource: a }],\n { credentials },\n )\n .then(r => r[0])\n : false);\n const canDelete =\n permissions?.get(`delete:answer:${a.id}`) ??\n (checkRights\n ? await permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaDeleteAnswerPermission, resource: a }],\n { credentials },\n )\n .then(r => r[0])\n : false);\n\n return {\n ...a,\n ownVote: a.votes?.find(v => v.author === username)?.score,\n own: a.author === username,\n canEdit,\n canDelete,\n expert: a.experts?.includes(resource.author),\n comments: comments[index],\n };\n }),\n );\n};\n\nconst mapPostAdditionalFields = async (\n request: Request<unknown>,\n resource: PostResponse,\n permissionMgr: PermissionManager,\n credentials: BackstageCredentials,\n username: string,\n checkRights?: boolean,\n routeOpts?: RouteOptions,\n permissions?: Map<string, boolean>,\n) => {\n resource.ownVote = resource.votes?.find(v => v.author === username)?.score;\n resource.own = resource.author === username;\n\n const [canEdit, canDelete, answers, comments, filteredEntities] =\n await Promise.all([\n permissions?.get(`edit:post:${resource.id}`) ??\n (checkRights\n ? permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaEditPostPermission, resource }],\n {\n credentials,\n },\n )\n .then(r => r[0])\n : undefined),\n permissions?.get(`delete:post:${resource.id}`) ??\n (checkRights\n ? permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaDeletePostPermission, resource }],\n {\n credentials,\n },\n )\n .then(r => r[0])\n : undefined),\n mapPostAnswers(\n request,\n resource,\n permissionMgr,\n credentials,\n username,\n checkRights,\n permissions,\n ),\n mapResourceComments(\n request,\n resource,\n permissionMgr,\n credentials,\n username,\n checkRights,\n permissions,\n ),\n routeOpts\n ? filterEntitiesByPermissions(resource.entities, routeOpts, credentials)\n : resource.entities,\n ]);\n resource.canEdit = canEdit;\n resource.canDelete = canDelete;\n resource.answers = answers;\n resource.comments = comments;\n resource.entities = filteredEntities;\n return resource;\n};\n\nconst authorizeResourcePermissions = async (\n request: Request<unknown>,\n permissionMgr: PermissionManager,\n credentials: BackstageCredentials,\n posts: PostResponse[],\n collections: CollectionResponse[],\n tags: TagResponse[],\n answers: AnswerResponse[],\n) => {\n const allAnswers = [\n ...answers,\n ...posts.flatMap(p => (p.answers ? p.answers : [])),\n ];\n const allComments = [\n ...posts.flatMap(p => (p.comments ? p.comments : [])),\n ...allAnswers.flatMap(a => (a.comments ? a.comments : [])),\n ];\n\n const [\n [postEditPerms, postDeletePerms],\n [collectionEditPerms, collectionDeletePerms],\n [tagEditPerms, tagDeletePerms],\n [answerEditPerms, answerDeletePerms],\n [commentEditPerms, commentDeletePerms],\n ] = await Promise.all([\n posts.length > 0\n ? permissionMgr\n .authorizeBoolean(\n request,\n [\n ...posts.map(r => ({\n permission: qetaEditPostPermission,\n resource: r,\n })),\n ...posts.map(r => ({\n permission: qetaDeletePostPermission,\n resource: r,\n })),\n ],\n { credentials },\n )\n .then(results => [\n results.slice(0, posts.length),\n results.slice(posts.length),\n ])\n : Promise.resolve([[], []]),\n collections.length > 0\n ? permissionMgr\n .authorizeBoolean(\n request,\n [\n ...collections.map(r => ({\n permission: qetaEditCollectionPermission,\n resource: r,\n })),\n ...collections.map(r => ({\n permission: qetaDeleteCollectionPermission,\n resource: r,\n })),\n ],\n { credentials },\n )\n .then(results => [\n results.slice(0, collections.length),\n results.slice(collections.length),\n ])\n : Promise.resolve([[], []]),\n tags.length > 0\n ? permissionMgr\n .authorizeBoolean(\n request,\n [\n ...tags.map(r => ({\n permission: qetaEditTagPermission,\n resource: r,\n })),\n ...tags.map(r => ({\n permission: qetaDeleteTagPermission,\n resource: r,\n })),\n ],\n { credentials },\n )\n .then(results => [\n results.slice(0, tags.length),\n results.slice(tags.length),\n ])\n : Promise.resolve([[], []]),\n allAnswers.length > 0\n ? permissionMgr\n .authorizeBoolean(\n request,\n [\n ...allAnswers.map(r => ({\n permission: qetaEditAnswerPermission,\n resource: r,\n })),\n ...allAnswers.map(r => ({\n permission: qetaDeleteAnswerPermission,\n resource: r,\n })),\n ],\n { credentials },\n )\n .then(results => [\n results.slice(0, allAnswers.length),\n results.slice(allAnswers.length),\n ])\n : Promise.resolve([[], []]),\n allComments.length > 0\n ? permissionMgr\n .authorizeBoolean(\n request,\n [\n ...allComments.map(r => ({\n permission: qetaEditCommentPermission,\n resource: r,\n })),\n ...allComments.map(r => ({\n permission: qetaDeleteCommentPermission,\n resource: r,\n })),\n ],\n { credentials },\n )\n .then(results => [\n results.slice(0, allComments.length),\n results.slice(allComments.length),\n ])\n : Promise.resolve([[], []]),\n ]);\n\n const permissions = new Map<string, boolean>();\n posts.forEach((r, i) => {\n permissions.set(`edit:post:${r.id}`, postEditPerms[i]);\n permissions.set(`delete:post:${r.id}`, postDeletePerms[i]);\n });\n collections.forEach((r, i) => {\n permissions.set(`edit:collection:${r.id}`, collectionEditPerms[i]);\n permissions.set(`delete:collection:${r.id}`, collectionDeletePerms[i]);\n });\n tags.forEach((r, i) => {\n permissions.set(`edit:tag:${r.id}`, tagEditPerms[i]);\n permissions.set(`delete:tag:${r.id}`, tagDeletePerms[i]);\n });\n allAnswers.forEach((r, i) => {\n permissions.set(`edit:answer:${r.id}`, answerEditPerms[i]);\n permissions.set(`delete:answer:${r.id}`, answerDeletePerms[i]);\n });\n allComments.forEach((r, i) => {\n permissions.set(`edit:comment:${r.id}`, commentEditPerms[i]);\n permissions.set(`delete:comment:${r.id}`, commentDeletePerms[i]);\n });\n\n return permissions;\n};\n\nexport const mapAdditionalFields = async (\n request: Request<unknown>,\n resources: (MaybePost | MaybeAnswer | MaybeTag | MaybeCollection)[],\n routeOpts: RouteOptions,\n options?: {\n checkRights?: boolean;\n creds?: BackstageCredentials;\n username?: string;\n },\n) => {\n if (!resources || resources.length === 0) {\n return resources;\n }\n\n const { creds, username, checkRights = true } = options ?? {};\n const { permissionMgr } = routeOpts;\n const credentials =\n creds ?? (await permissionMgr.getCredentials(request, true));\n const user =\n username ??\n (await routeOpts.permissionMgr.getUsername(request, true, credentials));\n\n const validResources = resources.filter(\n (\n r,\n ): r is PostResponse | AnswerResponse | TagResponse | CollectionResponse =>\n r !== null && r !== undefined,\n );\n\n const posts = validResources.filter(isPost) as PostResponse[];\n const collections = validResources.filter(\n isCollection,\n ) as CollectionResponse[];\n const tags = validResources.filter(isTag) as TagResponse[];\n const answers = validResources.filter(isAnswer) as AnswerResponse[];\n\n let permissions: Map<string, boolean> = new Map();\n\n if (checkRights) {\n permissions = await authorizeResourcePermissions(\n request,\n permissionMgr,\n credentials,\n posts,\n collections,\n tags,\n answers,\n );\n }\n\n await Promise.all(\n resources.map(async resource => {\n if (!resource) {\n return resource;\n }\n resource.self = getResourceUrl(resource, routeOpts.config, true);\n\n if (isTag(resource)) {\n return mapTagAdditionalFields(\n request,\n resource,\n permissionMgr,\n credentials,\n checkRights,\n permissions,\n );\n } else if (isCollection(resource)) {\n return mapCollectionAdditionalFields(\n request,\n resource,\n permissionMgr,\n credentials,\n checkRights,\n routeOpts,\n permissions,\n );\n } else if (isPost(resource)) {\n return mapPostAdditionalFields(\n request,\n resource,\n permissionMgr,\n credentials,\n user,\n checkRights,\n routeOpts,\n permissions,\n );\n } else if (isAnswer(resource)) {\n return mapAnswerAdditionalFields(\n request,\n resource,\n permissionMgr,\n credentials,\n user,\n checkRights,\n routeOpts,\n permissions,\n );\n }\n return resource;\n }),\n );\n\n return resources;\n};\nexport const stringDateTime = (dayString: string) => {\n const dateTimePeriod = Number(dayString.toString().slice(0, -1));\n return format(subDays(new Date(), dateTimePeriod), 'yyyy-MM-dd');\n};\n\nexport const getS3Client = (config: Config) => {\n const accessKeyId = config.getOptionalString('qeta.storage.accessKeyId');\n const secretAccessKey = config.getOptionalString(\n 'qeta.storage.secretAccessKey',\n );\n const region = config.getOptionalString('qeta.storage.region');\n const sessionToken = config.getOptionalString('qeta.storage.sessionToken');\n const endpoint = config.getOptionalString('qeta.storage.endpoint');\n const httpsProxy = config.getOptionalString('qeta.storage.httpsProxy');\n const forcePathStyle = config.getOptionalBoolean(\n 'qeta.storage.forcePathStyle',\n );\n const maxAttempts = config.getOptionalNumber('qeta.storage.maxAttempts');\n\n let credentials;\n if (accessKeyId && secretAccessKey) {\n credentials = {\n accessKeyId,\n secretAccessKey,\n sessionToken,\n };\n }\n return new S3Client({\n customUserAgent: 'backstage-aws-drodil-qeta-s3-storage',\n ...(credentials && { credentials }),\n ...(region && { region }),\n ...(endpoint && { endpoint }),\n ...(forcePathStyle && { forcePathStyle }),\n ...(maxAttempts && { maxAttempts }),\n ...(httpsProxy && {\n requestHandler: new NodeHttpHandler({\n httpsAgent: new HttpsProxyAgent({ proxy: httpsProxy }),\n }),\n }),\n });\n};\n\nexport const getAzureBlobServiceClient = (config: Config) => {\n const accountName = config.getOptionalString(\n 'qeta.storage.blobStorageAccountName',\n );\n const connectionString = config.getOptionalString(\n 'qeta.storage.blobStorageConnectionString',\n );\n if (connectionString) {\n return BlobServiceClient.fromConnectionString(connectionString);\n } else if (accountName) {\n return new BlobServiceClient(\n `https://${accountName}.blob.core.windows.net`,\n new DefaultAzureCredential(),\n );\n }\n\n throw new Error(\n 'Either account name or connection string must be provided for Azure Blob Storage',\n );\n};\n"],"names":["isTag","isCollection","isAnswer","isPost","selectByPostType","stringifyEntityRef","createConditionTransformer","rules","qetaEditTagPermission","qetaDeleteTagPermission","qetaEditCollectionPermission","qetaDeleteCollectionPermission","qetaEditCommentPermission","qetaDeleteCommentPermission","compact","qetaEditAnswerPermission","qetaDeleteAnswerPermission","qetaEditPostPermission","qetaDeletePostPermission","format","subDays","S3Client","NodeHttpHandler","HttpsProxyAgent","BlobServiceClient","DefaultAzureCredential"],"mappings":";;;;;;;;;;;;;;AAgDO,MAAM,cAAiB,GAAA,CAC5B,QACA,EAAA,MAAA,EACA,QACG,KAAA;AACH,EAAA,IAAI,CAAC,QAAU,EAAA;AACb,IAAO,OAAA,KAAA,CAAA;AAAA;AAET,EAAM,MAAA,QAAA,GAAA,CACJ,OAAO,iBAAkB,CAAA,YAAY,KAAK,MAC1C,EAAA,UAAA,CAAW,kBAAkB,EAAE,CAAA;AACjC,EAAA,MAAM,OAAU,GAAA,QAAA,GACZ,CAAG,EAAA,MAAA,CAAO,iBAAkB,CAAA,aAAa,CAAK,IAAA,EAAE,CAAI,CAAA,EAAA,QAAQ,CAC5D,CAAA,GAAA,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAA;AAEhB,EAAI,IAAAA,+BAAA,CAAM,QAAQ,CAAG,EAAA;AACnB,IAAA,OAAO,CAAG,EAAA,OAAO,CAAS,MAAA,EAAA,QAAA,CAAS,GAAG,CAAA,CAAA;AAAA,GACxC,MAAA,IAAWC,sCAAa,CAAA,QAAQ,CAAG,EAAA;AACjC,IAAA,OAAO,CAAG,EAAA,OAAO,CAAe,YAAA,EAAA,QAAA,CAAS,EAAE,CAAA,CAAA;AAAA,GAC7C,MAAA,IAAWC,kCAAS,CAAA,QAAQ,CAAG,EAAA;AAC7B,IAAA,OAAO,GAAG,OAAO,CAAA,WAAA,EAAc,SAAS,MAAM,CAAA,QAAA,EAAW,SAAS,EAAE,CAAA,CAAA;AAAA,GACtE,MAAA,IAAWC,gCAAO,CAAA,QAAQ,CAAG,EAAA;AAC3B,IAAA,MAAM,aAAgB,GAAA,CAAA,EAAG,OAAO,CAAA,WAAA,EAAc,SAAS,EAAE,CAAA,CAAA;AACzD,IAAA,MAAM,YAAe,GAAA,CAAA,EAAG,OAAO,CAAA,UAAA,EAAa,SAAS,EAAE,CAAA,CAAA;AACvD,IAAA,MAAM,SAAY,GAAA,CAAA,EAAG,OAAO,CAAA,OAAA,EAAU,SAAS,EAAE,CAAA,CAAA;AACjD,IAAO,OAAAC,0CAAA;AAAA,MACL,QAAS,CAAA,IAAA;AAAA,MACT,aAAA;AAAA,MACA,YAAA;AAAA,MACA;AAAA,KACF;AAAA;AAEF,EAAO,OAAA,KAAA,CAAA;AACT;AAOA,MAAM,2BAA8B,GAAA,OAClC,UACA,EAAA,SAAA,EACA,WACkC,KAAA;AAClC,EAAA,IAAI,CAAC,UAAA,IAAc,UAAW,CAAA,MAAA,KAAW,CAAG,EAAA;AAC1C,IAAO,OAAA,UAAA;AAAA;AAGT,EAAI,IAAA;AAEF,IAAA,MAAM,EAAE,KAAM,EAAA,GAAI,MAAM,SAAA,CAAU,KAAK,qBAAsB,CAAA;AAAA,MAC3D,UAAY,EAAA,WAAA;AAAA,MACZ,cAAgB,EAAA;AAAA,KACjB,CAAA;AAID,IAAM,MAAA,QAAA,GAAW,MAAM,SAAA,CAAU,OAAQ,CAAA,iBAAA;AAAA,MACvC,EAAE,UAAW,EAAA;AAAA,MACb,EAAE,KAAM;AAAA,KACV;AAGA,IAAO,OAAA,QAAA,CAAS,MACb,MAAO,CAAA,CAAA,MAAA,KAAU,WAAW,KAAS,CAAA,CAAA,CACrC,IAAIC,+BAAkB,CAAA;AAAA,WAClB,KAAO,EAAA;AAEd,IAAU,SAAA,CAAA,MAAA,CAAO,IAAK,CAAA,yCAAA,EAA2C,KAAK,CAAA;AACtE,IAAA,OAAO,EAAC;AAAA;AAEZ,CAAA;AAEa,MAAA,UAAA,GAAa,OACxB,GAAA,EACA,OACkB,KAAA;AAClB,EAAM,MAAA,kBAAA,GAAqB,QAAQ,MAAO,CAAA,kBAAA;AAAA,IACxC;AAAA,GACF;AAEA,EAAI,IAAA,kBAAA,IAAsB,GAAI,CAAA,IAAA,CAAK,OAAS,EAAA;AAC1C,IAAA,OAAO,IAAI,IAAA,CAAK,GAAI,CAAA,IAAA,CAAK,OAAO,CAAA;AAAA;AAGlC,EAAA,2BAAW,IAAK,EAAA;AAClB;AAsBO,MAAM,mBACX,GAAAC,+CAAA,CAA2B,MAAO,CAAA,MAAA,CAAOC,6BAAK,CAAC;AAEjD,MAAM,yBAAyB,OAC7B,OAAA,EACA,UACA,aACA,EAAA,WAAA,EACA,aACA,WACG,KAAA;AACH,EAAA,MAAM,CAAC,OAAS,EAAA,SAAS,CAAI,GAAA,MAAM,QAAQ,GAAI,CAAA;AAAA,IAC7C,WAAA,EAAa,IAAI,CAAY,SAAA,EAAA,QAAA,CAAS,EAAE,CAAE,CAAA,CAAA,KACvC,cACG,aACG,CAAA,gBAAA;AAAA,MACC,OAAA;AAAA,MACA,CAAC,EAAE,UAAY,EAAAC,+CAAA,EAAuB,UAAU,CAAA;AAAA,MAChD;AAAA,QACE;AAAA;AACF,MAED,IAAK,CAAA,CAAA,CAAA,KAAK,CAAE,CAAA,CAAC,CAAC,CACjB,GAAA,KAAA,CAAA,CAAA;AAAA,IACN,WAAA,EAAa,IAAI,CAAc,WAAA,EAAA,QAAA,CAAS,EAAE,CAAE,CAAA,CAAA,KACzC,cACG,aACG,CAAA,gBAAA;AAAA,MACC,OAAA;AAAA,MACA,CAAC,EAAE,UAAY,EAAAC,iDAAA,EAAyB,UAAU,CAAA;AAAA,MAClD;AAAA,QACE;AAAA;AACF,MAED,IAAK,CAAA,CAAA,CAAA,KAAK,CAAE,CAAA,CAAC,CAAC,CACjB,GAAA,KAAA,CAAA;AAAA,GACP,CAAA;AAED,EAAA,QAAA,CAAS,OAAU,GAAA,OAAA;AACnB,EAAA,QAAA,CAAS,SAAY,GAAA,SAAA;AACrB,EAAO,OAAA,QAAA;AACT,CAAA;AAEA,MAAM,6BAAA,GAAgC,OACpC,OACA,EAAA,QAAA,EACA,eACA,WACA,EAAA,WAAA,EACA,WACA,WACG,KAAA;AACH,EAAA,MAAM,CAAC,OAAS,EAAA,SAAA,EAAW,gBAAgB,CAAI,GAAA,MAAM,QAAQ,GAAI,CAAA;AAAA,IAC/D,WAAA,EAAa,IAAI,CAAmB,gBAAA,EAAA,QAAA,CAAS,EAAE,CAAE,CAAA,CAAA,KAC9C,cACG,aACG,CAAA,gBAAA;AAAA,MACC,OAAA;AAAA,MACA,CAAC,EAAE,UAAY,EAAAC,sDAAA,EAA8B,UAAU,CAAA;AAAA,MACvD;AAAA,QACE;AAAA;AACF,MAED,IAAK,CAAA,CAAA,CAAA,KAAK,CAAE,CAAA,CAAC,CAAC,CACjB,GAAA,KAAA,CAAA,CAAA;AAAA,IACN,WAAA,EAAa,IAAI,CAAqB,kBAAA,EAAA,QAAA,CAAS,EAAE,CAAE,CAAA,CAAA,KAChD,cACG,aACG,CAAA,gBAAA;AAAA,MACC,OAAA;AAAA,MACA,CAAC,EAAE,UAAY,EAAAC,wDAAA,EAAgC,UAAU,CAAA;AAAA,MACzD;AAAA,QACE;AAAA;AACF,MAED,IAAK,CAAA,CAAA,CAAA,KAAK,CAAE,CAAA,CAAC,CAAC,CACjB,GAAA,KAAA,CAAA,CAAA;AAAA,IACN,YACI,2BAA4B,CAAA,QAAA,CAAS,UAAU,SAAW,EAAA,WAAW,IACrE,QAAS,CAAA;AAAA,GACd,CAAA;AAED,EAAA,QAAA,CAAS,OAAU,GAAA,OAAA;AACnB,EAAA,QAAA,CAAS,SAAY,GAAA,SAAA;AACrB,EAAA,QAAA,CAAS,QAAW,GAAA,gBAAA;AAEpB,EAAI,IAAA,QAAA,CAAS,SAAS,SAAW,EAAA;AAC/B,IAAA,MAAM,OAAQ,CAAA,GAAA;AAAA,MACZ,QAAS,CAAA,KAAA,CAAM,GAAI,CAAA,OAAM,IAAQ,KAAA;AAC/B,QAAA,IAAA,CAAK,WAAW,MAAM,2BAAA;AAAA,UACpB,IAAK,CAAA,QAAA;AAAA,UACL,SAAA;AAAA,UACA;AAAA,SACF;AAAA,OACD;AAAA,KACH;AAAA;AAGF,EAAO,OAAA,QAAA;AACT,CAAA;AAEA,MAAM,mBAAA,GAAsB,OAC1B,OACA,EAAA,QAAA,EACA,eACA,WACA,EAAA,QAAA,EACA,aACA,WACG,KAAA;AACH,EAAM,MAAA,UAAA,GAAa,QAAS,CAAA,QAAA,IAAY,EAAC;AACzC,EAAM,MAAA,QAAA,GAA+B,MAAM,OAAQ,CAAA,GAAA;AAAA,IACjD,UAAA,CAAW,GAAI,CAAA,OAAO,CAAe,KAAA;AACnC,MAAM,MAAA,OAAA,GACJ,WAAa,EAAA,GAAA,CAAI,CAAgB,aAAA,EAAA,CAAA,CAAE,EAAE,CAAE,CAAA,CAAA,KACtC,WACG,GAAA,MAAM,aACH,CAAA,gBAAA;AAAA,QACC,OAAA;AAAA,QACA,CAAC,EAAE,UAAA,EAAYC,mDAA2B,EAAA,QAAA,EAAU,GAAG,CAAA;AAAA,QACvD,EAAE,WAAY;AAAA,QAEf,IAAK,CAAA,CAAA,CAAA,KAAK,CAAE,CAAA,CAAC,CAAC,CACjB,GAAA,KAAA,CAAA;AACN,MAAM,MAAA,SAAA,GACJ,WAAa,EAAA,GAAA,CAAI,CAAkB,eAAA,EAAA,CAAA,CAAE,EAAE,CAAE,CAAA,CAAA,KACxC,WACG,GAAA,MAAM,aACH,CAAA,gBAAA;AAAA,QACC,OAAA;AAAA,QACA,CAAC,EAAE,UAAA,EAAYC,qDAA6B,EAAA,QAAA,EAAU,GAAG,CAAA;AAAA,QACzD,EAAE,WAAY;AAAA,QAEf,IAAK,CAAA,CAAA,CAAA,KAAK,CAAE,CAAA,CAAC,CAAC,CACjB,GAAA,KAAA,CAAA;AAEN,MAAO,OAAA;AAAA,QACL,GAAG,CAAA;AAAA,QACH,GAAA,EAAK,EAAE,MAAW,KAAA,QAAA;AAAA,QAClB,MAAQ,EAAA,CAAA,CAAE,OAAS,EAAA,QAAA,CAAS,EAAE,MAAM,CAAA;AAAA,QACpC,OAAA;AAAA,QACA;AAAA,OACF;AAAA,KACD;AAAA,GACH;AACA,EAAA,OAAOC,eAAQ,QAAQ,CAAA;AACzB,CAAA;AAEA,MAAM,yBAAA,GAA4B,OAChC,OACA,EAAA,QAAA,EACA,eACA,WACA,EAAA,QAAA,EACA,WACA,EAAA,SAAA,EACA,WACG,KAAA;AACH,EAAA,MAAM,CAAC,OAAS,EAAA,SAAA,EAAW,QAAQ,CAAI,GAAA,MAAM,QAAQ,GAAI,CAAA;AAAA,IACvD,WAAA,EAAa,IAAI,CAAe,YAAA,EAAA,QAAA,CAAS,EAAE,CAAE,CAAA,CAAA,KAC1C,cACG,aACG,CAAA,gBAAA;AAAA,MACC,OAAA;AAAA,MACA,CAAC,EAAE,UAAY,EAAAC,kDAAA,EAA0B,UAAU,CAAA;AAAA,MACnD;AAAA,QACE;AAAA;AACF,MAED,IAAK,CAAA,CAAA,CAAA,KAAK,CAAE,CAAA,CAAC,CAAC,CACjB,GAAA,KAAA,CAAA,CAAA;AAAA,IACN,WAAA,EAAa,IAAI,CAAiB,cAAA,EAAA,QAAA,CAAS,EAAE,CAAE,CAAA,CAAA,KAC5C,cACG,aACG,CAAA,gBAAA;AAAA,MACC,OAAA;AAAA,MACA,CAAC,EAAE,UAAY,EAAAC,oDAAA,EAA4B,UAAU,CAAA;AAAA,MACrD;AAAA,QACE;AAAA;AACF,MAED,IAAK,CAAA,CAAA,CAAA,KAAK,CAAE,CAAA,CAAC,CAAC,CACjB,GAAA,KAAA,CAAA,CAAA;AAAA,IACN,mBAAA;AAAA,MACE,OAAA;AAAA,MACA,QAAA;AAAA,MACA,aAAA;AAAA,MACA,WAAA;AAAA,MACA,QAAA;AAAA,MACA,WAAA;AAAA,MACA;AAAA;AACF,GACD,CAAA;AAED,EAAS,QAAA,CAAA,OAAA,GAAU,SAAS,KAAO,EAAA,IAAA,CAAK,OAAK,CAAE,CAAA,MAAA,KAAW,QAAQ,CAAG,EAAA,KAAA;AACrE,EAAS,QAAA,CAAA,GAAA,GAAM,SAAS,MAAW,KAAA,QAAA;AACnC,EAAA,QAAA,CAAS,OAAU,GAAA,OAAA;AACnB,EAAA,QAAA,CAAS,SAAY,GAAA,SAAA;AACrB,EAAA,QAAA,CAAS,MAAS,GAAA,QAAA,CAAS,OAAS,EAAA,QAAA,CAAS,SAAS,MAAM,CAAA;AAC5D,EAAA,QAAA,CAAS,QAAW,GAAA,QAAA;AAGpB,EAAI,IAAA,QAAA,CAAS,QAAQ,SAAW,EAAA;AAC9B,IAAS,QAAA,CAAA,IAAA,CAAK,WAAW,MAAM,2BAAA;AAAA,MAC7B,SAAS,IAAK,CAAA,QAAA;AAAA,MACd,SAAA;AAAA,MACA;AAAA,KACF;AAAA;AAGF,EAAO,OAAA,QAAA;AACT,CAAA;AAEA,MAAM,cAAA,GAAiB,OACrB,OACA,EAAA,QAAA,EACA,eACA,WACA,EAAA,QAAA,EACA,aACA,WACG,KAAA;AACH,EAAM,MAAA,YAAA,GAAe,QAAS,CAAA,OAAA,IAAW,EAAC;AAC1C,EAAM,MAAA,QAAA,GAAW,MAAM,OAAQ,CAAA,GAAA;AAAA,IAC7B,YAAA,CAAa,GAAI,CAAA,OAAO,CAAc,KAAA;AACpC,MAAO,OAAA,mBAAA;AAAA,QACL,OAAA;AAAA,QACA,CAAA;AAAA,QACA,aAAA;AAAA,QACA,WAAA;AAAA,QACA,QAAA;AAAA,QACA,WAAA;AAAA,QACA;AAAA,OACF;AAAA,KACD;AAAA,GACH;AAEA,EAAA,OAAO,OAAQ,CAAA,GAAA;AAAA,IACb,YAAa,CAAA,GAAA,CAAI,OAAO,CAAA,EAAW,KAAkB,KAAA;AACnD,MAAM,MAAA,OAAA,GACJ,WAAa,EAAA,GAAA,CAAI,CAAe,YAAA,EAAA,CAAA,CAAE,EAAE,CAAE,CAAA,CAAA,KACrC,WACG,GAAA,MAAM,aACH,CAAA,gBAAA;AAAA,QACC,OAAA;AAAA,QACA,CAAC,EAAE,UAAA,EAAYD,kDAA0B,EAAA,QAAA,EAAU,GAAG,CAAA;AAAA,QACtD,EAAE,WAAY;AAAA,QAEf,IAAK,CAAA,CAAA,CAAA,KAAK,CAAE,CAAA,CAAC,CAAC,CACjB,GAAA,KAAA,CAAA;AACN,MAAM,MAAA,SAAA,GACJ,WAAa,EAAA,GAAA,CAAI,CAAiB,cAAA,EAAA,CAAA,CAAE,EAAE,CAAE,CAAA,CAAA,KACvC,WACG,GAAA,MAAM,aACH,CAAA,gBAAA;AAAA,QACC,OAAA;AAAA,QACA,CAAC,EAAE,UAAA,EAAYC,oDAA4B,EAAA,QAAA,EAAU,GAAG,CAAA;AAAA,QACxD,EAAE,WAAY;AAAA,QAEf,IAAK,CAAA,CAAA,CAAA,KAAK,CAAE,CAAA,CAAC,CAAC,CACjB,GAAA,KAAA,CAAA;AAEN,MAAO,OAAA;AAAA,QACL,GAAG,CAAA;AAAA,QACH,OAAA,EAAS,EAAE,KAAO,EAAA,IAAA,CAAK,OAAK,CAAE,CAAA,MAAA,KAAW,QAAQ,CAAG,EAAA,KAAA;AAAA,QACpD,GAAA,EAAK,EAAE,MAAW,KAAA,QAAA;AAAA,QAClB,OAAA;AAAA,QACA,SAAA;AAAA,QACA,MAAQ,EAAA,CAAA,CAAE,OAAS,EAAA,QAAA,CAAS,SAAS,MAAM,CAAA;AAAA,QAC3C,QAAA,EAAU,SAAS,KAAK;AAAA,OAC1B;AAAA,KACD;AAAA,GACH;AACF,CAAA;AAEA,MAAM,uBAAA,GAA0B,OAC9B,OACA,EAAA,QAAA,EACA,eACA,WACA,EAAA,QAAA,EACA,WACA,EAAA,SAAA,EACA,WACG,KAAA;AACH,EAAS,QAAA,CAAA,OAAA,GAAU,SAAS,KAAO,EAAA,IAAA,CAAK,OAAK,CAAE,CAAA,MAAA,KAAW,QAAQ,CAAG,EAAA,KAAA;AACrE,EAAS,QAAA,CAAA,GAAA,GAAM,SAAS,MAAW,KAAA,QAAA;AAEnC,EAAM,MAAA,CAAC,SAAS,SAAW,EAAA,OAAA,EAAS,UAAU,gBAAgB,CAAA,GAC5D,MAAM,OAAA,CAAQ,GAAI,CAAA;AAAA,IAChB,WAAA,EAAa,IAAI,CAAa,UAAA,EAAA,QAAA,CAAS,EAAE,CAAE,CAAA,CAAA,KACxC,cACG,aACG,CAAA,gBAAA;AAAA,MACC,OAAA;AAAA,MACA,CAAC,EAAE,UAAY,EAAAC,gDAAA,EAAwB,UAAU,CAAA;AAAA,MACjD;AAAA,QACE;AAAA;AACF,MAED,IAAK,CAAA,CAAA,CAAA,KAAK,CAAE,CAAA,CAAC,CAAC,CACjB,GAAA,KAAA,CAAA,CAAA;AAAA,IACN,WAAA,EAAa,IAAI,CAAe,YAAA,EAAA,QAAA,CAAS,EAAE,CAAE,CAAA,CAAA,KAC1C,cACG,aACG,CAAA,gBAAA;AAAA,MACC,OAAA;AAAA,MACA,CAAC,EAAE,UAAY,EAAAC,kDAAA,EAA0B,UAAU,CAAA;AAAA,MACnD;AAAA,QACE;AAAA;AACF,MAED,IAAK,CAAA,CAAA,CAAA,KAAK,CAAE,CAAA,CAAC,CAAC,CACjB,GAAA,KAAA,CAAA,CAAA;AAAA,IACN,cAAA;AAAA,MACE,OAAA;AAAA,MACA,QAAA;AAAA,MACA,aAAA;AAAA,MACA,WAAA;AAAA,MACA,QAAA;AAAA,MACA,WAAA;AAAA,MACA;AAAA,KACF;AAAA,IACA,mBAAA;AAAA,MACE,OAAA;AAAA,MACA,QAAA;AAAA,MACA,aAAA;AAAA,MACA,WAAA;AAAA,MACA,QAAA;AAAA,MACA,WAAA;AAAA,MACA;AAAA,KACF;AAAA,IACA,YACI,2BAA4B,CAAA,QAAA,CAAS,UAAU,SAAW,EAAA,WAAW,IACrE,QAAS,CAAA;AAAA,GACd,CAAA;AACH,EAAA,QAAA,CAAS,OAAU,GAAA,OAAA;AACnB,EAAA,QAAA,CAAS,SAAY,GAAA,SAAA;AACrB,EAAA,QAAA,CAAS,OAAU,GAAA,OAAA;AACnB,EAAA,QAAA,CAAS,QAAW,GAAA,QAAA;AACpB,EAAA,QAAA,CAAS,QAAW,GAAA,gBAAA;AACpB,EAAO,OAAA,QAAA;AACT,CAAA;AAEA,MAAM,4BAAA,GAA+B,OACnC,OACA,EAAA,aAAA,EACA,aACA,KACA,EAAA,WAAA,EACA,MACA,OACG,KAAA;AACH,EAAA,MAAM,UAAa,GAAA;AAAA,IACjB,GAAG,OAAA;AAAA,IACH,GAAG,MAAM,OAAQ,CAAA,CAAA,CAAA,KAAM,EAAE,OAAU,GAAA,CAAA,CAAE,OAAU,GAAA,EAAG;AAAA,GACpD;AACA,EAAA,MAAM,WAAc,GAAA;AAAA,IAClB,GAAG,MAAM,OAAQ,CAAA,CAAA,CAAA,KAAM,EAAE,QAAW,GAAA,CAAA,CAAE,QAAW,GAAA,EAAG,CAAA;AAAA,IACpD,GAAG,WAAW,OAAQ,CAAA,CAAA,CAAA,KAAM,EAAE,QAAW,GAAA,CAAA,CAAE,QAAW,GAAA,EAAG;AAAA,GAC3D;AAEA,EAAM,MAAA;AAAA,IACJ,CAAC,eAAe,eAAe,CAAA;AAAA,IAC/B,CAAC,qBAAqB,qBAAqB,CAAA;AAAA,IAC3C,CAAC,cAAc,cAAc,CAAA;AAAA,IAC7B,CAAC,iBAAiB,iBAAiB,CAAA;AAAA,IACnC,CAAC,kBAAkB,kBAAkB;AAAA,GACvC,GAAI,MAAM,OAAA,CAAQ,GAAI,CAAA;AAAA,IACpB,KAAA,CAAM,MAAS,GAAA,CAAA,GACX,aACG,CAAA,gBAAA;AAAA,MACC,OAAA;AAAA,MACA;AAAA,QACE,GAAG,KAAM,CAAA,GAAA,CAAI,CAAM,CAAA,MAAA;AAAA,UACjB,UAAY,EAAAD,gDAAA;AAAA,UACZ,QAAU,EAAA;AAAA,SACV,CAAA,CAAA;AAAA,QACF,GAAG,KAAM,CAAA,GAAA,CAAI,CAAM,CAAA,MAAA;AAAA,UACjB,UAAY,EAAAC,kDAAA;AAAA,UACZ,QAAU,EAAA;AAAA,SACV,CAAA;AAAA,OACJ;AAAA,MACA,EAAE,WAAY;AAAA,KAChB,CACC,KAAK,CAAW,OAAA,KAAA;AAAA,MACf,OAAQ,CAAA,KAAA,CAAM,CAAG,EAAA,KAAA,CAAM,MAAM,CAAA;AAAA,MAC7B,OAAA,CAAQ,KAAM,CAAA,KAAA,CAAM,MAAM;AAAA,KAC3B,IACH,OAAQ,CAAA,OAAA,CAAQ,CAAC,EAAC,EAAG,EAAE,CAAC,CAAA;AAAA,IAC5B,WAAA,CAAY,MAAS,GAAA,CAAA,GACjB,aACG,CAAA,gBAAA;AAAA,MACC,OAAA;AAAA,MACA;AAAA,QACE,GAAG,WAAY,CAAA,GAAA,CAAI,CAAM,CAAA,MAAA;AAAA,UACvB,UAAY,EAAAR,sDAAA;AAAA,UACZ,QAAU,EAAA;AAAA,SACV,CAAA,CAAA;AAAA,QACF,GAAG,WAAY,CAAA,GAAA,CAAI,CAAM,CAAA,MAAA;AAAA,UACvB,UAAY,EAAAC,wDAAA;AAAA,UACZ,QAAU,EAAA;AAAA,SACV,CAAA;AAAA,OACJ;AAAA,MACA,EAAE,WAAY;AAAA,KAChB,CACC,KAAK,CAAW,OAAA,KAAA;AAAA,MACf,OAAQ,CAAA,KAAA,CAAM,CAAG,EAAA,WAAA,CAAY,MAAM,CAAA;AAAA,MACnC,OAAA,CAAQ,KAAM,CAAA,WAAA,CAAY,MAAM;AAAA,KACjC,IACH,OAAQ,CAAA,OAAA,CAAQ,CAAC,EAAC,EAAG,EAAE,CAAC,CAAA;AAAA,IAC5B,IAAA,CAAK,MAAS,GAAA,CAAA,GACV,aACG,CAAA,gBAAA;AAAA,MACC,OAAA;AAAA,MACA;AAAA,QACE,GAAG,IAAK,CAAA,GAAA,CAAI,CAAM,CAAA,MAAA;AAAA,UAChB,UAAY,EAAAH,+CAAA;AAAA,UACZ,QAAU,EAAA;AAAA,SACV,CAAA,CAAA;AAAA,QACF,GAAG,IAAK,CAAA,GAAA,CAAI,CAAM,CAAA,MAAA;AAAA,UAChB,UAAY,EAAAC,iDAAA;AAAA,UACZ,QAAU,EAAA;AAAA,SACV,CAAA;AAAA,OACJ;AAAA,MACA,EAAE,WAAY;AAAA,KAChB,CACC,KAAK,CAAW,OAAA,KAAA;AAAA,MACf,OAAQ,CAAA,KAAA,CAAM,CAAG,EAAA,IAAA,CAAK,MAAM,CAAA;AAAA,MAC5B,OAAA,CAAQ,KAAM,CAAA,IAAA,CAAK,MAAM;AAAA,KAC1B,IACH,OAAQ,CAAA,OAAA,CAAQ,CAAC,EAAC,EAAG,EAAE,CAAC,CAAA;AAAA,IAC5B,UAAA,CAAW,MAAS,GAAA,CAAA,GAChB,aACG,CAAA,gBAAA;AAAA,MACC,OAAA;AAAA,MACA;AAAA,QACE,GAAG,UAAW,CAAA,GAAA,CAAI,CAAM,CAAA,MAAA;AAAA,UACtB,UAAY,EAAAM,kDAAA;AAAA,UACZ,QAAU,EAAA;AAAA,SACV,CAAA,CAAA;AAAA,QACF,GAAG,UAAW,CAAA,GAAA,CAAI,CAAM,CAAA,MAAA;AAAA,UACtB,UAAY,EAAAC,oDAAA;AAAA,UACZ,QAAU,EAAA;AAAA,SACV,CAAA;AAAA,OACJ;AAAA,MACA,EAAE,WAAY;AAAA,KAChB,CACC,KAAK,CAAW,OAAA,KAAA;AAAA,MACf,OAAQ,CAAA,KAAA,CAAM,CAAG,EAAA,UAAA,CAAW,MAAM,CAAA;AAAA,MAClC,OAAA,CAAQ,KAAM,CAAA,UAAA,CAAW,MAAM;AAAA,KAChC,IACH,OAAQ,CAAA,OAAA,CAAQ,CAAC,EAAC,EAAG,EAAE,CAAC,CAAA;AAAA,IAC5B,WAAA,CAAY,MAAS,GAAA,CAAA,GACjB,aACG,CAAA,gBAAA;AAAA,MACC,OAAA;AAAA,MACA;AAAA,QACE,GAAG,WAAY,CAAA,GAAA,CAAI,CAAM,CAAA,MAAA;AAAA,UACvB,UAAY,EAAAJ,mDAAA;AAAA,UACZ,QAAU,EAAA;AAAA,SACV,CAAA,CAAA;AAAA,QACF,GAAG,WAAY,CAAA,GAAA,CAAI,CAAM,CAAA,MAAA;AAAA,UACvB,UAAY,EAAAC,qDAAA;AAAA,UACZ,QAAU,EAAA;AAAA,SACV,CAAA;AAAA,OACJ;AAAA,MACA,EAAE,WAAY;AAAA,KAChB,CACC,KAAK,CAAW,OAAA,KAAA;AAAA,MACf,OAAQ,CAAA,KAAA,CAAM,CAAG,EAAA,WAAA,CAAY,MAAM,CAAA;AAAA,MACnC,OAAA,CAAQ,KAAM,CAAA,WAAA,CAAY,MAAM;AAAA,KACjC,IACH,OAAQ,CAAA,OAAA,CAAQ,CAAC,EAAC,EAAG,EAAE,CAAC;AAAA,GAC7B,CAAA;AAED,EAAM,MAAA,WAAA,uBAAkB,GAAqB,EAAA;AAC7C,EAAM,KAAA,CAAA,OAAA,CAAQ,CAAC,CAAA,EAAG,CAAM,KAAA;AACtB,IAAA,WAAA,CAAY,IAAI,CAAa,UAAA,EAAA,CAAA,CAAE,EAAE,CAAI,CAAA,EAAA,aAAA,CAAc,CAAC,CAAC,CAAA;AACrD,IAAA,WAAA,CAAY,IAAI,CAAe,YAAA,EAAA,CAAA,CAAE,EAAE,CAAI,CAAA,EAAA,eAAA,CAAgB,CAAC,CAAC,CAAA;AAAA,GAC1D,CAAA;AACD,EAAY,WAAA,CAAA,OAAA,CAAQ,CAAC,CAAA,EAAG,CAAM,KAAA;AAC5B,IAAA,WAAA,CAAY,IAAI,CAAmB,gBAAA,EAAA,CAAA,CAAE,EAAE,CAAI,CAAA,EAAA,mBAAA,CAAoB,CAAC,CAAC,CAAA;AACjE,IAAA,WAAA,CAAY,IAAI,CAAqB,kBAAA,EAAA,CAAA,CAAE,EAAE,CAAI,CAAA,EAAA,qBAAA,CAAsB,CAAC,CAAC,CAAA;AAAA,GACtE,CAAA;AACD,EAAK,IAAA,CAAA,OAAA,CAAQ,CAAC,CAAA,EAAG,CAAM,KAAA;AACrB,IAAA,WAAA,CAAY,IAAI,CAAY,SAAA,EAAA,CAAA,CAAE,EAAE,CAAI,CAAA,EAAA,YAAA,CAAa,CAAC,CAAC,CAAA;AACnD,IAAA,WAAA,CAAY,IAAI,CAAc,WAAA,EAAA,CAAA,CAAE,EAAE,CAAI,CAAA,EAAA,cAAA,CAAe,CAAC,CAAC,CAAA;AAAA,GACxD,CAAA;AACD,EAAW,UAAA,CAAA,OAAA,CAAQ,CAAC,CAAA,EAAG,CAAM,KAAA;AAC3B,IAAA,WAAA,CAAY,IAAI,CAAe,YAAA,EAAA,CAAA,CAAE,EAAE,CAAI,CAAA,EAAA,eAAA,CAAgB,CAAC,CAAC,CAAA;AACzD,IAAA,WAAA,CAAY,IAAI,CAAiB,cAAA,EAAA,CAAA,CAAE,EAAE,CAAI,CAAA,EAAA,iBAAA,CAAkB,CAAC,CAAC,CAAA;AAAA,GAC9D,CAAA;AACD,EAAY,WAAA,CAAA,OAAA,CAAQ,CAAC,CAAA,EAAG,CAAM,KAAA;AAC5B,IAAA,WAAA,CAAY,IAAI,CAAgB,aAAA,EAAA,CAAA,CAAE,EAAE,CAAI,CAAA,EAAA,gBAAA,CAAiB,CAAC,CAAC,CAAA;AAC3D,IAAA,WAAA,CAAY,IAAI,CAAkB,eAAA,EAAA,CAAA,CAAE,EAAE,CAAI,CAAA,EAAA,kBAAA,CAAmB,CAAC,CAAC,CAAA;AAAA,GAChE,CAAA;AAED,EAAO,OAAA,WAAA;AACT,CAAA;AAEO,MAAM,mBAAsB,GAAA,OACjC,OACA,EAAA,SAAA,EACA,WACA,OAKG,KAAA;AACH,EAAA,IAAI,CAAC,SAAA,IAAa,SAAU,CAAA,MAAA,KAAW,CAAG,EAAA;AACxC,IAAO,OAAA,SAAA;AAAA;AAGT,EAAA,MAAM,EAAE,KAAO,EAAA,QAAA,EAAU,cAAc,IAAK,EAAA,GAAI,WAAW,EAAC;AAC5D,EAAM,MAAA,EAAE,eAAkB,GAAA,SAAA;AAC1B,EAAA,MAAM,cACJ,KAAU,IAAA,MAAM,aAAc,CAAA,cAAA,CAAe,SAAS,IAAI,CAAA;AAC5D,EAAM,MAAA,IAAA,GACJ,YACC,MAAM,SAAA,CAAU,cAAc,WAAY,CAAA,OAAA,EAAS,MAAM,WAAW,CAAA;AAEvE,EAAA,MAAM,iBAAiB,SAAU,CAAA,MAAA;AAAA,IAC/B,CACE,CAAA,KAEA,CAAM,KAAA,IAAA,IAAQ,CAAM,KAAA,KAAA;AAAA,GACxB;AAEA,EAAM,MAAA,KAAA,GAAQ,cAAe,CAAA,MAAA,CAAOV,gCAAM,CAAA;AAC1C,EAAA,MAAM,cAAc,cAAe,CAAA,MAAA;AAAA,IACjCF;AAAA,GACF;AACA,EAAM,MAAA,IAAA,GAAO,cAAe,CAAA,MAAA,CAAOD,+BAAK,CAAA;AACxC,EAAM,MAAA,OAAA,GAAU,cAAe,CAAA,MAAA,CAAOE,kCAAQ,CAAA;AAE9C,EAAI,IAAA,WAAA,uBAAwC,GAAI,EAAA;AAEhD,EAAA,IAAI,WAAa,EAAA;AACf,IAAA,WAAA,GAAc,MAAM,4BAAA;AAAA,MAClB,OAAA;AAAA,MACA,aAAA;AAAA,MACA,WAAA;AAAA,MACA,KAAA;AAAA,MACA,WAAA;AAAA,MACA,IAAA;AAAA,MACA;AAAA,KACF;AAAA;AAGF,EAAA,MAAM,OAAQ,CAAA,GAAA;AAAA,IACZ,SAAA,CAAU,GAAI,CAAA,OAAM,QAAY,KAAA;AAC9B,MAAA,IAAI,CAAC,QAAU,EAAA;AACb,QAAO,OAAA,QAAA;AAAA;AAET,MAAA,QAAA,CAAS,IAAO,GAAA,cAAA,CAAe,QAAU,EAAA,SAAA,CAAU,QAAQ,IAAI,CAAA;AAE/D,MAAI,IAAAF,+BAAA,CAAM,QAAQ,CAAG,EAAA;AACnB,QAAO,OAAA,sBAAA;AAAA,UACL,OAAA;AAAA,UACA,QAAA;AAAA,UACA,aAAA;AAAA,UACA,WAAA;AAAA,UACA,WAAA;AAAA,UACA;AAAA,SACF;AAAA,OACF,MAAA,IAAWC,sCAAa,CAAA,QAAQ,CAAG,EAAA;AACjC,QAAO,OAAA,6BAAA;AAAA,UACL,OAAA;AAAA,UACA,QAAA;AAAA,UACA,aAAA;AAAA,UACA,WAAA;AAAA,UACA,WAAA;AAAA,UACA,SAAA;AAAA,UACA;AAAA,SACF;AAAA,OACF,MAAA,IAAWE,gCAAO,CAAA,QAAQ,CAAG,EAAA;AAC3B,QAAO,OAAA,uBAAA;AAAA,UACL,OAAA;AAAA,UACA,QAAA;AAAA,UACA,aAAA;AAAA,UACA,WAAA;AAAA,UACA,IAAA;AAAA,UACA,WAAA;AAAA,UACA,SAAA;AAAA,UACA;AAAA,SACF;AAAA,OACF,MAAA,IAAWD,kCAAS,CAAA,QAAQ,CAAG,EAAA;AAC7B,QAAO,OAAA,yBAAA;AAAA,UACL,OAAA;AAAA,UACA,QAAA;AAAA,UACA,aAAA;AAAA,UACA,WAAA;AAAA,UACA,IAAA;AAAA,UACA,WAAA;AAAA,UACA,SAAA;AAAA,UACA;AAAA,SACF;AAAA;AAEF,MAAO,OAAA,QAAA;AAAA,KACR;AAAA,GACH;AAEA,EAAO,OAAA,SAAA;AACT;AACa,MAAA,cAAA,GAAiB,CAAC,SAAsB,KAAA;AACnD,EAAM,MAAA,cAAA,GAAiB,OAAO,SAAU,CAAA,QAAA,GAAW,KAAM,CAAA,CAAA,EAAG,EAAE,CAAC,CAAA;AAC/D,EAAA,OAAOiB,eAAOC,eAAQ,iBAAA,IAAI,MAAQ,EAAA,cAAc,GAAG,YAAY,CAAA;AACjE;AAEa,MAAA,WAAA,GAAc,CAAC,MAAmB,KAAA;AAC7C,EAAM,MAAA,WAAA,GAAc,MAAO,CAAA,iBAAA,CAAkB,0BAA0B,CAAA;AACvE,EAAA,MAAM,kBAAkB,MAAO,CAAA,iBAAA;AAAA,IAC7B;AAAA,GACF;AACA,EAAM,MAAA,MAAA,GAAS,MAAO,CAAA,iBAAA,CAAkB,qBAAqB,CAAA;AAC7D,EAAM,MAAA,YAAA,GAAe,MAAO,CAAA,iBAAA,CAAkB,2BAA2B,CAAA;AACzE,EAAM,MAAA,QAAA,GAAW,MAAO,CAAA,iBAAA,CAAkB,uBAAuB,CAAA;AACjE,EAAM,MAAA,UAAA,GAAa,MAAO,CAAA,iBAAA,CAAkB,yBAAyB,CAAA;AACrE,EAAA,MAAM,iBAAiB,MAAO,CAAA,kBAAA;AAAA,IAC5B;AAAA,GACF;AACA,EAAM,MAAA,WAAA,GAAc,MAAO,CAAA,iBAAA,CAAkB,0BAA0B,CAAA;AAEvE,EAAI,IAAA,WAAA;AACJ,EAAA,IAAI,eAAe,eAAiB,EAAA;AAClC,IAAc,WAAA,GAAA;AAAA,MACZ,WAAA;AAAA,MACA,eAAA;AAAA,MACA;AAAA,KACF;AAAA;AAEF,EAAA,OAAO,IAAIC,iBAAS,CAAA;AAAA,IAClB,eAAiB,EAAA,sCAAA;AAAA,IACjB,GAAI,WAAe,IAAA,EAAE,WAAY,EAAA;AAAA,IACjC,GAAI,MAAU,IAAA,EAAE,MAAO,EAAA;AAAA,IACvB,GAAI,QAAY,IAAA,EAAE,QAAS,EAAA;AAAA,IAC3B,GAAI,cAAkB,IAAA,EAAE,cAAe,EAAA;AAAA,IACvC,GAAI,WAAe,IAAA,EAAE,WAAY,EAAA;AAAA,IACjC,GAAI,UAAc,IAAA;AAAA,MAChB,cAAA,EAAgB,IAAIC,+BAAgB,CAAA;AAAA,QAClC,YAAY,IAAIC,uBAAA,CAAgB,EAAE,KAAA,EAAO,YAAY;AAAA,OACtD;AAAA;AACH,GACD,CAAA;AACH;AAEa,MAAA,yBAAA,GAA4B,CAAC,MAAmB,KAAA;AAC3D,EAAA,MAAM,cAAc,MAAO,CAAA,iBAAA;AAAA,IACzB;AAAA,GACF;AACA,EAAA,MAAM,mBAAmB,MAAO,CAAA,iBAAA;AAAA,IAC9B;AAAA,GACF;AACA,EAAA,IAAI,gBAAkB,EAAA;AACpB,IAAO,OAAAC,6BAAA,CAAkB,qBAAqB,gBAAgB,CAAA;AAAA,aACrD,WAAa,EAAA;AACtB,IAAA,OAAO,IAAIA,6BAAA;AAAA,MACT,WAAW,WAAW,CAAA,sBAAA,CAAA;AAAA,MACtB,IAAIC,+BAAuB;AAAA,KAC7B;AAAA;AAGF,EAAA,MAAM,IAAI,KAAA;AAAA,IACR;AAAA,GACF;AACF;;;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"util.cjs.js","sources":["../../src/service/util.ts"],"sourcesContent":["import { Request } from 'express';\nimport { format, subDays } from 'date-fns';\nimport {\n isAnswer,\n isCollection,\n isPost,\n isTag,\n MaybeAnswer,\n MaybeCollection,\n MaybePost,\n MaybeTag,\n} from '../database/QetaStore';\nimport { Config } from '@backstage/config';\nimport { S3Client } from '@aws-sdk/client-s3';\nimport { RouteOptions } from './types';\nimport {\n Answer,\n AnswerResponse,\n CollectionResponse,\n Comment,\n PostResponse,\n qetaDeleteAnswerPermission,\n qetaDeleteCollectionPermission,\n qetaDeleteCommentPermission,\n qetaDeletePostPermission,\n qetaDeleteTagPermission,\n qetaEditAnswerPermission,\n qetaEditCollectionPermission,\n qetaEditCommentPermission,\n qetaEditPostPermission,\n qetaEditTagPermission,\n selectByPostType,\n TagResponse,\n} from '@drodil/backstage-plugin-qeta-common';\nimport { NodeHttpHandler } from '@smithy/node-http-handler';\nimport { HttpsProxyAgent } from 'hpagent';\nimport { compact } from 'lodash';\nimport {\n ConditionTransformer,\n createConditionTransformer,\n} from '@backstage/plugin-permission-node';\nimport { rules } from '@drodil/backstage-plugin-qeta-node';\nimport { BlobServiceClient } from '@azure/storage-blob';\nimport { DefaultAzureCredential } from '@azure/identity';\nimport { BackstageCredentials } from '@backstage/backend-plugin-api';\nimport { PermissionManager } from './PermissionManager.ts';\nimport { stringifyEntityRef } from '@backstage/catalog-model';\n\nexport const getResourceUrl = (\n resource: MaybePost | MaybeAnswer | MaybeTag | MaybeCollection,\n config: Config,\n absolute?: boolean,\n) => {\n if (!resource) {\n return undefined;\n }\n const basePath = (\n config.getOptionalString('qeta.route') ?? 'qeta'\n ).replaceAll(/(^\\/+)|(\\/+$)/g, '');\n const baseUrl = absolute\n ? `${config.getOptionalString('app.baseUrl') ?? ''}/${basePath}`\n : `/${basePath}`;\n\n if (isTag(resource)) {\n return `${baseUrl}/tags/${resource.tag}`;\n } else if (isCollection(resource)) {\n return `${baseUrl}/collection/${resource.id}`;\n } else if (isAnswer(resource)) {\n return `${baseUrl}/questions/${resource.postId}#answer_${resource.id}`;\n } else if (isPost(resource)) {\n const questionRoute = `${baseUrl}/questions/${resource.id}`;\n const articleRoute = `${baseUrl}/articles/${resource.id}`;\n const linkRoute = `${baseUrl}/links/${resource.id}`;\n return selectByPostType(\n resource.type,\n questionRoute,\n articleRoute,\n linkRoute,\n );\n }\n return undefined;\n};\n\nconst filterEntitiesByPermissions = async (\n entityRefs: string[] | undefined,\n routeOpts: RouteOptions,\n credentials: BackstageCredentials,\n): Promise<string[] | undefined> => {\n if (!entityRefs || entityRefs.length === 0) {\n return entityRefs;\n }\n\n try {\n let userKey: string | undefined = undefined;\n if (routeOpts.auth.isPrincipal(credentials, 'user')) {\n userKey = credentials.principal.userEntityRef;\n } else if (routeOpts.auth.isPrincipal(credentials, 'service')) {\n userKey = credentials.principal.subject;\n } else {\n routeOpts.logger.warn(\n `Could not determine principal for permission check. Credentials: ${JSON.stringify(\n credentials,\n )}`,\n );\n return [];\n }\n\n const cacheKey = `qeta:entity-permissions:${userKey}`;\n const cache = routeOpts.cache;\n let cachedPermissions: Record<string, boolean> = {};\n\n if (cache) {\n const cached = await cache.get<Record<string, boolean>>(cacheKey);\n if (cached) {\n cachedPermissions = cached;\n }\n }\n\n const refsToCheck: string[] = [];\n const allowedRefs: string[] = [];\n\n for (const ref of entityRefs) {\n if (ref in cachedPermissions) {\n if (cachedPermissions[ref]) {\n allowedRefs.push(ref);\n }\n } else {\n refsToCheck.push(ref);\n }\n }\n\n if (refsToCheck.length > 0) {\n const { token } = await routeOpts.auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n const entities = await routeOpts.catalog.getEntitiesByRefs(\n { entityRefs: refsToCheck },\n { token },\n );\n\n const fetchedRefs = new Set(\n entities.items\n .filter(entity => entity !== undefined)\n .map(stringifyEntityRef),\n );\n\n refsToCheck.forEach(ref => {\n const isAllowed = fetchedRefs.has(ref);\n cachedPermissions[ref] = isAllowed;\n if (isAllowed) {\n allowedRefs.push(ref);\n }\n });\n\n if (cache) {\n await cache.set(cacheKey, cachedPermissions, { ttl: 300000 }); // 5 minutes\n }\n }\n\n return allowedRefs;\n } catch (error) {\n routeOpts.logger.warn('Error filtering entities by permissions', error);\n return [];\n }\n};\n\nexport const getCreated = async (\n req: Request<unknown>,\n options: RouteOptions,\n): Promise<Date> => {\n const allowMetadataInput = options.config.getOptionalBoolean(\n 'qeta.allowMetadataInput',\n );\n\n if (allowMetadataInput && req.body.created) {\n return new Date(req.body.created);\n }\n\n return new Date();\n};\n\nexport type QetaFilter = {\n property:\n | 'posts.id'\n | 'posts.author'\n | 'posts.type'\n | 'tags'\n | 'entityRefs'\n | 'answers.id'\n | 'answers.author'\n | 'comments.id'\n | 'comments.author'\n | 'tags.tag'\n | 'tag.experts'\n | 'collections.owner'\n | 'collections.id';\n values: Array<string | undefined>;\n};\n\nexport type QetaFilters = QetaFilter;\n\nexport const transformConditions: ConditionTransformer<QetaFilters> =\n createConditionTransformer(Object.values(rules));\n\nconst mapTagAdditionalFields = async (\n request: Request<unknown>,\n resource: TagResponse,\n permissionMgr: PermissionManager,\n credentials: BackstageCredentials,\n checkRights?: boolean,\n permissions?: Map<string, boolean>,\n) => {\n const [canEdit, canDelete] = await Promise.all([\n permissions?.get(`edit:tag:${resource.id}`) ??\n (checkRights\n ? permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaEditTagPermission, resource }],\n {\n credentials,\n },\n )\n .then(r => r[0])\n : undefined),\n permissions?.get(`delete:tag:${resource.id}`) ??\n (checkRights\n ? permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaDeleteTagPermission, resource }],\n {\n credentials,\n },\n )\n .then(r => r[0])\n : undefined),\n ]);\n\n resource.canEdit = canEdit;\n resource.canDelete = canDelete;\n return resource;\n};\n\nconst mapCollectionAdditionalFields = async (\n request: Request<unknown>,\n resource: CollectionResponse,\n permissionMgr: PermissionManager,\n credentials: BackstageCredentials,\n checkRights?: boolean,\n routeOpts?: RouteOptions,\n permissions?: Map<string, boolean>,\n) => {\n const [canEdit, canDelete, filteredEntities] = await Promise.all([\n permissions?.get(`edit:collection:${resource.id}`) ??\n (checkRights\n ? permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaEditCollectionPermission, resource }],\n {\n credentials,\n },\n )\n .then(r => r[0])\n : undefined),\n permissions?.get(`delete:collection:${resource.id}`) ??\n (checkRights\n ? permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaDeleteCollectionPermission, resource }],\n {\n credentials,\n },\n )\n .then(r => r[0])\n : undefined),\n routeOpts\n ? filterEntitiesByPermissions(resource.entities, routeOpts, credentials)\n : resource.entities,\n ]);\n\n resource.canEdit = canEdit;\n resource.canDelete = canDelete;\n resource.entities = filteredEntities;\n\n if (resource.posts && routeOpts) {\n const allEntityRefs = new Set<string>();\n resource.posts.forEach(post => {\n post.entities?.forEach(ref => allEntityRefs.add(ref));\n });\n\n if (allEntityRefs.size > 0) {\n const allowedRefs = await filterEntitiesByPermissions(\n Array.from(allEntityRefs),\n routeOpts,\n credentials,\n );\n\n if (allowedRefs) {\n const allowedSet = new Set(allowedRefs);\n resource.posts.forEach(post => {\n post.entities = post.entities?.filter(ref => allowedSet.has(ref));\n });\n }\n }\n }\n\n return resource;\n};\n\nconst mapResourceComments = async (\n request: Request<unknown>,\n resource: AnswerResponse | PostResponse,\n permissionMgr: PermissionManager,\n credentials: BackstageCredentials,\n username: string,\n checkRights?: boolean,\n permissions?: Map<string, boolean>,\n) => {\n const commentArr = resource.comments ?? [];\n const comments: (Comment | null)[] = await Promise.all(\n commentArr.map(async (c: Comment) => {\n const canEdit =\n permissions?.get(`edit:comment:${c.id}`) ??\n (checkRights\n ? await permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaEditCommentPermission, resource: c }],\n { credentials },\n )\n .then(r => r[0])\n : false);\n const canDelete =\n permissions?.get(`delete:comment:${c.id}`) ??\n (checkRights\n ? await permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaDeleteCommentPermission, resource: c }],\n { credentials },\n )\n .then(r => r[0])\n : false);\n\n return {\n ...c,\n own: c.author === username,\n expert: c.experts?.includes(c.author),\n canEdit,\n canDelete,\n };\n }),\n );\n return compact(comments);\n};\n\nconst mapAnswerAdditionalFields = async (\n request: Request<unknown>,\n resource: AnswerResponse,\n permissionMgr: PermissionManager,\n credentials: BackstageCredentials,\n username: string,\n checkRights?: boolean,\n routeOpts?: RouteOptions,\n permissions?: Map<string, boolean>,\n) => {\n const [canEdit, canDelete, comments] = await Promise.all([\n permissions?.get(`edit:answer:${resource.id}`) ??\n (checkRights\n ? permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaEditAnswerPermission, resource }],\n {\n credentials,\n },\n )\n .then(r => r[0])\n : undefined),\n permissions?.get(`delete:answer:${resource.id}`) ??\n (checkRights\n ? permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaDeleteAnswerPermission, resource }],\n {\n credentials,\n },\n )\n .then(r => r[0])\n : undefined),\n mapResourceComments(\n request,\n resource,\n permissionMgr,\n credentials,\n username,\n checkRights,\n permissions,\n ),\n ]);\n\n resource.ownVote = resource.votes?.find(v => v.author === username)?.score;\n resource.own = resource.author === username;\n resource.canEdit = canEdit;\n resource.canDelete = canDelete;\n resource.expert = resource.experts?.includes(resource.author);\n resource.comments = comments;\n\n // Filter entities on the associated post if present\n if (resource.post && routeOpts) {\n resource.post.entities = await filterEntitiesByPermissions(\n resource.post.entities,\n routeOpts,\n credentials,\n );\n }\n\n return resource;\n};\n\nconst mapPostAnswers = async (\n request: Request<unknown>,\n resource: PostResponse,\n permissionMgr: PermissionManager,\n credentials: BackstageCredentials,\n username: string,\n checkRights?: boolean,\n permissions?: Map<string, boolean>,\n) => {\n const answersArray = resource.answers ?? [];\n const comments = await Promise.all(\n answersArray.map(async (a: Answer) => {\n return mapResourceComments(\n request,\n a,\n permissionMgr,\n credentials,\n username,\n checkRights,\n permissions,\n );\n }),\n );\n\n return Promise.all(\n answersArray.map(async (a: Answer, index: number) => {\n const canEdit =\n permissions?.get(`edit:answer:${a.id}`) ??\n (checkRights\n ? await permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaEditAnswerPermission, resource: a }],\n { credentials },\n )\n .then(r => r[0])\n : false);\n const canDelete =\n permissions?.get(`delete:answer:${a.id}`) ??\n (checkRights\n ? await permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaDeleteAnswerPermission, resource: a }],\n { credentials },\n )\n .then(r => r[0])\n : false);\n\n return {\n ...a,\n ownVote: a.votes?.find(v => v.author === username)?.score,\n own: a.author === username,\n canEdit,\n canDelete,\n expert: a.experts?.includes(resource.author),\n comments: comments[index],\n };\n }),\n );\n};\n\nconst mapPostAdditionalFields = async (\n request: Request<unknown>,\n resource: PostResponse,\n permissionMgr: PermissionManager,\n credentials: BackstageCredentials,\n username: string,\n checkRights?: boolean,\n routeOpts?: RouteOptions,\n permissions?: Map<string, boolean>,\n) => {\n resource.ownVote = resource.votes?.find(v => v.author === username)?.score;\n resource.own = resource.author === username;\n\n const [canEdit, canDelete, answers, comments, filteredEntities] =\n await Promise.all([\n permissions?.get(`edit:post:${resource.id}`) ??\n (checkRights\n ? permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaEditPostPermission, resource }],\n {\n credentials,\n },\n )\n .then(r => r[0])\n : undefined),\n permissions?.get(`delete:post:${resource.id}`) ??\n (checkRights\n ? permissionMgr\n .authorizeBoolean(\n request,\n [{ permission: qetaDeletePostPermission, resource }],\n {\n credentials,\n },\n )\n .then(r => r[0])\n : undefined),\n mapPostAnswers(\n request,\n resource,\n permissionMgr,\n credentials,\n username,\n checkRights,\n permissions,\n ),\n mapResourceComments(\n request,\n resource,\n permissionMgr,\n credentials,\n username,\n checkRights,\n permissions,\n ),\n routeOpts\n ? filterEntitiesByPermissions(resource.entities, routeOpts, credentials)\n : resource.entities,\n ]);\n resource.canEdit = canEdit;\n resource.canDelete = canDelete;\n resource.answers = answers;\n resource.comments = comments;\n resource.entities = filteredEntities;\n return resource;\n};\n\nconst authorizeResourcePermissions = async (\n request: Request<unknown>,\n permissionMgr: PermissionManager,\n credentials: BackstageCredentials,\n posts: PostResponse[],\n collections: CollectionResponse[],\n tags: TagResponse[],\n answers: AnswerResponse[],\n) => {\n const allAnswers = [\n ...answers,\n ...posts.flatMap(p => (p.answers ? p.answers : [])),\n ];\n const allComments = [\n ...posts.flatMap(p => (p.comments ? p.comments : [])),\n ...allAnswers.flatMap(a => (a.comments ? a.comments : [])),\n ];\n\n const [\n [postEditPerms, postDeletePerms],\n [collectionEditPerms, collectionDeletePerms],\n [tagEditPerms, tagDeletePerms],\n [answerEditPerms, answerDeletePerms],\n [commentEditPerms, commentDeletePerms],\n ] = await Promise.all([\n posts.length > 0\n ? permissionMgr\n .authorizeBoolean(\n request,\n [\n ...posts.map(r => ({\n permission: qetaEditPostPermission,\n resource: r,\n })),\n ...posts.map(r => ({\n permission: qetaDeletePostPermission,\n resource: r,\n })),\n ],\n { credentials },\n )\n .then(results => [\n results.slice(0, posts.length),\n results.slice(posts.length),\n ])\n : Promise.resolve([[], []]),\n collections.length > 0\n ? permissionMgr\n .authorizeBoolean(\n request,\n [\n ...collections.map(r => ({\n permission: qetaEditCollectionPermission,\n resource: r,\n })),\n ...collections.map(r => ({\n permission: qetaDeleteCollectionPermission,\n resource: r,\n })),\n ],\n { credentials },\n )\n .then(results => [\n results.slice(0, collections.length),\n results.slice(collections.length),\n ])\n : Promise.resolve([[], []]),\n tags.length > 0\n ? permissionMgr\n .authorizeBoolean(\n request,\n [\n ...tags.map(r => ({\n permission: qetaEditTagPermission,\n resource: r,\n })),\n ...tags.map(r => ({\n permission: qetaDeleteTagPermission,\n resource: r,\n })),\n ],\n { credentials },\n )\n .then(results => [\n results.slice(0, tags.length),\n results.slice(tags.length),\n ])\n : Promise.resolve([[], []]),\n allAnswers.length > 0\n ? permissionMgr\n .authorizeBoolean(\n request,\n [\n ...allAnswers.map(r => ({\n permission: qetaEditAnswerPermission,\n resource: r,\n })),\n ...allAnswers.map(r => ({\n permission: qetaDeleteAnswerPermission,\n resource: r,\n })),\n ],\n { credentials },\n )\n .then(results => [\n results.slice(0, allAnswers.length),\n results.slice(allAnswers.length),\n ])\n : Promise.resolve([[], []]),\n allComments.length > 0\n ? permissionMgr\n .authorizeBoolean(\n request,\n [\n ...allComments.map(r => ({\n permission: qetaEditCommentPermission,\n resource: r,\n })),\n ...allComments.map(r => ({\n permission: qetaDeleteCommentPermission,\n resource: r,\n })),\n ],\n { credentials },\n )\n .then(results => [\n results.slice(0, allComments.length),\n results.slice(allComments.length),\n ])\n : Promise.resolve([[], []]),\n ]);\n\n const permissions = new Map<string, boolean>();\n posts.forEach((r, i) => {\n permissions.set(`edit:post:${r.id}`, postEditPerms[i]);\n permissions.set(`delete:post:${r.id}`, postDeletePerms[i]);\n });\n collections.forEach((r, i) => {\n permissions.set(`edit:collection:${r.id}`, collectionEditPerms[i]);\n permissions.set(`delete:collection:${r.id}`, collectionDeletePerms[i]);\n });\n tags.forEach((r, i) => {\n permissions.set(`edit:tag:${r.id}`, tagEditPerms[i]);\n permissions.set(`delete:tag:${r.id}`, tagDeletePerms[i]);\n });\n allAnswers.forEach((r, i) => {\n permissions.set(`edit:answer:${r.id}`, answerEditPerms[i]);\n permissions.set(`delete:answer:${r.id}`, answerDeletePerms[i]);\n });\n allComments.forEach((r, i) => {\n permissions.set(`edit:comment:${r.id}`, commentEditPerms[i]);\n permissions.set(`delete:comment:${r.id}`, commentDeletePerms[i]);\n });\n\n return permissions;\n};\n\nexport const mapAdditionalFields = async (\n request: Request<unknown>,\n resources: (MaybePost | MaybeAnswer | MaybeTag | MaybeCollection)[],\n routeOpts: RouteOptions,\n options?: {\n checkRights?: boolean;\n creds?: BackstageCredentials;\n username?: string;\n },\n) => {\n if (!resources || resources.length === 0) {\n return resources;\n }\n\n const { creds, username, checkRights = true } = options ?? {};\n const { permissionMgr } = routeOpts;\n const credentials =\n creds ?? (await permissionMgr.getCredentials(request, true));\n const user =\n username ??\n (await routeOpts.permissionMgr.getUsername(request, true, credentials));\n\n const validResources = resources.filter(\n (\n r,\n ): r is PostResponse | AnswerResponse | TagResponse | CollectionResponse =>\n r !== null && r !== undefined,\n );\n\n const posts = validResources.filter(isPost) as PostResponse[];\n const collections = validResources.filter(\n isCollection,\n ) as CollectionResponse[];\n const tags = validResources.filter(isTag) as TagResponse[];\n const answers = validResources.filter(isAnswer) as AnswerResponse[];\n\n let permissions: Map<string, boolean> = new Map();\n\n if (checkRights) {\n permissions = await authorizeResourcePermissions(\n request,\n permissionMgr,\n credentials,\n posts,\n collections,\n tags,\n answers,\n );\n }\n\n await Promise.all(\n resources.map(async resource => {\n if (!resource) {\n return resource;\n }\n resource.self = getResourceUrl(resource, routeOpts.config, true);\n\n if (isTag(resource)) {\n return mapTagAdditionalFields(\n request,\n resource,\n permissionMgr,\n credentials,\n checkRights,\n permissions,\n );\n } else if (isCollection(resource)) {\n return mapCollectionAdditionalFields(\n request,\n resource,\n permissionMgr,\n credentials,\n checkRights,\n routeOpts,\n permissions,\n );\n } else if (isPost(resource)) {\n return mapPostAdditionalFields(\n request,\n resource,\n permissionMgr,\n credentials,\n user,\n checkRights,\n routeOpts,\n permissions,\n );\n } else if (isAnswer(resource)) {\n return mapAnswerAdditionalFields(\n request,\n resource,\n permissionMgr,\n credentials,\n user,\n checkRights,\n routeOpts,\n permissions,\n );\n }\n return resource;\n }),\n );\n\n return resources;\n};\nexport const stringDateTime = (dayString: string) => {\n const dateTimePeriod = Number(dayString.toString().slice(0, -1));\n return format(subDays(new Date(), dateTimePeriod), 'yyyy-MM-dd');\n};\n\nexport const getS3Client = (config: Config) => {\n const accessKeyId = config.getOptionalString('qeta.storage.accessKeyId');\n const secretAccessKey = config.getOptionalString(\n 'qeta.storage.secretAccessKey',\n );\n const region = config.getOptionalString('qeta.storage.region');\n const sessionToken = config.getOptionalString('qeta.storage.sessionToken');\n const endpoint = config.getOptionalString('qeta.storage.endpoint');\n const httpsProxy = config.getOptionalString('qeta.storage.httpsProxy');\n const forcePathStyle = config.getOptionalBoolean(\n 'qeta.storage.forcePathStyle',\n );\n const maxAttempts = config.getOptionalNumber('qeta.storage.maxAttempts');\n\n let credentials;\n if (accessKeyId && secretAccessKey) {\n credentials = {\n accessKeyId,\n secretAccessKey,\n sessionToken,\n };\n }\n return new S3Client({\n customUserAgent: 'backstage-aws-drodil-qeta-s3-storage',\n ...(credentials && { credentials }),\n ...(region && { region }),\n ...(endpoint && { endpoint }),\n ...(forcePathStyle && { forcePathStyle }),\n ...(maxAttempts && { maxAttempts }),\n ...(httpsProxy && {\n requestHandler: new NodeHttpHandler({\n httpsAgent: new HttpsProxyAgent({ proxy: httpsProxy }),\n }),\n }),\n });\n};\n\nexport const getAzureBlobServiceClient = (config: Config) => {\n const accountName = config.getOptionalString(\n 'qeta.storage.blobStorageAccountName',\n );\n const connectionString = config.getOptionalString(\n 'qeta.storage.blobStorageConnectionString',\n );\n if (connectionString) {\n return BlobServiceClient.fromConnectionString(connectionString);\n } else if (accountName) {\n return new BlobServiceClient(\n `https://${accountName}.blob.core.windows.net`,\n new DefaultAzureCredential(),\n );\n }\n\n throw new Error(\n 'Either account name or connection string must be provided for Azure Blob Storage',\n );\n};\n"],"names":["isTag","isCollection","isAnswer","isPost","selectByPostType","stringifyEntityRef","createConditionTransformer","rules","qetaEditTagPermission","qetaDeleteTagPermission","qetaEditCollectionPermission","qetaDeleteCollectionPermission","qetaEditCommentPermission","qetaDeleteCommentPermission","compact","qetaEditAnswerPermission","qetaDeleteAnswerPermission","qetaEditPostPermission","qetaDeletePostPermission","format","subDays","S3Client","NodeHttpHandler","HttpsProxyAgent","BlobServiceClient","DefaultAzureCredential"],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {import('knex').Knex} knex
|
|
3
|
+
*/
|
|
4
|
+
exports.up = async function up(knex) {
|
|
5
|
+
await knex.schema.createTable('collection_tags', table => {
|
|
6
|
+
table.integer('collectionId').unsigned().notNullable();
|
|
7
|
+
table.integer('tagId').notNullable();
|
|
8
|
+
table.primary(['collectionId', 'tagId']);
|
|
9
|
+
table
|
|
10
|
+
.foreign('collectionId')
|
|
11
|
+
.references('id')
|
|
12
|
+
.inTable('collections')
|
|
13
|
+
.onDelete('CASCADE');
|
|
14
|
+
table.foreign('tagId').references('id').inTable('tags').onDelete('CASCADE');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
await knex.schema.createTable('collection_entities', table => {
|
|
18
|
+
table.integer('collectionId').unsigned().notNullable();
|
|
19
|
+
table
|
|
20
|
+
.foreign('collectionId')
|
|
21
|
+
.references('id')
|
|
22
|
+
.inTable('collections')
|
|
23
|
+
.onDelete('CASCADE');
|
|
24
|
+
table.integer('entityId').unsigned().notNullable();
|
|
25
|
+
table
|
|
26
|
+
.foreign('entityId')
|
|
27
|
+
.references('id')
|
|
28
|
+
.inTable('entities')
|
|
29
|
+
.onDelete('CASCADE');
|
|
30
|
+
table.primary(['collectionId', 'entityId']);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
await knex.schema.createTable('collection_users', table => {
|
|
34
|
+
table.integer('collectionId').unsigned().notNullable();
|
|
35
|
+
table
|
|
36
|
+
.foreign('collectionId')
|
|
37
|
+
.references('id')
|
|
38
|
+
.inTable('collections')
|
|
39
|
+
.onDelete('CASCADE');
|
|
40
|
+
table.string('userRef').notNullable();
|
|
41
|
+
table.primary(['collectionId', 'userRef']);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
await knex.schema.alterTable('collection_posts', table => {
|
|
45
|
+
table.boolean('automatic').defaultTo(false).notNullable();
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @param {import('knex').Knex} knex
|
|
51
|
+
*/
|
|
52
|
+
exports.down = async function down(knex) {
|
|
53
|
+
await knex.schema.dropTable('collection_tags');
|
|
54
|
+
await knex.schema.dropTable('collection_entities');
|
|
55
|
+
await knex.schema.dropTable('collection_users');
|
|
56
|
+
await knex.schema.alterTable('collection_posts', table => {
|
|
57
|
+
table.dropColumn('automatic');
|
|
58
|
+
});
|
|
59
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@drodil/backstage-plugin-qeta-backend",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.55.0",
|
|
4
4
|
"description": "Backstage.io Q&A plugin backend",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"backstage",
|
|
@@ -66,8 +66,8 @@
|
|
|
66
66
|
"@backstage/plugin-permission-node": "^0.10.7",
|
|
67
67
|
"@backstage/plugin-signals-node": "^0.1.27",
|
|
68
68
|
"@backstage/types": "^1.2.2",
|
|
69
|
-
"@drodil/backstage-plugin-qeta-common": "^3.
|
|
70
|
-
"@drodil/backstage-plugin-qeta-node": "^3.
|
|
69
|
+
"@drodil/backstage-plugin-qeta-common": "^3.55.0",
|
|
70
|
+
"@drodil/backstage-plugin-qeta-node": "^3.55.0",
|
|
71
71
|
"@smithy/node-http-handler": "^4.0.2",
|
|
72
72
|
"@types/express": "*",
|
|
73
73
|
"@types/mime-types": "^2.1.4",
|
|
@@ -105,9 +105,9 @@
|
|
|
105
105
|
"@backstage/plugin-search-backend-module-pg": "^0.5.51",
|
|
106
106
|
"@backstage/plugin-signals-backend": "^0.3.11",
|
|
107
107
|
"@backstage/plugin-techdocs-backend": "^2.1.3",
|
|
108
|
-
"@drodil/backstage-plugin-catalog-backend-module-qeta": "^3.
|
|
109
|
-
"@drodil/backstage-plugin-qeta-backend-module-openai": "^3.
|
|
110
|
-
"@drodil/backstage-plugin-search-backend-module-qeta": "^3.
|
|
108
|
+
"@drodil/backstage-plugin-catalog-backend-module-qeta": "^3.55.0",
|
|
109
|
+
"@drodil/backstage-plugin-qeta-backend-module-openai": "^3.55.0",
|
|
110
|
+
"@drodil/backstage-plugin-search-backend-module-qeta": "^3.55.0",
|
|
111
111
|
"@types/sanitize-html": "^2.9.5",
|
|
112
112
|
"@types/stopword": "^2.0.3",
|
|
113
113
|
"@types/supertest": "^2.0.12",
|