From baf9b658018e6b7d4bc2645eef871e9a57ef23db Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Fri, 5 Oct 2018 01:43:47 +0900
Subject: [PATCH] Improve error handling of packaging functions

---
 package.json                             |  2 +-
 src/models/drive-file.ts                 | 15 ++++++++++++++-
 src/models/note.ts                       | 12 ++++++++----
 src/models/user.ts                       |  2 +-
 src/server/api/endpoints/drive/files.ts  |  5 ++---
 src/server/api/endpoints/drive/stream.ts |  4 ++--
 6 files changed, 28 insertions(+), 12 deletions(-)

diff --git a/package.json b/package.json
index 8e0a8e6250..e04d9d8b4e 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "9.5.0",
+	"version": "9.6.0",
 	"clientVersion": "1.0.10090",
 	"codename": "nighthike",
 	"main": "./built/index.js",
diff --git a/src/models/drive-file.ts b/src/models/drive-file.ts
index 215b49b305..c11121126f 100644
--- a/src/models/drive-file.ts
+++ b/src/models/drive-file.ts
@@ -127,6 +127,15 @@ export async function deleteDriveFile(driveFile: string | mongo.ObjectID | IDriv
 	});
 }
 
+export const packMany = async (
+	files: any[],
+	options?: {
+		detail: boolean
+	}
+) => {
+	return (await Promise.all(files.map(f => pack(f, options)))).filter(x => x != null);
+};
+
 /**
  * Pack a drive file for API response
  */
@@ -155,7 +164,11 @@ export const pack = (
 		_file = deepcopy(file);
 	}
 
-	if (!_file) return reject('invalid file arg.');
+	// (データベースの欠損などで)ファイルがデータベース上に見つからなかったとき
+	if (_file == null) {
+		console.warn(`in packaging driveFile: driveFile not found on database: ${_file}`);
+		return null;
+	}
 
 	// rendered target
 	let _target: any = {};
diff --git a/src/models/note.ts b/src/models/note.ts
index 75518d709f..43b8753195 100644
--- a/src/models/note.ts
+++ b/src/models/note.ts
@@ -7,7 +7,7 @@ import { IUser, pack as packUser } from './user';
 import { pack as packApp } from './app';
 import PollVote, { deletePollVote } from './poll-vote';
 import Reaction, { deleteNoteReaction } from './note-reaction';
-import { pack as packFile, IDriveFile } from './drive-file';
+import { packMany as packFileMany, IDriveFile } from './drive-file';
 import NoteWatching, { deleteNoteWatching } from './note-watching';
 import NoteReaction from './note-reaction';
 import Favorite, { deleteFavorite } from './favorite';
@@ -309,9 +309,7 @@ export const pack = async (
 	}
 
 	// Populate files
-	_note.files = Promise.all((_note.fileIds || []).map((fileId: mongo.ObjectID) =>
-		packFile(fileId)
-	));
+	_note.files = packFileMany(_note.fileIds || []);
 
 	// 後方互換性のため
 	_note.mediaIds = _note.fileIds;
@@ -380,6 +378,12 @@ export const pack = async (
 	// resolve promises in _note object
 	_note = await rap(_note);
 
+	// (データベースの欠損などで)ユーザーがデータベース上に見つからなかったとき
+	if (_note.user == null) {
+		console.warn(`in packaging note: note user not found on database: note(${_note.id})`);
+		return null;
+	}
+
 	if (_note.user.isCat && _note.text) {
 		_note.text = _note.text.replace(/な/g, 'にゃ').replace(/ナ/g, 'ニャ').replace(/ナ/g, 'ニャ');
 	}
diff --git a/src/models/user.ts b/src/models/user.ts
index 3e8aefc4b1..642a993f65 100644
--- a/src/models/user.ts
+++ b/src/models/user.ts
@@ -361,7 +361,7 @@ export const pack = (
 		_user = deepcopy(user);
 	}
 
-	// ユーザーがデータベース上に見つからなかったとき
+	// (データベースの欠損などで)ユーザーがデータベース上に見つからなかったとき
 	if (_user == null) {
 		console.warn(`user not found on database: ${user}`);
 		return null;
diff --git a/src/server/api/endpoints/drive/files.ts b/src/server/api/endpoints/drive/files.ts
index dc6a602e10..de0bde086b 100644
--- a/src/server/api/endpoints/drive/files.ts
+++ b/src/server/api/endpoints/drive/files.ts
@@ -1,5 +1,5 @@
 import $ from 'cafy'; import ID from '../../../../misc/cafy-id';
-import DriveFile, { pack } from '../../../../models/drive-file';
+import DriveFile, { packMany } from '../../../../models/drive-file';
 import { ILocalUser } from '../../../../models/user';
 
 export const meta = {
@@ -73,6 +73,5 @@ export default async (params: any, user: ILocalUser) => {
 		});
 
 	// Serialize
-	const _files = await Promise.all(files.map(file => pack(file)));
-	return _files;
+	return await packMany(files);
 };
diff --git a/src/server/api/endpoints/drive/stream.ts b/src/server/api/endpoints/drive/stream.ts
index a9f3f7e9a5..3ac7dd0234 100644
--- a/src/server/api/endpoints/drive/stream.ts
+++ b/src/server/api/endpoints/drive/stream.ts
@@ -1,5 +1,5 @@
 import $ from 'cafy'; import ID from '../../../../misc/cafy-id';
-import DriveFile, { pack } from '../../../../models/drive-file';
+import DriveFile, { packMany } from '../../../../models/drive-file';
 import { ILocalUser } from '../../../../models/user';
 
 export const meta = {
@@ -63,5 +63,5 @@ export default (params: any, user: ILocalUser) => new Promise(async (res, rej) =
 		});
 
 	// Serialize
-	res(await Promise.all(files.map(file => pack(file))));
+	res(await packMany(files));
 });