Skip to content

Commit

Permalink
chore(code.angularjs): enable directory listings
Browse files Browse the repository at this point in the history
  • Loading branch information
Narretz committed Jul 31, 2017
1 parent 84061c2 commit 0179c70
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 30 deletions.
137 changes: 117 additions & 20 deletions scripts/code.angularjs.org-firebase/functions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ const gcs = require('@google-cloud/storage')();
const path = require('path');

const gcsBucketId = `${process.env.GCLOUD_PROJECT}.appspot.com`;
const LOCAL_TMP_FOLDER = '/tmp/';

const BROWSER_CACHE_DURATION = 300;
const CDN_CACHE_DURATION = 600;
Expand All @@ -22,7 +21,6 @@ function sendStoredFile(request, response) {
const bucket = gcs.bucket(gcsBucketId);

let downloadSource;
let downloadDestination;
let fileName;

if (isDocsPath && filePathSegments.length === 2) {
Expand All @@ -32,43 +30,142 @@ function sendStoredFile(request, response) {
fileName = lastSegment;
}

if (!fileName) {
//Root
return getDirectoryListing('/').catch(sendErrorResponse);
}

downloadSource = path.join.apply(null, filePathSegments);
downloadDestination = `${LOCAL_TMP_FOLDER}${fileName}`;

downloadAndSend(downloadSource, downloadDestination).catch(error => {
downloadAndSend(downloadSource).catch(error => {
if (isDocsPath && error.code === 404) {
fileName = 'index.html';
filePathSegments = [version, 'docs', fileName];
downloadSource = path.join.apply(null, filePathSegments);
downloadDestination = `${LOCAL_TMP_FOLDER}${fileName}`;

return downloadAndSend(downloadSource, downloadDestination);
return downloadAndSend(downloadSource);
}

return Promise.reject(error);
}).catch(error => {
let message = 'General error';

// If file not found, try the path as a directory
return error.code === 404 ? getDirectoryListing(request.path.slice(1)) : Promise.reject(error);
}).catch(sendErrorResponse);

function downloadAndSend(downloadSource) {

const file = bucket.file(downloadSource);

return file.getMetadata().then(data => {
return new Promise((resolve, reject) => {

const readStream = file.createReadStream()
.on('error', error => {
reject(error);
})
.on('response', () => {
resolve(response);
});

response
.status(200)
.set({
'Content-Type': data[0].contentType,
'Cache-Control': `public, max-age=${BROWSER_CACHE_DURATION}, s-maxage=${CDN_CACHE_DURATION}`
});

readStream.pipe(response);
});

});
}

function sendErrorResponse(error) {
let code = 500;
let message = `General error. Please try again later.
If the error persists, please create an issue in the
<a href="https://github.com/angular/angular.js/issues">AngularJS Github repository</a>`;

if (error.code === 404) {
if (fileName.split('.').length === 1) {
message = 'Directory listing is not supported';
} else {
message = 'File not found';
}
message = 'File or directory not found';
code = 404;
}

return response.status(error.code).send(message);
});
return response.status(code).send(message);
}

function getDirectoryListing(path) {
if (!path.endsWith('/')) path += '/';

function downloadAndSend(downloadSource, downloadDestination) {
return bucket.file(downloadSource).download({
destination: downloadDestination
}).then(() => {
return response.status(200)
const getFilesOptions = {
delimiter: '/',
autoPaginate: false
};

if (path !== '/') getFilesOptions.prefix = path;

let fileList = [];
let directoryList = [];

return getContent(getFilesOptions).then(() => {
let contentList = '';

directoryList.forEach(directoryPath => {
const dirName = directoryPath.split('/').reverse()[1];
contentList += `<a href="${dirName}/">${dirName}/</a><br>`;
});

fileList.forEach(file => {
const fileName = file.metadata.name.split('/').pop();
contentList += `<a href="${fileName}">${fileName}</a><br>`;
});

// A trailing slash in the base creates correct relative links when the url is accessed
// without trailing slash
const base = request.originalUrl.endsWith('/') ? request.originalUrl : request.originalUrl + '/';

let directoryListing = `
<base href="${base}">
<h1>Index of ${path}</h1>
<hr>
<pre>${contentList}</pre>`;

return response
.status(200)
.set({
'Cache-Control': `public, max-age=${BROWSER_CACHE_DURATION}, s-maxage=${CDN_CACHE_DURATION}`
})
.sendFile(downloadDestination);
.send(directoryListing);
});

function getContent(options) {
return bucket.getFiles(options).then(data => {
const files = data[0];
const nextQuery = data[1];
const apiResponse = data[2];

if (!files.length && (!apiResponse || !apiResponse.prefixes)) {
return Promise.reject({
code: 404
});
}

fileList = fileList.concat(files);

if (apiResponse && apiResponse.prefixes) {
directoryList = directoryList.concat(apiResponse.prefixes);
}

if (nextQuery) {
// If the results are paged, get the next page
return getContent(nextQuery);
}

return true;
});

}
}
}

Expand Down
10 changes: 0 additions & 10 deletions scripts/code.angularjs.org-firebase/public/index.html

This file was deleted.

0 comments on commit 0179c70

Please sign in to comment.