summaryrefslogtreecommitdiff
path: root/src/server/api/endpoints/drive
diff options
context:
space:
mode:
authorha-dai <contact@haradai.net>2018-05-04 02:49:46 +0900
committerha-dai <contact@haradai.net>2018-05-04 02:49:46 +0900
commitf850283147072c681df1b39c57f8bd0b14f18016 (patch)
tree63ff533c91097da2d8ca2070fc67a28f67ee33da /src/server/api/endpoints/drive
parentMerge branch 'master' of github.com:syuilo/misskey (diff)
parent1.7.0 (diff)
downloadmisskey-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.ts68
-rw-r--r--src/server/api/endpoints/drive/files/create.ts46
-rw-r--r--src/server/api/endpoints/drive/files/find.ts30
-rw-r--r--src/server/api/endpoints/drive/files/show.ts32
-rw-r--r--src/server/api/endpoints/drive/files/update.ts71
-rw-r--r--src/server/api/endpoints/drive/files/upload_from_url.ts22
-rw-r--r--src/server/api/endpoints/drive/folders.ts61
-rw-r--r--src/server/api/endpoints/drive/folders/create.ts51
-rw-r--r--src/server/api/endpoints/drive/folders/find.ts29
-rw-r--r--src/server/api/endpoints/drive/folders/show.ts30
-rw-r--r--src/server/api/endpoints/drive/folders/update.ts95
-rw-r--r--src/server/api/endpoints/drive/stream.ts63
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))));
+});