diff --git a/backend/docs/api_data.js b/backend/docs/api_data.js
index e251608..82c43d1 100644
--- a/backend/docs/api_data.js
+++ b/backend/docs/api_data.js
@@ -3,7 +3,6 @@ define({ "api": [
"type": "post",
"url": "/api/login",
"title": "Authenticate the user",
- "name": "Login",
"group": "Authenticate",
"parameter": {
"fields": {
@@ -33,13 +32,13 @@ define({ "api": [
"type": "String",
"optional": false,
"field": "token",
- "description": "
User token, valid for 20 minutes .
"
+ "description": "User token, valid for 20 minutes.
"
}
]
},
"examples": [
{
- "title": "Sucess",
+ "title": "Success",
"content": "HTTP/1.1 200 OK\n{\n \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImRhbmllbHJjIiwiaWF0IjoxNTI3MTY1NTg2LCJleHAiOjE1MjcxNjY3ODZ9.VEvOcyPa-LKSr0kJXTa6TvpCqyKmenJRbEgdxNKJjik\" \n}",
"type": "json"
}
@@ -77,6 +76,101 @@ define({ "api": [
},
"version": "0.0.0",
"filename": "routes/login.js",
- "groupTitle": "Authenticate"
+ "groupTitle": "Authenticate",
+ "name": "PostApiLogin"
+ },
+ {
+ "type": "get",
+ "url": "/api/directories",
+ "title": "List items",
+ "group": "Directories",
+ "description": "List items from specified path. The token is needed.
",
+ "header": {
+ "fields": {
+ "Header": [
+ {
+ "group": "Header",
+ "type": "String",
+ "optional": false,
+ "field": "Authorization",
+ "description": "Authorization token.
"
+ }
+ ]
+ }
+ },
+ "parameter": {
+ "fields": {
+ "Parameter": [
+ {
+ "group": "Parameter",
+ "type": "String",
+ "optional": false,
+ "field": "path",
+ "description": "The directory path.
"
+ }
+ ]
+ }
+ },
+ "examples": [
+ {
+ "title": "Example usage",
+ "content": "curl -H \"Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImRhbmllbCIsImlhdCI6MTUyNzI5Mjk2NSwiZXhwIjoxNTI3Mjk0MTY1fQ.M8HAJAjq5E8k-e4LzxMXccG7z5ay4Yrs05ZmhXhMv6g\" http://127.0.0.1:3000/api/directories?path=Documents/example",
+ "type": "curl"
+ }
+ ],
+ "success": {
+ "examples": [
+ {
+ "title": "Success",
+ "content": "HTTP/1.1 200 OK\n{\n \"items\": [\n {\n \"name\": \"dir1\",\n \"path\": \"/dir1\",\n \"isFile\": false\n },\n {\n \"name\": \"file1.txt\",\n \"path\": \"/file1.txt\",\n \"isFile\": true\n }\n ]\n}",
+ "type": "json"
+ }
+ ]
+ },
+ "error": {
+ "fields": {
+ "Error 4xx": [
+ {
+ "group": "Error 4xx",
+ "optional": false,
+ "field": "ENOENT",
+ "description": "No such file or directory.
"
+ },
+ {
+ "group": "Error 4xx",
+ "optional": false,
+ "field": "NoTokenProvided",
+ "description": "No token provided.
"
+ },
+ {
+ "group": "Error 4xx",
+ "optional": false,
+ "field": "InvalidToken",
+ "description": "Invalid token.
"
+ }
+ ]
+ },
+ "examples": [
+ {
+ "title": "ENOENT",
+ "content": "HTTP/1.1 404 NotFound\n{\n \"error\": \"ENOENT: no such file or directory, scandir ''\"\n}",
+ "type": "json"
+ },
+ {
+ "title": "NoTokenProvided",
+ "content": "HTTP/1.1 401 Unauthorized\n{\n \"error\": \"Access denied. No token provided.\"\n}",
+ "type": "json"
+ },
+ {
+ "title": "InvalidToken",
+ "content": "HTTP/1.1 400 BadRequest\n{\n \"error\": \"Invalid token\"\n}",
+ "type": "json"
+ }
+ ]
+ },
+ "version": "0.0.0",
+ "filename": "routes/directories.js",
+ "groupTitle": "Directories",
+ "name": "GetApiDirectories"
}
] });
diff --git a/backend/docs/api_data.json b/backend/docs/api_data.json
index 70874a0..c3edada 100644
--- a/backend/docs/api_data.json
+++ b/backend/docs/api_data.json
@@ -3,7 +3,6 @@
"type": "post",
"url": "/api/login",
"title": "Authenticate the user",
- "name": "Login",
"group": "Authenticate",
"parameter": {
"fields": {
@@ -33,13 +32,13 @@
"type": "String",
"optional": false,
"field": "token",
- "description": "User token, valid for 20 minutes .
"
+ "description": "User token, valid for 20 minutes.
"
}
]
},
"examples": [
{
- "title": "Sucess",
+ "title": "Success",
"content": "HTTP/1.1 200 OK\n{\n \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImRhbmllbHJjIiwiaWF0IjoxNTI3MTY1NTg2LCJleHAiOjE1MjcxNjY3ODZ9.VEvOcyPa-LKSr0kJXTa6TvpCqyKmenJRbEgdxNKJjik\" \n}",
"type": "json"
}
@@ -77,6 +76,101 @@
},
"version": "0.0.0",
"filename": "routes/login.js",
- "groupTitle": "Authenticate"
+ "groupTitle": "Authenticate",
+ "name": "PostApiLogin"
+ },
+ {
+ "type": "get",
+ "url": "/api/directories",
+ "title": "List items",
+ "group": "Directories",
+ "description": "List items from specified path. The token is needed.
",
+ "header": {
+ "fields": {
+ "Header": [
+ {
+ "group": "Header",
+ "type": "String",
+ "optional": false,
+ "field": "Authorization",
+ "description": "Authorization token.
"
+ }
+ ]
+ }
+ },
+ "parameter": {
+ "fields": {
+ "Parameter": [
+ {
+ "group": "Parameter",
+ "type": "String",
+ "optional": false,
+ "field": "path",
+ "description": "The directory path.
"
+ }
+ ]
+ }
+ },
+ "examples": [
+ {
+ "title": "Example usage",
+ "content": "curl -H \"Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImRhbmllbCIsImlhdCI6MTUyNzI5Mjk2NSwiZXhwIjoxNTI3Mjk0MTY1fQ.M8HAJAjq5E8k-e4LzxMXccG7z5ay4Yrs05ZmhXhMv6g\" http://127.0.0.1:3000/api/directories?path=Documents/example",
+ "type": "curl"
+ }
+ ],
+ "success": {
+ "examples": [
+ {
+ "title": "Success",
+ "content": "HTTP/1.1 200 OK\n{\n \"items\": [\n {\n \"name\": \"dir1\",\n \"path\": \"/dir1\",\n \"isFile\": false\n },\n {\n \"name\": \"file1.txt\",\n \"path\": \"/file1.txt\",\n \"isFile\": true\n }\n ]\n}",
+ "type": "json"
+ }
+ ]
+ },
+ "error": {
+ "fields": {
+ "Error 4xx": [
+ {
+ "group": "Error 4xx",
+ "optional": false,
+ "field": "ENOENT",
+ "description": "No such file or directory.
"
+ },
+ {
+ "group": "Error 4xx",
+ "optional": false,
+ "field": "NoTokenProvided",
+ "description": "No token provided.
"
+ },
+ {
+ "group": "Error 4xx",
+ "optional": false,
+ "field": "InvalidToken",
+ "description": "Invalid token.
"
+ }
+ ]
+ },
+ "examples": [
+ {
+ "title": "ENOENT",
+ "content": "HTTP/1.1 404 NotFound\n{\n \"error\": \"ENOENT: no such file or directory, scandir ''\"\n}",
+ "type": "json"
+ },
+ {
+ "title": "NoTokenProvided",
+ "content": "HTTP/1.1 401 Unauthorized\n{\n \"error\": \"Access denied. No token provided.\"\n}",
+ "type": "json"
+ },
+ {
+ "title": "InvalidToken",
+ "content": "HTTP/1.1 400 BadRequest\n{\n \"error\": \"Invalid token\"\n}",
+ "type": "json"
+ }
+ ]
+ },
+ "version": "0.0.0",
+ "filename": "routes/directories.js",
+ "groupTitle": "Directories",
+ "name": "GetApiDirectories"
}
]
diff --git a/backend/docs/api_project.js b/backend/docs/api_project.js
index c1cf591..89c9f1d 100644
--- a/backend/docs/api_project.js
+++ b/backend/docs/api_project.js
@@ -8,7 +8,7 @@ define({
"apidoc": "0.3.0",
"generator": {
"name": "apidoc",
- "time": "2018-05-24T16:32:08.705Z",
+ "time": "2018-05-26T00:22:17.461Z",
"url": "http://apidocjs.com",
"version": "0.17.6"
}
diff --git a/backend/docs/api_project.json b/backend/docs/api_project.json
index c11b6c1..688ccf4 100644
--- a/backend/docs/api_project.json
+++ b/backend/docs/api_project.json
@@ -8,7 +8,7 @@
"apidoc": "0.3.0",
"generator": {
"name": "apidoc",
- "time": "2018-05-24T16:32:08.705Z",
+ "time": "2018-05-26T00:22:17.461Z",
"url": "http://apidocjs.com",
"version": "0.17.6"
}
diff --git a/backend/docs/vendor/path-to-regexp/index.js b/backend/docs/vendor/path-to-regexp/index.js
new file mode 100644
index 0000000..5cb8ed8
--- /dev/null
+++ b/backend/docs/vendor/path-to-regexp/index.js
@@ -0,0 +1,204 @@
+var isArray = Array.isArray || function (arr) {
+ return Object.prototype.toString.call(arr) == '[object Array]';
+};
+
+/**
+ * Expose `pathToRegexp`.
+ */
+// module.exports = pathToRegexp
+
+/**
+ * The main path matching regexp utility.
+ *
+ * @type {RegExp}
+ */
+var PATH_REGEXP = new RegExp([
+ // Match escaped characters that would otherwise appear in future matches.
+ // This allows the user to escape special characters that won't transform.
+ '(\\\\.)',
+ // Match Express-style parameters and un-named parameters with a prefix
+ // and optional suffixes. Matches appear as:
+ //
+ // "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?"]
+ // "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined]
+ '([\\/.])?(?:\\:(\\w+)(?:\\(((?:\\\\.|[^)])*)\\))?|\\(((?:\\\\.|[^)])*)\\))([+*?])?',
+ // Match regexp special characters that are always escaped.
+ '([.+*?=^!:${}()[\\]|\\/])'
+].join('|'), 'g');
+
+/**
+ * Escape the capturing group by escaping special characters and meaning.
+ *
+ * @param {String} group
+ * @return {String}
+ */
+function escapeGroup (group) {
+ return group.replace(/([=!:$\/()])/g, '\\$1');
+}
+
+/**
+ * Attach the keys as a property of the regexp.
+ *
+ * @param {RegExp} re
+ * @param {Array} keys
+ * @return {RegExp}
+ */
+function attachKeys (re, keys) {
+ re.keys = keys;
+ return re;
+}
+
+/**
+ * Get the flags for a regexp from the options.
+ *
+ * @param {Object} options
+ * @return {String}
+ */
+function flags (options) {
+ return options.sensitive ? '' : 'i';
+}
+
+/**
+ * Pull out keys from a regexp.
+ *
+ * @param {RegExp} path
+ * @param {Array} keys
+ * @return {RegExp}
+ */
+function regexpToRegexp (path, keys) {
+ // Use a negative lookahead to match only capturing groups.
+ var groups = path.source.match(/\((?!\?)/g);
+
+ if (groups) {
+ for (var i = 0; i < groups.length; i++) {
+ keys.push({
+ name: i,
+ delimiter: null,
+ optional: false,
+ repeat: false
+ });
+ }
+ }
+
+ return attachKeys(path, keys);
+}
+
+/**
+ * Transform an array into a regexp.
+ *
+ * @param {Array} path
+ * @param {Array} keys
+ * @param {Object} options
+ * @return {RegExp}
+ */
+function arrayToRegexp (path, keys, options) {
+ var parts = [];
+
+ for (var i = 0; i < path.length; i++) {
+ parts.push(pathToRegexp(path[i], keys, options).source);
+ }
+
+ var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options));
+ return attachKeys(regexp, keys);
+}
+
+/**
+ * Replace the specific tags with regexp strings.
+ *
+ * @param {String} path
+ * @param {Array} keys
+ * @return {String}
+ */
+function replacePath (path, keys) {
+ var index = 0;
+
+ function replace (_, escaped, prefix, key, capture, group, suffix, escape) {
+ if (escaped) {
+ return escaped;
+ }
+
+ if (escape) {
+ return '\\' + escape;
+ }
+
+ var repeat = suffix === '+' || suffix === '*';
+ var optional = suffix === '?' || suffix === '*';
+
+ keys.push({
+ name: key || index++,
+ delimiter: prefix || '/',
+ optional: optional,
+ repeat: repeat
+ });
+
+ prefix = prefix ? ('\\' + prefix) : '';
+ capture = escapeGroup(capture || group || '[^' + (prefix || '\\/') + ']+?');
+
+ if (repeat) {
+ capture = capture + '(?:' + prefix + capture + ')*';
+ }
+
+ if (optional) {
+ return '(?:' + prefix + '(' + capture + '))?';
+ }
+
+ // Basic parameter support.
+ return prefix + '(' + capture + ')';
+ }
+
+ return path.replace(PATH_REGEXP, replace);
+}
+
+/**
+ * Normalize the given path string, returning a regular expression.
+ *
+ * An empty array can be passed in for the keys, which will hold the
+ * placeholder key descriptions. For example, using `/user/:id`, `keys` will
+ * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
+ *
+ * @param {(String|RegExp|Array)} path
+ * @param {Array} [keys]
+ * @param {Object} [options]
+ * @return {RegExp}
+ */
+function pathToRegexp (path, keys, options) {
+ keys = keys || [];
+
+ if (!isArray(keys)) {
+ options = keys;
+ keys = [];
+ } else if (!options) {
+ options = {};
+ }
+
+ if (path instanceof RegExp) {
+ return regexpToRegexp(path, keys, options);
+ }
+
+ if (isArray(path)) {
+ return arrayToRegexp(path, keys, options);
+ }
+
+ var strict = options.strict;
+ var end = options.end !== false;
+ var route = replacePath(path, keys);
+ var endsWithSlash = path.charAt(path.length - 1) === '/';
+
+ // In non-strict mode we allow a slash at the end of match. If the path to
+ // match already ends with a slash, we remove it for consistency. The slash
+ // is valid at the end of a path match, not in the middle. This is important
+ // in non-ending mode, where "/test/" shouldn't match "/test//route".
+ if (!strict) {
+ route = (endsWithSlash ? route.slice(0, -2) : route) + '(?:\\/(?=$))?';
+ }
+
+ if (end) {
+ route += '$';
+ } else {
+ // In non-ending mode, we need the capturing groups to match as much as
+ // possible by using a positive lookahead to the end or next path segment.
+ route += strict && endsWithSlash ? '' : '(?=\\/|$)';
+ }
+
+ return attachKeys(new RegExp('^' + route, flags(options)), keys);
+}
diff --git a/backend/routes/directories.js b/backend/routes/directories.js
index 3fc4e62..0c597a4 100644
--- a/backend/routes/directories.js
+++ b/backend/routes/directories.js
@@ -2,5 +2,58 @@ module.exports = function (app) {
var auth = app.middlewares.auth
var directoriesREST = app.controllers.directories
+ /**
+ * @api {get} /api/directories List items
+ * @apiGroup Directories
+ *
+ * @apiDescription
+ * List items from specified path.
+ * The token is needed.
+ *
+ * @apiHeader {String} Authorization Authorization token.
+ *
+ * @apiParam {String} path The directory path.
+ *
+ * @apiExample {curl} Example usage
+ * curl -H "Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImRhbmllbCIsImlhdCI6MTUyNzI5Mjk2NSwiZXhwIjoxNTI3Mjk0MTY1fQ.M8HAJAjq5E8k-e4LzxMXccG7z5ay4Yrs05ZmhXhMv6g" http://127.0.0.1:3000/api/directories?path=Documents/example
+ *
+ * @apiSuccessExample {json} Success
+ * HTTP/1.1 200 OK
+ * {
+ * "items": [
+ * {
+ * "name": "dir1",
+ * "path": "/dir1",
+ * "isFile": false
+ * },
+ * {
+ * "name": "file1.txt",
+ * "path": "/file1.txt",
+ * "isFile": true
+ * }
+ * ]
+ * }
+ *
+ * @apiError ENOENT No such file or directory.
+ * @apiError NoTokenProvided No token provided.
+ * @apiError InvalidToken Invalid token.
+ *
+ * @apiErrorExample {json} ENOENT
+ * HTTP/1.1 404 NotFound
+ * {
+ * "error": "ENOENT: no such file or directory, scandir ''"
+ * }
+ * @apiErrorExample {json} NoTokenProvided
+ * HTTP/1.1 401 Unauthorized
+ * {
+ * "error": "Access denied. No token provided."
+ * }
+ * @apiErrorExample {json} InvalidToken
+ * HTTP/1.1 400 BadRequest
+ * {
+ * "error": "Invalid token"
+ * }
+ *
+ */
app.get('/api/directories', auth, directoriesREST.get)
}
diff --git a/backend/routes/login.js b/backend/routes/login.js
index 85c0b50..412689a 100644
--- a/backend/routes/login.js
+++ b/backend/routes/login.js
@@ -3,7 +3,6 @@ module.exports = (app) => {
/**
* @api {post} /api/login Authenticate the user
- * @apiName Login
* @apiGroup Authenticate
*
* @apiParam {String} username Username of LCCs.
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..48e341a
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,3 @@
+{
+ "lockfileVersion": 1
+}