Skip to content

Instantly share code, notes, and snippets.

@ToJans
Last active January 30, 2025 07:08
Show Gist options
  • Select an option

  • Save ToJans/fa18e2a7363edd24be6ad8dda2dd0232 to your computer and use it in GitHub Desktop.

Select an option

Save ToJans/fa18e2a7363edd24be6ad8dda2dd0232 to your computer and use it in GitHub Desktop.

Revisions

  1. ToJans renamed this gist Oct 21, 2021. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. ToJans created this gist Oct 21, 2021.
    122 changes: 122 additions & 0 deletions index.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,122 @@
    // Quick hack: Redirect to asset by URL - Endpoint extension for directus.io
    // =========================================================================
    //
    // 2021 - ToJans - Public Domain
    //
    // *** Don't hold me liable if it breaks anything! Quick hack, might expose all your data!
    //
    // You can use this endpoint extension to access assets via the folder and file structure
    // you used in the file module, so you don't need to reference assets by guid anymore.
    //
    // Usage:
    // ------
    //
    // Browse to "/filestorage/[folder/subfolder/filename.ext]" according to the [folder]s
    // and [filename_download] you used in the file module. It will redirect to "/assets/some-huge-guid-xxxxx"
    //
    // Installation:
    // -------------
    //
    // Save the contents of this file in "$DIRECTUS_ROOT/extensions/endpoints/filestorage/index.js" and (re)start directus.
    //
    // Note:
    // -----
    // This is just a quick hack to see how extensible directus.io is, and I have to say I'm not disappointed.
    //
    // However, I only discovered directus.io a couple of hours ago, so I'm by no means an expert on this stuff.
    // So authorization & async might need to be validated TBH.

    module.exports = function registerEndpoint(router, context) {
    const {
    services,
    exceptions,
    } = context;

    const {
    FilesService,
    FoldersService,
    } = services;
    const {
    ServiceUnavailableException
    } = exceptions;


    router.get('*', (req, res, next) => {

    const foldersService = new FoldersService({
    schema: req.schema,
    accountability: req.accountability
    });

    const paths = req.params[0].split("/").filter(x => !!x);

    const file = paths.pop();

    let parentKey = null;
    let currentPath = "/";
    let hasError = false;

    foldersService.readByQuery({
    filter: {
    name: {
    "_in": paths
    }
    },
    fields: ["id", "name", "parent"]
    }).then(folders => {

    while (paths.length && !hasError) {
    head = paths.shift();
    currentPath += head;
    let headFolder = folders.find(x => x.parent == parentKey && x.name == head);
    if (!headFolder) {
    res.status(404).send({
    status: 404,
    error: "path not found: " + currentPath
    });
    hasError = true;
    break;
    }
    parentKey = headFolder.id;
    }

    // TODO: I should handle this properly
    if (!hasError) {
    const filesService = new FilesService({
    schema: req.schema,
    accountability: req.accountability
    });

    return filesService.readByQuery({
    filter: {
    "filename_download": {
    "_eq": file
    },
    // TODO:
    // This does not seem to work, as it fails on null values, so for now I just check it manually
    // This might cause perf issues if we have a lot of files with the same name....
    // "folder": {
    // "_eq": parentKey
    // }
    },
    fields: ["id", "type", "folder"]
    });
    }
    })
    .then((results) => {
    // TODO: workaround I mentioned a few lines earlier
    results = results.filter(x => x.folder === parentKey);
    if (!results.length) {
    res.status(404).send({
    status: 404,
    error: "file not found"
    });
    } else {
    res.redirect("/assets/" + results[0].id);
    }
    })
    .catch((error) => {
    return next(new ServiceUnavailableException(error.message));
    });
    });
    };