diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2018-03-29 14:51:06 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-03-29 14:51:06 +0900 |
| commit | 0b5597c873d2d9d45be94a18e1b74f44d9925185 (patch) | |
| tree | 8b4dac3a56cf703650c8207f9279028a8560a96b /src/server/api/endpoints/drive | |
| parent | oops (diff) | |
| parent | Resolve conflicts (diff) | |
| download | sharkey-0b5597c873d2d9d45be94a18e1b74f44d9925185.tar.gz sharkey-0b5597c873d2d9d45be94a18e1b74f44d9925185.tar.bz2 sharkey-0b5597c873d2d9d45be94a18e1b74f44d9925185.zip | |
Merge pull request #1332 from syuilo/pr/1327
Pr/1327
Diffstat (limited to 'src/server/api/endpoints/drive')
| -rw-r--r-- | src/server/api/endpoints/drive/files.ts | 73 | ||||
| -rw-r--r-- | src/server/api/endpoints/drive/files/create.ts | 51 | ||||
| -rw-r--r-- | src/server/api/endpoints/drive/files/find.ts | 34 | ||||
| -rw-r--r-- | src/server/api/endpoints/drive/files/show.ts | 36 | ||||
| -rw-r--r-- | src/server/api/endpoints/drive/files/update.ts | 75 | ||||
| -rw-r--r-- | src/server/api/endpoints/drive/files/upload_from_url.ts | 26 | ||||
| -rw-r--r-- | src/server/api/endpoints/drive/folders.ts | 66 | ||||
| -rw-r--r-- | src/server/api/endpoints/drive/folders/create.ts | 55 | ||||
| -rw-r--r-- | src/server/api/endpoints/drive/folders/find.ts | 33 | ||||
| -rw-r--r-- | src/server/api/endpoints/drive/folders/show.ts | 34 | ||||
| -rw-r--r-- | src/server/api/endpoints/drive/folders/update.ts | 99 | ||||
| -rw-r--r-- | src/server/api/endpoints/drive/stream.ts | 67 |
12 files changed, 649 insertions, 0 deletions
diff --git a/src/server/api/endpoints/drive/files.ts b/src/server/api/endpoints/drive/files.ts new file mode 100644 index 0000000000..f982ef62e0 --- /dev/null +++ b/src/server/api/endpoints/drive/files.ts @@ -0,0 +1,73 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; +import DriveFile, { pack } from '../../models/drive-file'; + +/** + * Get drive files + * + * @param {any} params + * @param {any} user + * @param {any} app + * @return {Promise<any>} + */ +module.exports = async (params, user, app) => { + // Get 'limit' parameter + const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$; + if (limitErr) throw 'invalid limit param'; + + // Get 'sinceId' parameter + const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$; + if (sinceIdErr) throw 'invalid sinceId param'; + + // Get 'untilId' parameter + const [untilId, untilIdErr] = $(params.untilId).optional.id().$; + if (untilIdErr) throw 'invalid untilId param'; + + // Check if both of sinceId and untilId is specified + if (sinceId && untilId) { + throw 'cannot set sinceId and untilId'; + } + + // Get 'folderId' parameter + const [folderId = null, folderIdErr] = $(params.folderId).optional.nullable.id().$; + if (folderIdErr) throw 'invalid folderId param'; + + // Get 'type' parameter + const [type, typeErr] = $(params.type).optional.string().match(/^[a-zA-Z\/\-\*]+$/).$; + if (typeErr) throw 'invalid type param'; + + // Construct query + const sort = { + _id: -1 + }; + const query = { + 'metadata.userId': user._id, + 'metadata.folderId': folderId + } as any; + if (sinceId) { + sort._id = 1; + query._id = { + $gt: sinceId + }; + } else if (untilId) { + query._id = { + $lt: untilId + }; + } + if (type) { + query.contentType = new RegExp(`^${type.replace(/\*/g, '.+?')}$`); + } + + // Issue query + const files = await DriveFile + .find(query, { + limit: limit, + sort: sort + }); + + // Serialize + const _files = await Promise.all(files.map(file => pack(file))); + return _files; +}; diff --git a/src/server/api/endpoints/drive/files/create.ts b/src/server/api/endpoints/drive/files/create.ts new file mode 100644 index 0000000000..2cd89a8fac --- /dev/null +++ b/src/server/api/endpoints/drive/files/create.ts @@ -0,0 +1,51 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; +import { validateFileName, pack } from '../../../models/drive-file'; +import create from '../../../common/drive/add-file'; + +/** + * Create a file + * + * @param {any} file + * @param {any} params + * @param {any} user + * @return {Promise<any>} + */ +module.exports = async (file, params, user): Promise<any> => { + if (file == null) { + throw 'file is required'; + } + + // Get 'name' parameter + let name = file.originalname; + if (name !== undefined && name !== null) { + name = name.trim(); + if (name.length === 0) { + name = null; + } else if (name === 'blob') { + name = null; + } else if (!validateFileName(name)) { + throw 'invalid name'; + } + } else { + name = null; + } + + // Get 'folderId' parameter + const [folderId = null, folderIdErr] = $(params.folderId).optional.nullable.id().$; + if (folderIdErr) throw 'invalid folderId param'; + + try { + // Create file + const driveFile = await create(user, file.path, name, null, folderId); + + // Serialize + return pack(driveFile); + } catch (e) { + console.error(e); + + throw e; + } +}; diff --git a/src/server/api/endpoints/drive/files/find.ts b/src/server/api/endpoints/drive/files/find.ts new file mode 100644 index 0000000000..47ce891305 --- /dev/null +++ b/src/server/api/endpoints/drive/files/find.ts @@ -0,0 +1,34 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; +import DriveFile, { pack } from '../../../models/drive-file'; + +/** + * Find a file(s) + * + * @param {any} params + * @param {any} user + * @return {Promise<any>} + */ +module.exports = (params, user) => new Promise(async (res, rej) => { + // Get 'name' parameter + const [name, nameErr] = $(params.name).string().$; + if (nameErr) return rej('invalid name param'); + + // Get 'folderId' parameter + const [folderId = null, folderIdErr] = $(params.folderId).optional.nullable.id().$; + if (folderIdErr) return rej('invalid folderId param'); + + // Issue query + const files = await DriveFile + .find({ + filename: name, + 'metadata.userId': user._id, + 'metadata.folderId': folderId + }); + + // Serialize + res(await Promise.all(files.map(async file => + await pack(file)))); +}); diff --git a/src/server/api/endpoints/drive/files/show.ts b/src/server/api/endpoints/drive/files/show.ts new file mode 100644 index 0000000000..63920db7fc --- /dev/null +++ b/src/server/api/endpoints/drive/files/show.ts @@ -0,0 +1,36 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; +import DriveFile, { pack } from '../../../models/drive-file'; + +/** + * Show a file + * + * @param {any} params + * @param {any} user + * @return {Promise<any>} + */ +module.exports = async (params, user) => { + // Get 'fileId' parameter + const [fileId, fileIdErr] = $(params.fileId).id().$; + if (fileIdErr) throw 'invalid fileId param'; + + // Fetch file + const file = await DriveFile + .findOne({ + _id: fileId, + 'metadata.userId': user._id + }); + + if (file === null) { + throw 'file-not-found'; + } + + // Serialize + const _file = await pack(file, { + detail: true + }); + + return _file; +}; diff --git a/src/server/api/endpoints/drive/files/update.ts b/src/server/api/endpoints/drive/files/update.ts new file mode 100644 index 0000000000..bfad45b0a2 --- /dev/null +++ b/src/server/api/endpoints/drive/files/update.ts @@ -0,0 +1,75 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; +import DriveFolder from '../../../models/drive-folder'; +import DriveFile, { validateFileName, pack } from '../../../models/drive-file'; +import { publishDriveStream } from '../../../event'; + +/** + * Update a file + * + * @param {any} params + * @param {any} user + * @return {Promise<any>} + */ +module.exports = (params, user) => new Promise(async (res, rej) => { + // Get 'fileId' parameter + const [fileId, fileIdErr] = $(params.fileId).id().$; + if (fileIdErr) return rej('invalid fileId param'); + + // Fetch file + const file = await DriveFile + .findOne({ + _id: fileId, + 'metadata.userId': user._id + }); + + if (file === null) { + return rej('file-not-found'); + } + + // Get 'name' parameter + const [name, nameErr] = $(params.name).optional.string().pipe(validateFileName).$; + if (nameErr) return rej('invalid name param'); + if (name) file.filename = name; + + // Get 'folderId' parameter + const [folderId, folderIdErr] = $(params.folderId).optional.nullable.id().$; + if (folderIdErr) return rej('invalid folderId param'); + + if (folderId !== undefined) { + if (folderId === null) { + file.metadata.folderId = null; + } else { + // Fetch folder + const folder = await DriveFolder + .findOne({ + _id: folderId, + userId: user._id + }); + + if (folder === null) { + return rej('folder-not-found'); + } + + file.metadata.folderId = folder._id; + } + } + + await DriveFile.update(file._id, { + $set: { + filename: file.filename, + 'metadata.folderId': file.metadata.folderId + } + }); + + // Serialize + const fileObj = await pack(file); + + // Response + res(fileObj); + + // Publish file_updated event + publishDriveStream(user._id, 'file_updated', fileObj); +}); diff --git a/src/server/api/endpoints/drive/files/upload_from_url.ts b/src/server/api/endpoints/drive/files/upload_from_url.ts new file mode 100644 index 0000000000..1a4ce0bf08 --- /dev/null +++ b/src/server/api/endpoints/drive/files/upload_from_url.ts @@ -0,0 +1,26 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; +import { pack } from '../../../models/drive-file'; +import uploadFromUrl from '../../../common/drive/upload_from_url'; + +/** + * Create a file from a URL + * + * @param {any} params + * @param {any} user + * @return {Promise<any>} + */ +module.exports = async (params, user): Promise<any> => { + // Get 'url' parameter + // TODO: Validate this url + const [url, urlErr] = $(params.url).string().$; + if (urlErr) throw 'invalid url param'; + + // Get 'folderId' parameter + const [folderId = null, folderIdErr] = $(params.folderId).optional.nullable.id().$; + if (folderIdErr) throw 'invalid folderId param'; + + return pack(await uploadFromUrl(url, user, folderId)); +}; diff --git a/src/server/api/endpoints/drive/folders.ts b/src/server/api/endpoints/drive/folders.ts new file mode 100644 index 0000000000..c314837f72 --- /dev/null +++ b/src/server/api/endpoints/drive/folders.ts @@ -0,0 +1,66 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; +import DriveFolder, { pack } from '../../models/drive-folder'; + +/** + * Get drive folders + * + * @param {any} params + * @param {any} user + * @param {any} app + * @return {Promise<any>} + */ +module.exports = (params, user, app) => new Promise(async (res, rej) => { + // Get 'limit' parameter + const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$; + if (limitErr) return rej('invalid limit param'); + + // Get 'sinceId' parameter + const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$; + if (sinceIdErr) return rej('invalid sinceId param'); + + // Get 'untilId' parameter + const [untilId, untilIdErr] = $(params.untilId).optional.id().$; + if (untilIdErr) return rej('invalid untilId param'); + + // Check if both of sinceId and untilId is specified + if (sinceId && untilId) { + return rej('cannot set sinceId and untilId'); + } + + // Get 'folderId' parameter + const [folderId = null, folderIdErr] = $(params.folderId).optional.nullable.id().$; + if (folderIdErr) return rej('invalid folderId param'); + + // Construct query + const sort = { + _id: -1 + }; + const query = { + userId: user._id, + parentId: folderId + } as any; + if (sinceId) { + sort._id = 1; + query._id = { + $gt: sinceId + }; + } else if (untilId) { + query._id = { + $lt: untilId + }; + } + + // Issue query + const folders = await DriveFolder + .find(query, { + limit: limit, + sort: sort + }); + + // Serialize + res(await Promise.all(folders.map(async folder => + await pack(folder)))); +}); diff --git a/src/server/api/endpoints/drive/folders/create.ts b/src/server/api/endpoints/drive/folders/create.ts new file mode 100644 index 0000000000..564558606d --- /dev/null +++ b/src/server/api/endpoints/drive/folders/create.ts @@ -0,0 +1,55 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; +import DriveFolder, { isValidFolderName, pack } from '../../../models/drive-folder'; +import { publishDriveStream } from '../../../event'; + +/** + * Create drive folder + * + * @param {any} params + * @param {any} user + * @return {Promise<any>} + */ +module.exports = (params, user) => new Promise(async (res, rej) => { + // Get 'name' parameter + const [name = '無題のフォルダー', nameErr] = $(params.name).optional.string().pipe(isValidFolderName).$; + if (nameErr) return rej('invalid name param'); + + // Get 'parentId' parameter + const [parentId = null, parentIdErr] = $(params.parentId).optional.nullable.id().$; + if (parentIdErr) return rej('invalid parentId param'); + + // If the parent folder is specified + let parent = null; + if (parentId) { + // Fetch parent folder + parent = await DriveFolder + .findOne({ + _id: parentId, + userId: user._id + }); + + if (parent === null) { + return rej('parent-not-found'); + } + } + + // Create folder + const folder = await DriveFolder.insert({ + createdAt: new Date(), + name: name, + parentId: parent !== null ? parent._id : null, + userId: user._id + }); + + // Serialize + const folderObj = await pack(folder); + + // Response + res(folderObj); + + // Publish folder_created event + publishDriveStream(user._id, 'folder_created', folderObj); +}); diff --git a/src/server/api/endpoints/drive/folders/find.ts b/src/server/api/endpoints/drive/folders/find.ts new file mode 100644 index 0000000000..f46aaedd32 --- /dev/null +++ b/src/server/api/endpoints/drive/folders/find.ts @@ -0,0 +1,33 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; +import DriveFolder, { pack } from '../../../models/drive-folder'; + +/** + * Find a folder(s) + * + * @param {any} params + * @param {any} user + * @return {Promise<any>} + */ +module.exports = (params, user) => new Promise(async (res, rej) => { + // Get 'name' parameter + const [name, nameErr] = $(params.name).string().$; + if (nameErr) return rej('invalid name param'); + + // Get 'parentId' parameter + const [parentId = null, parentIdErr] = $(params.parentId).optional.nullable.id().$; + if (parentIdErr) return rej('invalid parentId param'); + + // Issue query + const folders = await DriveFolder + .find({ + name: name, + userId: user._id, + parentId: parentId + }); + + // Serialize + res(await Promise.all(folders.map(folder => pack(folder)))); +}); diff --git a/src/server/api/endpoints/drive/folders/show.ts b/src/server/api/endpoints/drive/folders/show.ts new file mode 100644 index 0000000000..a6d7e86df1 --- /dev/null +++ b/src/server/api/endpoints/drive/folders/show.ts @@ -0,0 +1,34 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; +import DriveFolder, { pack } from '../../../models/drive-folder'; + +/** + * Show a folder + * + * @param {any} params + * @param {any} user + * @return {Promise<any>} + */ +module.exports = (params, user) => new Promise(async (res, rej) => { + // Get 'folderId' parameter + const [folderId, folderIdErr] = $(params.folderId).id().$; + if (folderIdErr) return rej('invalid folderId param'); + + // Get folder + const folder = await DriveFolder + .findOne({ + _id: folderId, + userId: user._id + }); + + if (folder === null) { + return rej('folder-not-found'); + } + + // Serialize + res(await pack(folder, { + detail: true + })); +}); diff --git a/src/server/api/endpoints/drive/folders/update.ts b/src/server/api/endpoints/drive/folders/update.ts new file mode 100644 index 0000000000..fcfd241241 --- /dev/null +++ b/src/server/api/endpoints/drive/folders/update.ts @@ -0,0 +1,99 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; +import DriveFolder, { isValidFolderName, pack } from '../../../models/drive-folder'; +import { publishDriveStream } from '../../../event'; + +/** + * Update a folder + * + * @param {any} params + * @param {any} user + * @return {Promise<any>} + */ +module.exports = (params, user) => new Promise(async (res, rej) => { + // Get 'folderId' parameter + const [folderId, folderIdErr] = $(params.folderId).id().$; + if (folderIdErr) return rej('invalid folderId param'); + + // Fetch folder + const folder = await DriveFolder + .findOne({ + _id: folderId, + userId: user._id + }); + + if (folder === null) { + return rej('folder-not-found'); + } + + // Get 'name' parameter + const [name, nameErr] = $(params.name).optional.string().pipe(isValidFolderName).$; + if (nameErr) return rej('invalid name param'); + if (name) folder.name = name; + + // Get 'parentId' parameter + const [parentId, parentIdErr] = $(params.parentId).optional.nullable.id().$; + if (parentIdErr) return rej('invalid parentId param'); + if (parentId !== undefined) { + if (parentId === null) { + folder.parentId = null; + } else { + // Get parent folder + const parent = await DriveFolder + .findOne({ + _id: parentId, + userId: user._id + }); + + if (parent === null) { + return rej('parent-folder-not-found'); + } + + // Check if the circular reference will occur + async function checkCircle(folderId) { + // Fetch folder + const folder2 = await DriveFolder.findOne({ + _id: folderId + }, { + _id: true, + parentId: true + }); + + if (folder2._id.equals(folder._id)) { + return true; + } else if (folder2.parentId) { + return await checkCircle(folder2.parentId); + } else { + return false; + } + } + + if (parent.parentId !== null) { + if (await checkCircle(parent.parentId)) { + return rej('detected-circular-definition'); + } + } + + folder.parentId = parent._id; + } + } + + // Update + DriveFolder.update(folder._id, { + $set: { + name: folder.name, + parentId: folder.parentId + } + }); + + // Serialize + const folderObj = await pack(folder); + + // Response + res(folderObj); + + // Publish folder_updated event + publishDriveStream(user._id, 'folder_updated', folderObj); +}); diff --git a/src/server/api/endpoints/drive/stream.ts b/src/server/api/endpoints/drive/stream.ts new file mode 100644 index 0000000000..71db38f3b3 --- /dev/null +++ b/src/server/api/endpoints/drive/stream.ts @@ -0,0 +1,67 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; +import DriveFile, { pack } from '../../models/drive-file'; + +/** + * Get drive stream + * + * @param {any} params + * @param {any} user + * @return {Promise<any>} + */ +module.exports = (params, user) => new Promise(async (res, rej) => { + // Get 'limit' parameter + const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$; + if (limitErr) return rej('invalid limit param'); + + // Get 'sinceId' parameter + const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$; + if (sinceIdErr) return rej('invalid sinceId param'); + + // Get 'untilId' parameter + const [untilId, untilIdErr] = $(params.untilId).optional.id().$; + if (untilIdErr) return rej('invalid untilId param'); + + // Check if both of sinceId and untilId is specified + if (sinceId && untilId) { + return rej('cannot set sinceId and untilId'); + } + + // Get 'type' parameter + const [type, typeErr] = $(params.type).optional.string().match(/^[a-zA-Z\/\-\*]+$/).$; + if (typeErr) return rej('invalid type param'); + + // Construct query + const sort = { + _id: -1 + }; + const query = { + 'metadata.userId': user._id + } as any; + if (sinceId) { + sort._id = 1; + query._id = { + $gt: sinceId + }; + } else if (untilId) { + query._id = { + $lt: untilId + }; + } + if (type) { + query.contentType = new RegExp(`^${type.replace(/\*/g, '.+?')}$`); + } + + // Issue query + const files = await DriveFile + .find(query, { + limit: limit, + sort: sort + }); + + // Serialize + res(await Promise.all(files.map(async file => + await pack(file)))); +}); |