From df71c90f9f85b1e1f0eecbdf25d749dc96b5b2ff Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 18 Aug 2018 23:48:54 +0900
Subject: [PATCH] wip

---
 CHANGELOG.md                 |   9 +++
 cli/migration/7.0.0.js       | 134 +++++++++++++++++++++++++++++++++++
 package.json                 |   2 +-
 src/models/chart.ts          |  55 ++++++++++++++
 src/models/drive-file.ts     |   5 ++
 src/services/update-chart.ts |  82 ++++++++++++++++-----
 6 files changed, 270 insertions(+), 17 deletions(-)
 create mode 100644 cli/migration/7.0.0.js

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9b5d8c8307..e8879b747a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,15 @@ ChangeLog
 
 This document describes breaking changes only.
 
+7.0.0
+-----
+
+### Migration
+
+起動する前に、`node cli/migration/7.0.0`してください。
+
+Please run `node cli/migration/7.0.0` before launch.
+
 6.0.0
 -----
 
diff --git a/cli/migration/7.0.0.js b/cli/migration/7.0.0.js
new file mode 100644
index 0000000000..d40670c6c0
--- /dev/null
+++ b/cli/migration/7.0.0.js
@@ -0,0 +1,134 @@
+const { default: Chart } = require('../../built/models/chart');
+const { default: User } = require('../../built/models/user');
+const { default: Note } = require('../../built/models/note');
+const { default: DriveFile } = require('../../built/models/drive-file');
+
+const now = new Date();
+const y = now.getFullYear();
+const m = now.getMonth();
+const d = now.getDate();
+const today = new Date(y, m, d);
+
+async function main() {
+	const localUsersCount = await User.count({
+		host: null
+	});
+
+	const remoteUsersCount = await User.count({
+		host: { $ne: null }
+	});
+
+	const localNotesCount = await Note.count({
+		'_user.host': null
+	});
+
+	const remoteNotesCount = await Note.count({
+		'_user.host': { $ne: null }
+	});
+
+	const localDriveFilesCount = await DriveFile.count({
+		'metadata._user.host': null
+	});
+
+	const remoteDriveFilesCount = await DriveFile.count({
+		'metadata._user.host': { $ne: null }
+	});
+
+	const localDriveFilesSize = await DriveFile
+		.aggregate([{
+			$match: {
+				'metadata._user.host': null,
+				'metadata.deletedAt': { $exists: false }
+			}
+		}, {
+			$project: {
+				length: true
+			}
+		}, {
+			$group: {
+				_id: null,
+				usage: { $sum: '$length' }
+			}
+		}])
+		.then(aggregates => {
+			if (aggregates.length > 0) {
+				return aggregates[0].usage;
+			}
+			return 0;
+		});
+
+	const remoteDriveFilesSize = await DriveFile
+		.aggregate([{
+			$match: {
+				'metadata._user.host': { $ne: null },
+				'metadata.deletedAt': { $exists: false }
+			}
+		}, {
+			$project: {
+				length: true
+			}
+		}, {
+			$group: {
+				_id: null,
+				usage: { $sum: '$length' }
+			}
+		}])
+		.then(aggregates => {
+			if (aggregates.length > 0) {
+				return aggregates[0].usage;
+			}
+			return 0;
+		});
+
+	await Chart.insert({
+		date: today,
+		users: {
+			local: {
+				total: localUsersCount,
+				diff: 0
+			},
+			remote: {
+				total: remoteUsersCount,
+				diff: 0
+			}
+		},
+		notes: {
+			local: {
+				total: localNotesCount,
+				diff: 0,
+				diffs: {
+					normal: 0,
+					reply: 0,
+					renote: 0
+				}
+			},
+			remote: {
+				total: remoteNotesCount,
+				diff: 0,
+				diffs: {
+					normal: 0,
+					reply: 0,
+					renote: 0
+				}
+			}
+		},
+		drive: {
+			local: {
+				totalCount: localDriveFilesCount,
+				totalSize: localDriveFilesSize,
+				diffCount: 0,
+				diffSize: 0
+			},
+			remote: {
+				totalCount: remoteDriveFilesCount,
+				totalSize: remoteDriveFilesSize,
+				diffCount: 0,
+				diffSize: 0
+			}
+		}
+	});
+
+	console.log('done');
+}
+
+main();
diff --git a/package.json b/package.json
index 1101230f61..ff5eeae3f5 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "6.4.1",
+	"version": "7.0.0",
 	"clientVersion": "1.0.8520",
 	"codename": "nighthike",
 	"main": "./built/index.js",
diff --git a/src/models/chart.ts b/src/models/chart.ts
index e7e85c9481..a2154be4fc 100644
--- a/src/models/chart.ts
+++ b/src/models/chart.ts
@@ -10,6 +10,9 @@ export interface IChart {
 
 	date: Date;
 
+	/**
+	 * ユーザーに関する統計
+	 */
 	users: {
 		local: {
 			/**
@@ -36,6 +39,9 @@ export interface IChart {
 		};
 	};
 
+	/**
+	 * 投稿に関する統計
+	 */
 	notes: {
 		local: {
 			/**
@@ -95,4 +101,53 @@ export interface IChart {
 			};
 		};
 	};
+
+	/**
+	 * ドライブ(のファイル)に関する統計
+	 */
+	drive: {
+		local: {
+			/**
+			 * この日時点での、ローカルのドライブファイル数の総計
+			 */
+			totalCount: number;
+
+			/**
+			 * この日時点での、ローカルのドライブファイルサイズの総計
+			 */
+			totalSize: number;
+
+			/**
+			 * ローカルのドライブファイル数の前日比
+			 */
+			diffCount: number;
+
+			/**
+			 * ローカルのドライブファイルサイズの前日比
+			 */
+			diffSize: number;
+		};
+
+		remote: {
+			/**
+			 * この日時点での、リモートのドライブファイル数の総計
+			 */
+			totalCount: number;
+
+			/**
+			 * この日時点での、リモートのドライブファイルサイズの総計
+			 */
+			totalSize: number;
+
+			/**
+			 * リモートのドライブファイル数の前日比
+			 */
+			diffCount: number;
+
+			/**
+			 * リモートのドライブファイルサイズの前日比
+			 */
+			diffSize: number;
+		};
+	};
 }
diff --git a/src/models/drive-file.ts b/src/models/drive-file.ts
index 2b9efc404d..dbbc1f1cd5 100644
--- a/src/models/drive-file.ts
+++ b/src/models/drive-file.ts
@@ -52,6 +52,11 @@ export type IDriveFile = {
 	filename: string;
 	contentType: string;
 	metadata: IMetadata;
+
+	/**
+	 * ファイルサイズ
+	 */
+	length: number;
 };
 
 export function validateFileName(name: string): boolean {
diff --git a/src/services/update-chart.ts b/src/services/update-chart.ts
index bd4fcbbeda..64ba9e53cf 100644
--- a/src/services/update-chart.ts
+++ b/src/services/update-chart.ts
@@ -1,6 +1,7 @@
 import { INote } from '../models/note';
 import Chart, { IChart } from '../models/chart';
 import { isLocalUser, IUser } from '../models/user';
+import { IDriveFile } from '../models/drive-file';
 
 type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
 
@@ -63,6 +64,20 @@ async function getTodayStats(): Promise<IChart> {
 							renote: 0
 						}
 					}
+				},
+				drive: {
+					local: {
+						totalCount: 0,
+						totalSize: 0,
+						diffCount: 0,
+						diffSize: 0
+					},
+					remote: {
+						totalCount: 0,
+						totalSize: 0,
+						diffCount: 0,
+						diffSize: 0
+					}
 				}
 			};
 
@@ -102,6 +117,20 @@ async function getTodayStats(): Promise<IChart> {
 							renote: 0
 						}
 					}
+				},
+				drive: {
+					local: {
+						totalCount: mostRecentStats.drive.local.totalCount,
+						totalSize: mostRecentStats.drive.local.totalSize,
+						diffCount: 0,
+						diffSize: 0
+					},
+					remote: {
+						totalCount: mostRecentStats.drive.remote.totalCount,
+						totalSize: mostRecentStats.drive.remote.totalSize,
+						diffCount: 0,
+						diffSize: 0
+					}
 				}
 			};
 
@@ -127,14 +156,14 @@ async function update(inc: any) {
 export async function updateUserStats(user: IUser, isAdditional: boolean) {
 	const inc = {} as any;
 
-	const val = isAdditional ? 1 : -1;
+	const amount = isAdditional ? 1 : -1;
 
 	if (isLocalUser(user)) {
-		inc['users.local.total'] = val;
-		inc['users.local.diff'] = val;
+		inc['users.local.total'] = amount;
+		inc['users.local.diff'] = amount;
 	} else {
-		inc['users.remote.total'] = val;
-		inc['users.remote.diff'] = val;
+		inc['users.remote.total'] = amount;
+		inc['users.remote.diff'] = amount;
 	}
 
 	await update(inc);
@@ -143,31 +172,52 @@ export async function updateUserStats(user: IUser, isAdditional: boolean) {
 export async function updateNoteStats(note: INote, isAdditional: boolean) {
 	const inc = {} as any;
 
-	const val = isAdditional ? 1 : -1;
+	const amount = isAdditional ? 1 : -1;
 
 	if (isLocalUser(note._user)) {
-		inc['notes.local.total'] = val;
-		inc['notes.local.diff'] = val;
+		inc['notes.local.total'] = amount;
+		inc['notes.local.diff'] = amount;
 
 		if (note.replyId != null) {
-			inc['notes.local.diffs.reply'] = val;
+			inc['notes.local.diffs.reply'] = amount;
 		} else if (note.renoteId != null) {
-			inc['notes.local.diffs.renote'] = val;
+			inc['notes.local.diffs.renote'] = amount;
 		} else {
-			inc['notes.local.diffs.normal'] = val;
+			inc['notes.local.diffs.normal'] = amount;
 		}
 	} else {
-		inc['notes.remote.total'] = val;
-		inc['notes.remote.diff'] = val;
+		inc['notes.remote.total'] = amount;
+		inc['notes.remote.diff'] = amount;
 
 		if (note.replyId != null) {
-			inc['notes.remote.diffs.reply'] = val;
+			inc['notes.remote.diffs.reply'] = amount;
 		} else if (note.renoteId != null) {
-			inc['notes.remote.diffs.renote'] = val;
+			inc['notes.remote.diffs.renote'] = amount;
 		} else {
-			inc['notes.remote.diffs.normal'] = val;
+			inc['notes.remote.diffs.normal'] = amount;
 		}
 	}
 
 	await update(inc);
 }
+
+export async function updateDriveStats(user: IUser, file: IDriveFile, isAdditional: boolean) {
+	const inc = {} as any;
+
+	const amount = isAdditional ? 1 : -1;
+	const size = isAdditional ? file.length : -file.length;
+
+	if (isLocalUser(user)) {
+		inc['drive.local.totalCount'] = amount;
+		inc['drive.local.diffCount'] = amount;
+		inc['drive.local.totalSize'] = size;
+		inc['drive.local.diffSize'] = size;
+	} else {
+		inc['drive.remote.total'] = amount;
+		inc['drive.remote.diff'] = amount;
+		inc['drive.remote.totalSize'] = size;
+		inc['drive.remote.diffSize'] = size;
+	}
+
+	await update(inc);
+}