diff --git a/server/graph/resolvers/asset.js b/server/graph/resolvers/asset.js index 91efbdda8..38c4c5489 100644 --- a/server/graph/resolvers/asset.js +++ b/server/graph/resolvers/asset.js @@ -41,6 +41,13 @@ module.exports = { const path = parentPath ? `${parentPath}/${r.slug}` : r.slug return WIKI.auth.checkAccess(context.req.user, ['read:assets'], { path }) }) + }, + async folderByPath(obj, args, context) { + const path = args.path.toLowerCase() + if (!WIKI.auth.checkAccess(context.req.user, ['read:assets'], { path })) { + return null + } + return WIKI.models.assetFolders.getFolderByPath(path) } }, AssetMutation: { diff --git a/server/graph/schemas/asset.graphql b/server/graph/schemas/asset.graphql index f07f1307f..0bfd344f9 100644 --- a/server/graph/schemas/asset.graphql +++ b/server/graph/schemas/asset.graphql @@ -23,6 +23,8 @@ type AssetQuery { folders( parentFolderId: Int! ): [AssetFolder] @auth(requires: ["manage:system", "read:assets"]) + + folderByPath(path: String!): AssetFolder @auth(requires: ["manage:system", "read:assets"]) } # ----------------------------------------------- diff --git a/server/models/assetFolders.js b/server/models/assetFolders.js index 4acb496cc..752181638 100644 --- a/server/models/assetFolders.js +++ b/server/models/assetFolders.js @@ -75,4 +75,32 @@ module.exports = class AssetFolder extends Model { }) return folders } + + /** + * Get asset folder by resolving its path from root + * @param {string} path Folder path, e.g. 'abc/def/ghi' + */ + static async getFolderByPath(path) { + const segments = String(path).split('/').filter(Boolean) + if (segments.length === 0) return null + const db = this.knex() + const targetPath = segments.join('/') + let results + if (WIKI.config.db.type === 'mssql') { + results = await db + .with('folder_path', (qb) => { + qb.select('af.*').select(db.raw('CAST(af.slug AS VARCHAR(MAX)) AS current_path')).from('assetFolders as af').whereNull('af.parentId').unionAll((uqb) => { + uqb.select('af.*').select(db.raw("CAST(fp.current_path + '/' + af.slug AS VARCHAR(MAX)) AS current_path")).from('assetFolders as af').join('folder_path as fp', 'af.parentId', 'fp.id') + }) + }).select('*').from('folder_path').where('current_path', targetPath).limit(1) + } else { + results = await db + .withRecursive('folder_path', (qb) => { + qb.select('af.*').select(db.raw('af.slug::TEXT AS current_path')).from('assetFolders as af').whereNull('af.parentId').unionAll((uqb) => { + uqb.select('af.*').select(db.raw("fp.current_path || '/' || af.slug AS current_path")).from('assetFolders as af').join('folder_path as fp', 'af.parentId', 'fp.id') + }, true) + }).select('*').from('folder_path').where('current_path', targetPath).limit(1) + } + return results[0] || null + } }