Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Quick hack: Redirect to asset by URL - Endpoint extension for directus.io
// 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));
});
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment