From 3f2a7a561ee7e008422d4cac3b269beb6006072a Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 6 May 2018 18:04:37 +0900
Subject: [PATCH] =?UTF-8?q?=E3=82=A2=E3=82=A4=E3=82=B3=E3=83=B3=E3=81=AE?=
 =?UTF-8?q?=E3=83=AC=E3=83=B3=E3=83=80=E3=83=AA=E3=83=B3=E3=82=B0=E3=82=92?=
 =?UTF-8?q?=E6=94=B9=E5=96=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 migration/2.4.0.js                            | 69 +++++++++++++++++++
 package.json                                  |  4 +-
 .../app/common/views/components/avatar.vue    | 28 ++++----
 src/client/app/mobile/views/pages/user.vue    |  2 +-
 src/server/api/endpoints/i/update.ts          | 23 +++++++
 5 files changed, 110 insertions(+), 16 deletions(-)
 create mode 100644 migration/2.4.0.js

diff --git a/migration/2.4.0.js b/migration/2.4.0.js
new file mode 100644
index 000000000..d324d4471
--- /dev/null
+++ b/migration/2.4.0.js
@@ -0,0 +1,69 @@
+// for Node.js interpret
+
+const chalk = require('chalk');
+const sequential = require('promise-sequential');
+
+const { default: User } = require('../built/models/user');
+const { default: DriveFile } = require('../built/models/drive-file');
+
+async function main() {
+	const promiseGens = [];
+
+	const count = await User.count({});
+
+	let prev;
+
+	for (let i = 0; i < count; i++) {
+		promiseGens.push(() => {
+			const promise = new Promise(async (res, rej) => {
+				const user = await User.findOne(prev ? {
+					_id: { $gt: prev._id }
+				} : {}, {
+					sort: {
+						_id: 1
+					}
+				});
+
+				prev = user;
+
+				const set = {};
+
+				if (user.avatarId != null) {
+					const file = await DriveFile.findOne({ _id: user.avatarId });
+
+					if (file && file.metadata.properties.avgColor) {
+						set.avatarColor = file.metadata.properties.avgColor;
+					}
+				}
+
+				if (user.bannerId != null) {
+					const file = await DriveFile.findOne({ _id: user.bannerId });
+
+					if (file && file.metadata.properties.avgColor) {
+						set.bannerColor = file.metadata.properties.avgColor;
+					}
+				}
+
+				User.update({
+					_id: user._id
+				}, {
+					$set: set
+				}).then(() => {
+					res([i, user]);
+				}).catch(rej);
+			});
+
+			promise.then(([i, user]) => {
+				console.log(chalk`{gray ${i}} {green done: {bold ${user._id}} @${user.username}}`);
+			});
+
+			return promise;
+		});
+	}
+
+	return await sequential(promiseGens);
+}
+
+main().then(() => {
+	console.log('ALL DONE');
+}).catch(console.error);
diff --git a/package.json b/package.json
index 00447ef69..2e91c381b 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "2.3.1",
-	"clientVersion": "1.0.5207",
+	"version": "2.4.0",
+	"clientVersion": "1.0.5215",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,
diff --git a/src/client/app/common/views/components/avatar.vue b/src/client/app/common/views/components/avatar.vue
index 460c6e23b..60ee06b48 100644
--- a/src/client/app/common/views/components/avatar.vue
+++ b/src/client/app/common/views/components/avatar.vue
@@ -1,8 +1,6 @@
 <template>
-	<router-link class="mk-avatar" :to="user | userPage" :title="user | acct" :target="target" :style="{ borderRadius: clientSettings.circleIcons ? '100%' : null }">
-		<img v-if="disablePreview" :src="`${user.avatarUrl}?thumbnail&size=128`" alt=""/>
-		<img v-else :src="`${user.avatarUrl}?thumbnail&size=128`" alt="" v-user-preview="user.id"/>
-	</router-link>
+	<router-link class="mk-avatar" :to="user | userPage" :title="user | acct" :target="target" :style="style" v-if="disablePreview"></router-link>
+	<router-link class="mk-avatar" :to="user | userPage" :title="user | acct" :target="target" :style="style" v-else v-user-preview="user.id"></router-link>
 </template>
 
 <script lang="ts">
@@ -10,6 +8,7 @@ import Vue from 'vue';
 export default Vue.extend({
 	props: {
 		user: {
+			type: Object,
 			required: true
 		},
 		target: {
@@ -20,6 +19,15 @@ export default Vue.extend({
 			required: false,
 			default: false
 		}
+	},
+	computed: {
+		style(): any {
+			return {
+				backgroundColor: this.user.avatarColor ? `rgb(${ this.user.avatarColor.join(',') })` : null,
+				backgroundImage: `url(${ this.user.avatarUrl }?thumbnail)`,
+				borderRadius: (this as any).clientSettings.circleIcons ? '100%' : null
+			};
+		}
 	}
 });
 </script>
@@ -27,13 +35,7 @@ export default Vue.extend({
 <style lang="stylus" scoped>
 .mk-avatar
 	display inline-block
-
-	> img
-		display inline-block
-		width 100%
-		height 100%
-		margin 0
-		border-radius inherit
-		vertical-align bottom
-		transition border-radius 1s ease
+	background-size cover
+	background-position center center
+	transition border-radius 1s ease
 </style>
diff --git a/src/client/app/mobile/views/pages/user.vue b/src/client/app/mobile/views/pages/user.vue
index c602a2638..12874421d 100644
--- a/src/client/app/mobile/views/pages/user.vue
+++ b/src/client/app/mobile/views/pages/user.vue
@@ -9,7 +9,7 @@
 			<div class="body">
 				<div class="top">
 					<a class="avatar">
-						<img :src="`${user.avatarUrl}?thumbnail&size=200`" alt="avatar"/>
+						<img :src="user.avatarUrl" alt="avatar"/>
 					</a>
 					<mk-follow-button v-if="os.isSignedIn && os.i.id != user.id" :user="user"/>
 				</div>
diff --git a/src/server/api/endpoints/i/update.ts b/src/server/api/endpoints/i/update.ts
index 6ba472995..b7b25d0f6 100644
--- a/src/server/api/endpoints/i/update.ts
+++ b/src/server/api/endpoints/i/update.ts
@@ -4,6 +4,7 @@
 import $ from 'cafy'; import ID from '../../../../cafy-id';
 import User, { isValidName, isValidDescription, isValidLocation, isValidBirthday, pack } from '../../../../models/user';
 import event from '../../../../publishers/stream';
+import DriveFile from '../../../../models/drive-file';
 
 /**
  * Update myself
@@ -51,12 +52,34 @@ module.exports = async (params, user, app) => new Promise(async (res, rej) => {
 	if (autoWatchErr) return rej('invalid autoWatch param');
 	if (autoWatch != null) user.settings.autoWatch = autoWatch;
 
+	if (avatarId) {
+		const avatar = await DriveFile.findOne({
+			_id: avatarId
+		});
+
+		if (avatar != null && avatar.metadata.properties.avgColor) {
+			user.avatarColor = avatar.metadata.properties.avgColor;
+		}
+	}
+
+	if (bannerId) {
+		const banner = await DriveFile.findOne({
+			_id: bannerId
+		});
+
+		if (banner != null && banner.metadata.properties.avgColor) {
+			user.bannerColor = banner.metadata.properties.avgColor;
+		}
+	}
+
 	await User.update(user._id, {
 		$set: {
 			name: user.name,
 			description: user.description,
 			avatarId: user.avatarId,
+			avatarColor: user.avatarColor,
 			bannerId: user.bannerId,
+			bannerColor: user.bannerColor,
 			profile: user.profile,
 			isBot: user.isBot,
 			settings: user.settings