From 31006fbc2570a3bf1f013190750b01f56a67c7b1 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Thu, 29 Mar 2018 15:23:15 +0900
Subject: [PATCH] #1253

---
 src/server/api/endpoints/posts/create.ts      |  5 +-
 src/server/api/models/post.ts                 |  4 +-
 .../desktop/views/components/post-detail.vue  |  4 +-
 .../desktop/views/components/post-form.vue    |  3 +-
 .../desktop/views/components/posts.post.vue   |  4 +-
 .../mobile/views/components/post-detail.vue   |  4 +-
 .../app/mobile/views/components/post-form.vue |  3 +-
 .../web/app/mobile/views/components/post.vue  |  4 +-
 src/server/web/docs/api/entities/post.yaml    | 11 ++---
 tools/migration/nighthike/5.js                | 47 +++++++++++++++++++
 10 files changed, 65 insertions(+), 24 deletions(-)
 create mode 100644 tools/migration/nighthike/5.js

diff --git a/src/server/api/endpoints/posts/create.ts b/src/server/api/endpoints/posts/create.ts
index 390370ad42..33042a51a2 100644
--- a/src/server/api/endpoints/posts/create.ts
+++ b/src/server/api/endpoints/posts/create.ts
@@ -43,8 +43,9 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
 
 	// Get 'geo' parameter
 	const [geo, geoErr] = $(params.geo).optional.nullable.strict.object()
-		.have('latitude', $().number().range(-90, 90))
-		.have('longitude', $().number().range(-180, 180))
+		.have('coordinates', $().array().length(2)
+			.item(0, $().number().range(-180, 180))
+			.item(1, $().number().range(-90, 90)))
 		.have('altitude', $().nullable.number())
 		.have('accuracy', $().nullable.number())
 		.have('altitudeAccuracy', $().nullable.number())
diff --git a/src/server/api/models/post.ts b/src/server/api/models/post.ts
index 0317cff3fa..1bf4e09051 100644
--- a/src/server/api/models/post.ts
+++ b/src/server/api/models/post.ts
@@ -35,8 +35,7 @@ export type IPost = {
 	reactionCounts: any;
 	mentions: mongo.ObjectID[];
 	geo: {
-		latitude: number;
-		longitude: number;
+		coordinates: number[];
 		altitude: number;
 		accuracy: number;
 		altitudeAccuracy: number;
@@ -97,6 +96,7 @@ export const pack = async (
 	delete _post._id;
 
 	delete _post.mentions;
+	if (_post.geo) delete _post.geo.type;
 
 	// Parse text
 	if (_post.text) {
diff --git a/src/server/web/app/desktop/views/components/post-detail.vue b/src/server/web/app/desktop/views/components/post-detail.vue
index 7783ec62c7..5c7a7dfdbe 100644
--- a/src/server/web/app/desktop/views/components/post-detail.vue
+++ b/src/server/web/app/desktop/views/components/post-detail.vue
@@ -47,7 +47,7 @@
 			<div class="tags" v-if="p.tags && p.tags.length > 0">
 				<router-link v-for="tag in p.tags" :key="tag" :to="`/search?q=#${tag}`">{{ tag }}</router-link>
 			</div>
-			<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.latitude},${p.geo.longitude}`" target="_blank">%fa:map-marker-alt% 位置情報</a>
+			<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% 位置情報</a>
 			<div class="map" v-if="p.geo" ref="map"></div>
 			<div class="repost" v-if="p.repost">
 				<mk-post-preview :post="p.repost"/>
@@ -157,7 +157,7 @@ export default Vue.extend({
 			const shouldShowMap = (this as any).os.isSignedIn ? (this as any).os.i.account.clientSettings.showMaps : true;
 			if (shouldShowMap) {
 				(this as any).os.getGoogleMaps().then(maps => {
-					const uluru = new maps.LatLng(this.p.geo.latitude, this.p.geo.longitude);
+					const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]);
 					const map = new maps.Map(this.$refs.map, {
 						center: uluru,
 						zoom: 15
diff --git a/src/server/web/app/desktop/views/components/post-form.vue b/src/server/web/app/desktop/views/components/post-form.vue
index 11028ceb52..1c83a38b64 100644
--- a/src/server/web/app/desktop/views/components/post-form.vue
+++ b/src/server/web/app/desktop/views/components/post-form.vue
@@ -224,8 +224,7 @@ export default Vue.extend({
 				repostId: this.repost ? this.repost.id : undefined,
 				poll: this.poll ? (this.$refs.poll as any).get() : undefined,
 				geo: this.geo ? {
-					latitude: this.geo.latitude,
-					longitude: this.geo.longitude,
+					coordinates: [this.geo.longitude, this.geo.latitude],
 					altitude: this.geo.altitude,
 					accuracy: this.geo.accuracy,
 					altitudeAccuracy: this.geo.altitudeAccuracy,
diff --git a/src/server/web/app/desktop/views/components/posts.post.vue b/src/server/web/app/desktop/views/components/posts.post.vue
index c70e019115..37c6e63043 100644
--- a/src/server/web/app/desktop/views/components/posts.post.vue
+++ b/src/server/web/app/desktop/views/components/posts.post.vue
@@ -48,7 +48,7 @@
 				<div class="tags" v-if="p.tags && p.tags.length > 0">
 					<router-link v-for="tag in p.tags" :key="tag" :to="`/search?q=#${tag}`">{{ tag }}</router-link>
 				</div>
-				<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.latitude},${p.geo.longitude}`" target="_blank">%fa:map-marker-alt% 位置情報</a>
+				<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% 位置情報</a>
 				<div class="map" v-if="p.geo" ref="map"></div>
 				<div class="repost" v-if="p.repost">
 					<mk-post-preview :post="p.repost"/>
@@ -169,7 +169,7 @@ export default Vue.extend({
 			const shouldShowMap = (this as any).os.isSignedIn ? (this as any).os.i.account.clientSettings.showMaps : true;
 			if (shouldShowMap) {
 				(this as any).os.getGoogleMaps().then(maps => {
-					const uluru = new maps.LatLng(this.p.geo.latitude, this.p.geo.longitude);
+					const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]);
 					const map = new maps.Map(this.$refs.map, {
 						center: uluru,
 						zoom: 15
diff --git a/src/server/web/app/mobile/views/components/post-detail.vue b/src/server/web/app/mobile/views/components/post-detail.vue
index 29993c79ed..f0af1a61aa 100644
--- a/src/server/web/app/mobile/views/components/post-detail.vue
+++ b/src/server/web/app/mobile/views/components/post-detail.vue
@@ -47,7 +47,7 @@
 			</div>
 			<mk-poll v-if="p.poll" :post="p"/>
 			<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
-			<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.latitude},${p.geo.longitude}`" target="_blank">%fa:map-marker-alt% 位置情報</a>
+			<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% 位置情報</a>
 			<div class="map" v-if="p.geo" ref="map"></div>
 			<div class="repost" v-if="p.repost">
 				<mk-post-preview :post="p.repost"/>
@@ -154,7 +154,7 @@ export default Vue.extend({
 			const shouldShowMap = (this as any).os.isSignedIn ? (this as any).os.i.account.clientSettings.showMaps : true;
 			if (shouldShowMap) {
 				(this as any).os.getGoogleMaps().then(maps => {
-					const uluru = new maps.LatLng(this.p.geo.latitude, this.p.geo.longitude);
+					const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]);
 					const map = new maps.Map(this.$refs.map, {
 						center: uluru,
 						zoom: 15
diff --git a/src/server/web/app/mobile/views/components/post-form.vue b/src/server/web/app/mobile/views/components/post-form.vue
index 929dc5933b..5b78a25710 100644
--- a/src/server/web/app/mobile/views/components/post-form.vue
+++ b/src/server/web/app/mobile/views/components/post-form.vue
@@ -118,8 +118,7 @@ export default Vue.extend({
 				replyId: this.reply ? this.reply.id : undefined,
 				poll: this.poll ? (this.$refs.poll as any).get() : undefined,
 				geo: this.geo ? {
-					latitude: this.geo.latitude,
-					longitude: this.geo.longitude,
+					coordinates: [this.geo.longitude, this.geo.latitude],
 					altitude: this.geo.altitude,
 					accuracy: this.geo.accuracy,
 					altitudeAccuracy: this.geo.altitudeAccuracy,
diff --git a/src/server/web/app/mobile/views/components/post.vue b/src/server/web/app/mobile/views/components/post.vue
index 66c595f4e9..a01eb7669e 100644
--- a/src/server/web/app/mobile/views/components/post.vue
+++ b/src/server/web/app/mobile/views/components/post.vue
@@ -48,7 +48,7 @@
 					<router-link v-for="tag in p.tags" :key="tag" :to="`/search?q=#${tag}`">{{ tag }}</router-link>
 				</div>
 				<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
-				<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.latitude},${p.geo.longitude}`" target="_blank">%fa:map-marker-alt% 位置情報</a>
+				<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% 位置情報</a>
 				<div class="map" v-if="p.geo" ref="map"></div>
 				<span class="app" v-if="p.app">via <b>{{ p.app.name }}</b></span>
 				<div class="repost" v-if="p.repost">
@@ -147,7 +147,7 @@ export default Vue.extend({
 			const shouldShowMap = (this as any).os.isSignedIn ? (this as any).os.i.account.clientSettings.showMaps : true;
 			if (shouldShowMap) {
 				(this as any).os.getGoogleMaps().then(maps => {
-					const uluru = new maps.LatLng(this.p.geo.latitude, this.p.geo.longitude);
+					const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]);
 					const map = new maps.Map(this.$refs.map, {
 						center: uluru,
 						zoom: 15
diff --git a/src/server/web/docs/api/entities/post.yaml b/src/server/web/docs/api/entities/post.yaml
index 71b6a64123..74d7973e38 100644
--- a/src/server/web/docs/api/entities/post.yaml
+++ b/src/server/web/docs/api/entities/post.yaml
@@ -136,16 +136,11 @@ props:
       en: "Geo location"
     defName: "geo"
     def:
-      - name: "latitude"
-        type: "number"
+      - name: "coordinates"
+        type: "number[]"
         optional: false
         desc:
-          ja: "緯度。-90〜90で表す。"
-      - name: "longitude"
-        type: "number"
-        optional: false
-        desc:
-          ja: "経度。-180〜180で表す。"
+          ja: "座標。最初に経度:-180〜180で表す。最後に緯度:-90〜90で表す。"
       - name: "altitude"
         type: "number"
         optional: false
diff --git a/tools/migration/nighthike/5.js b/tools/migration/nighthike/5.js
new file mode 100644
index 0000000000..fb72b69076
--- /dev/null
+++ b/tools/migration/nighthike/5.js
@@ -0,0 +1,47 @@
+// for Node.js interpret
+
+const { default: Post } = require('../../../built/api/models/post');
+const { default: zip } = require('@prezzemolo/zip')
+
+const migrate = async (post) => {
+	const result = await Post.update(post._id, {
+		$set: {
+			'geo.type': 'Point',
+			'geo.coordinates': [post.geo.longitude, post.geo.latitude]
+		},
+		$unset: {
+			'geo.longitude': '',
+			'geo.latitude': '',
+		}
+	});
+	return result.ok === 1;
+}
+
+async function main() {
+	const count = await Post.count({
+		'geo': { $ne: null }
+	});
+
+	const dop = Number.parseInt(process.argv[2]) || 5
+	const idop = ((count - (count % dop)) / dop) + 1
+
+	return zip(
+		1,
+		async (time) => {
+			console.log(`${time} / ${idop}`)
+			const doc = await Post.find({
+				'geo': { $ne: null }
+			}, {
+				limit: dop, skip: time * dop
+			})
+			return Promise.all(doc.map(migrate))
+		},
+		idop
+	).then(a => {
+		const rv = []
+		a.forEach(e => rv.push(...e))
+		return rv
+	})
+}
+
+main().then(console.dir).catch(console.error)