diff options
| author | ha-dai <contact@haradai.net> | 2018-05-04 02:49:46 +0900 |
|---|---|---|
| committer | ha-dai <contact@haradai.net> | 2018-05-04 02:49:46 +0900 |
| commit | f850283147072c681df1b39c57f8bd0b14f18016 (patch) | |
| tree | 63ff533c91097da2d8ca2070fc67a28f67ee33da /src/server/api/endpoints/drive | |
| parent | Merge branch 'master' of github.com:syuilo/misskey (diff) | |
| parent | 1.7.0 (diff) | |
| download | misskey-f850283147072c681df1b39c57f8bd0b14f18016.tar.gz misskey-f850283147072c681df1b39c57f8bd0b14f18016.tar.bz2 misskey-f850283147072c681df1b39c57f8bd0b14f18016.zip | |
Merge branch 'master' of github.com:syuilo/misskey
Diffstat (limited to 'src/server/api/endpoints/drive')
| -rw-r--r-- | src/server/api/endpoints/drive/files.ts | 68 | ||||
| -rw-r--r-- | src/server/api/endpoints/drive/files/create.ts | 46 | ||||
| -rw-r--r-- | src/server/api/endpoints/drive/files/find.ts | 30 | ||||
| -rw-r--r-- | src/server/api/endpoints/drive/files/show.ts | 32 | ||||
| -rw-r--r-- | src/server/api/endpoints/drive/files/update.ts | 71 | ||||
| -rw-r--r-- | src/server/api/endpoints/drive/files/upload_from_url.ts | 22 | ||||
| -rw-r--r-- | src/server/api/endpoints/drive/folders.ts | 61 | ||||
| -rw-r--r-- | src/server/api/endpoints/drive/folders/create.ts | 51 | ||||
| -rw-r--r-- | src/server/api/endpoints/drive/folders/find.ts | 29 | ||||
| -rw-r--r-- | src/server/api/endpoints/drive/folders/show.ts | 30 | ||||
| -rw-r--r-- | src/server/api/endpoints/drive/folders/update.ts | 95 | ||||
| -rw-r--r-- | src/server/api/endpoints/drive/stream.ts | 63 |
12 files changed, 598 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..ab4b18cef4 --- /dev/null +++ b/src/server/api/endpoints/drive/files.ts @@ -0,0 +1,68 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; import ID from '../../../../cafy-id'; +import DriveFile, { pack } from '../../../../models/drive-file'; + +/** + * Get drive files + */ +module.exports = async (params, user, app) => { + // Get 'limit' parameter + const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit); + if (limitErr) throw 'invalid limit param'; + + // Get 'sinceId' parameter + const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId); + if (sinceIdErr) throw 'invalid sinceId param'; + + // Get 'untilId' parameter + const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId); + 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] = $.type(ID).optional().nullable().get(params.folderId); + if (folderIdErr) throw 'invalid folderId param'; + + // Get 'type' parameter + const [type, typeErr] = $.str.optional().match(/^[a-zA-Z\/\-\*]+$/).get(params.type); + 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..e9348e4e2f --- /dev/null +++ b/src/server/api/endpoints/drive/files/create.ts @@ -0,0 +1,46 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; import ID from '../../../../../cafy-id'; +import { validateFileName, pack } from '../../../../../models/drive-file'; +import create from '../../../../../services/drive/add-file'; + +/** + * Create a file + */ +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] = $.type(ID).optional().nullable().get(params.folderId); + 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..98165990fe --- /dev/null +++ b/src/server/api/endpoints/drive/files/find.ts @@ -0,0 +1,30 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; import ID from '../../../../../cafy-id'; +import DriveFile, { pack } from '../../../../../models/drive-file'; + +/** + * Find a file(s) + */ +module.exports = (params, user) => new Promise(async (res, rej) => { + // Get 'name' parameter + const [name, nameErr] = $.str.get(params.name); + if (nameErr) return rej('invalid name param'); + + // Get 'folderId' parameter + const [folderId = null, folderIdErr] = $.type(ID).optional().nullable().get(params.folderId); + 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..c7efda7ab0 --- /dev/null +++ b/src/server/api/endpoints/drive/files/show.ts @@ -0,0 +1,32 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; import ID from '../../../../../cafy-id'; +import DriveFile, { pack } from '../../../../../models/drive-file'; + +/** + * Show a file + */ +module.exports = async (params, user) => { + // Get 'fileId' parameter + const [fileId, fileIdErr] = $.type(ID).get(params.fileId); + 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..12fa8e025d --- /dev/null +++ b/src/server/api/endpoints/drive/files/update.ts @@ -0,0 +1,71 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; import ID from '../../../../../cafy-id'; +import DriveFolder from '../../../../../models/drive-folder'; +import DriveFile, { validateFileName, pack } from '../../../../../models/drive-file'; +import { publishDriveStream } from '../../../../../publishers/stream'; + +/** + * Update a file + */ +module.exports = (params, user) => new Promise(async (res, rej) => { + // Get 'fileId' parameter + const [fileId, fileIdErr] = $.type(ID).get(params.fileId); + 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] = $.str.optional().pipe(validateFileName).get(params.name); + if (nameErr) return rej('invalid name param'); + if (name) file.filename = name; + + // Get 'folderId' parameter + const [folderId, folderIdErr] = $.type(ID).optional().nullable().get(params.folderId); + 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..c012f0d3c9 --- /dev/null +++ b/src/server/api/endpoints/drive/files/upload_from_url.ts @@ -0,0 +1,22 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; import ID from '../../../../../cafy-id'; +import { pack } from '../../../../../models/drive-file'; +import uploadFromUrl from '../../../../../services/drive/upload-from-url'; + +/** + * Create a file from a URL + */ +module.exports = async (params, user): Promise<any> => { + // Get 'url' parameter + // TODO: Validate this url + const [url, urlErr] = $.str.get(params.url); + if (urlErr) throw 'invalid url param'; + + // Get 'folderId' parameter + const [folderId = null, folderIdErr] = $.type(ID).optional().nullable().get(params.folderId); + 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..bc6c50eb99 --- /dev/null +++ b/src/server/api/endpoints/drive/folders.ts @@ -0,0 +1,61 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; import ID from '../../../../cafy-id'; +import DriveFolder, { pack } from '../../../../models/drive-folder'; + +/** + * Get drive folders + */ +module.exports = (params, user, app) => new Promise(async (res, rej) => { + // Get 'limit' parameter + const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit); + if (limitErr) return rej('invalid limit param'); + + // Get 'sinceId' parameter + const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId); + if (sinceIdErr) return rej('invalid sinceId param'); + + // Get 'untilId' parameter + const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId); + 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] = $.type(ID).optional().nullable().get(params.folderId); + 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..62e3b6f6e8 --- /dev/null +++ b/src/server/api/endpoints/drive/folders/create.ts @@ -0,0 +1,51 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; import ID from '../../../../../cafy-id'; +import DriveFolder, { isValidFolderName, pack } from '../../../../../models/drive-folder'; +import { publishDriveStream } from '../../../../../publishers/stream'; + +/** + * Create drive folder + */ +module.exports = (params, user) => new Promise(async (res, rej) => { + // Get 'name' parameter + const [name = '無題のフォルダー', nameErr] = $.str.optional().pipe(isValidFolderName).get(params.name); + if (nameErr) return rej('invalid name param'); + + // Get 'parentId' parameter + const [parentId = null, parentIdErr] = $.type(ID).optional().nullable().get(params.parentId); + 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..9703d9e99d --- /dev/null +++ b/src/server/api/endpoints/drive/folders/find.ts @@ -0,0 +1,29 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; import ID from '../../../../../cafy-id'; +import DriveFolder, { pack } from '../../../../../models/drive-folder'; + +/** + * Find a folder(s) + */ +module.exports = (params, user) => new Promise(async (res, rej) => { + // Get 'name' parameter + const [name, nameErr] = $.str.get(params.name); + if (nameErr) return rej('invalid name param'); + + // Get 'parentId' parameter + const [parentId = null, parentIdErr] = $.type(ID).optional().nullable().get(params.parentId); + 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..44f1889001 --- /dev/null +++ b/src/server/api/endpoints/drive/folders/show.ts @@ -0,0 +1,30 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; import ID from '../../../../../cafy-id'; +import DriveFolder, { pack } from '../../../../../models/drive-folder'; + +/** + * Show a folder + */ +module.exports = (params, user) => new Promise(async (res, rej) => { + // Get 'folderId' parameter + const [folderId, folderIdErr] = $.type(ID).get(params.folderId); + 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..e24d8a14cd --- /dev/null +++ b/src/server/api/endpoints/drive/folders/update.ts @@ -0,0 +1,95 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; import ID from '../../../../../cafy-id'; +import DriveFolder, { isValidFolderName, pack } from '../../../../../models/drive-folder'; +import { publishDriveStream } from '../../../../../publishers/stream'; + +/** + * Update a folder + */ +module.exports = (params, user) => new Promise(async (res, rej) => { + // Get 'folderId' parameter + const [folderId, folderIdErr] = $.type(ID).get(params.folderId); + 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] = $.str.optional().pipe(isValidFolderName).get(params.name); + if (nameErr) return rej('invalid name param'); + if (name) folder.name = name; + + // Get 'parentId' parameter + const [parentId, parentIdErr] = $.type(ID).optional().nullable().get(params.parentId); + 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..8cb3a99b42 --- /dev/null +++ b/src/server/api/endpoints/drive/stream.ts @@ -0,0 +1,63 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; import ID from '../../../../cafy-id'; +import DriveFile, { pack } from '../../../../models/drive-file'; + +/** + * Get drive stream + */ +module.exports = (params, user) => new Promise(async (res, rej) => { + // Get 'limit' parameter + const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit); + if (limitErr) return rej('invalid limit param'); + + // Get 'sinceId' parameter + const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId); + if (sinceIdErr) return rej('invalid sinceId param'); + + // Get 'untilId' parameter + const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId); + 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] = $.str.optional().match(/^[a-zA-Z\/\-\*]+$/).get(params.type); + 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)))); +}); |