From 77528f022d2e9f76298331b55303cfc42359c7af Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Mon, 30 Oct 2017 17:30:32 +0900
Subject: [PATCH] wip

---
 locales/en.yml                          |  6 ++++
 locales/ja.yml                          |  6 ++++
 src/api/endpoints/bbs/threads/create.ts | 29 ++++++++++++++++
 src/api/models/bbs-thread.ts            | 13 ++++++++
 src/api/serializers/bbs-thread.ts       | 44 +++++++++++++++++++++++++
 src/web/app/desktop/tags/index.js       |  1 +
 src/web/app/desktop/tags/pages/bbs.tag  | 30 +++++++++++++++++
 src/web/app/desktop/tags/ui.tag         | 32 +++++++++++-------
 8 files changed, 149 insertions(+), 12 deletions(-)
 create mode 100644 src/api/endpoints/bbs/threads/create.ts
 create mode 100644 src/api/models/bbs-thread.ts
 create mode 100644 src/api/serializers/bbs-thread.ts
 create mode 100644 src/web/app/desktop/tags/pages/bbs.tag

diff --git a/locales/en.yml b/locales/en.yml
index 03d5306d3e..6c763886df 100644
--- a/locales/en.yml
+++ b/locales/en.yml
@@ -241,6 +241,7 @@ desktop:
     mk-ui-header-nav:
       home: "Home"
       messaging: "Messages"
+      bbs: "BBS"
       info: "News"
 
     mk-ui-header-search:
@@ -351,6 +352,11 @@ desktop:
     mk-repost-form-window:
       title: "Are you sure you want to repost this post?"
 
+    mk-bbs-page:
+      title: "Misskey BBS"
+      new: "Create new thread"
+      thread-title: "Thread title"
+
 mobile:
   tags:
     mk-drive-file-viewer:
diff --git a/locales/ja.yml b/locales/ja.yml
index b640f0f248..1e243fb8d6 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -241,6 +241,7 @@ desktop:
     mk-ui-header-nav:
       home: "ホーム"
       messaging: "メッセージ"
+      bbs: "掲示板"
       info: "お知らせ"
 
     mk-ui-header-search:
@@ -351,6 +352,11 @@ desktop:
     mk-repost-form-window:
       title: "この投稿をRepostしますか?"
 
+    mk-bbs-page:
+      title: "Misskey掲示板"
+      new: "スレッドを作成"
+      thread-title: "スレッドのタイトル"
+
 mobile:
   tags:
     mk-drive-file-viewer:
diff --git a/src/api/endpoints/bbs/threads/create.ts b/src/api/endpoints/bbs/threads/create.ts
new file mode 100644
index 0000000000..71d61d8711
--- /dev/null
+++ b/src/api/endpoints/bbs/threads/create.ts
@@ -0,0 +1,29 @@
+/**
+ * Module dependencies
+ */
+import $ from 'cafy';
+import Thread from '../../../models/bbs-thread';
+import serialize from '../../../serializers/bbs-thread';
+
+/**
+ * Create a thread
+ *
+ * @param {any} params
+ * @param {any} user
+ * @return {Promise<any>}
+ */
+module.exports = async (params, user) => new Promise(async (res, rej) => {
+	// Get 'title' parameter
+	const [title, titleErr] = $(params.title).string().range(1, 100).$;
+	if (titleErr) return rej('invalid title param');
+
+	// Create a thread
+	const thread = await Thread.insert({
+		created_at: new Date(),
+		user_id: user._id,
+		title: title
+	});
+
+	// Response
+	res(await serialize(thread));
+});
diff --git a/src/api/models/bbs-thread.ts b/src/api/models/bbs-thread.ts
new file mode 100644
index 0000000000..a92157c6f4
--- /dev/null
+++ b/src/api/models/bbs-thread.ts
@@ -0,0 +1,13 @@
+import * as mongo from 'mongodb';
+import db from '../../db/mongodb';
+
+const collection = db.get('bbs_threads');
+
+export default collection as any; // fuck type definition
+
+export type IBbsThread = {
+	_id: mongo.ObjectID;
+	created_at: Date;
+	title: string;
+	user_id: mongo.ObjectID;
+};
diff --git a/src/api/serializers/bbs-thread.ts b/src/api/serializers/bbs-thread.ts
new file mode 100644
index 0000000000..d9e41a8468
--- /dev/null
+++ b/src/api/serializers/bbs-thread.ts
@@ -0,0 +1,44 @@
+/**
+ * Module dependencies
+ */
+import * as mongo from 'mongodb';
+import deepcopy = require('deepcopy');
+import { IUser } from '../models/user';
+import { default as Thread, IBbsThread } from '../models/bbs-thread';
+
+/**
+ * Serialize a thread
+ *
+ * @param thread target
+ * @param me? serializee
+ * @return response
+ */
+export default (
+	thread: string | mongo.ObjectID | IBbsThread,
+	me?: string | mongo.ObjectID | IUser
+) => new Promise<any>(async (resolve, reject) => {
+
+	let _thread: any;
+
+	// Populate the thread if 'thread' is ID
+	if (mongo.ObjectID.prototype.isPrototypeOf(thread)) {
+		_thread = await Thread.findOne({
+			_id: thread
+		});
+	} else if (typeof thread === 'string') {
+		_thread = await Thread.findOne({
+			_id: new mongo.ObjectID(thread)
+		});
+	} else {
+		_thread = deepcopy(thread);
+	}
+
+	// Rename _id to id
+	_thread.id = _thread._id;
+	delete _thread._id;
+
+	// Remove needless properties
+	delete _thread.user_id;
+
+	resolve(_thread);
+});
diff --git a/src/web/app/desktop/tags/index.js b/src/web/app/desktop/tags/index.js
index 4e286013a1..fa7161ddfa 100644
--- a/src/web/app/desktop/tags/index.js
+++ b/src/web/app/desktop/tags/index.js
@@ -61,6 +61,7 @@ require('./pages/user.tag');
 require('./pages/post.tag');
 require('./pages/search.tag');
 require('./pages/not-found.tag');
+require('./pages/bbs.tag');
 require('./autocomplete-suggestion.tag');
 require('./progress-dialog.tag');
 require('./user-preview.tag');
diff --git a/src/web/app/desktop/tags/pages/bbs.tag b/src/web/app/desktop/tags/pages/bbs.tag
new file mode 100644
index 0000000000..cb58af1934
--- /dev/null
+++ b/src/web/app/desktop/tags/pages/bbs.tag
@@ -0,0 +1,30 @@
+<mk-bbs-page>
+	<mk-ui ref="ui">
+		<main>
+			<h1>%i18n:desktop.tags.mk-bbs-page.title%</h1>
+			<button onclick={ parent.new }>%i18n:desktop.tags.mk-bbs-page.new%</button>
+		</main>
+	</mk-ui>
+	<style>
+		:scope
+			display block
+
+	</style>
+	<script>
+		this.mixin('api');
+
+		this.on('mount', () => {
+			document.title = '%i18n:desktop.tags.mk-bbs-page.title%';
+		});
+
+		this.new = () => {
+			const title = window.prompt('%i18n:desktop.tags.mk-bbs-page.thread-title%');
+
+			this.api('bbs/threads/create', {
+				title: title
+			}).then(thread => {
+				location.href = '/bbs/' + thread.id;
+			});
+		};
+	</script>
+</mk-bbs-page>
diff --git a/src/web/app/desktop/tags/ui.tag b/src/web/app/desktop/tags/ui.tag
index e0d7393b08..452a72c00a 100644
--- a/src/web/app/desktop/tags/ui.tag
+++ b/src/web/app/desktop/tags/ui.tag
@@ -319,18 +319,26 @@
 </mk-ui-header-notifications>
 
 <mk-ui-header-nav>
-	<ul if={ SIGNIN }>
-		<li class="home { active: page == 'home' }">
-			<a href={ CONFIG.url }>
-				<i class="fa fa-home"></i>
-				<p>%i18n:desktop.tags.mk-ui-header-nav.home%</p>
-			</a>
-		</li>
-		<li class="messaging">
-			<a onclick={ messaging }>
-				<i class="fa fa-comments"></i>
-				<p>%i18n:desktop.tags.mk-ui-header-nav.messaging%</p>
-				<i class="fa fa-circle" if={ hasUnreadMessagingMessages }></i>
+	<ul>
+		<virtual if={ SIGNIN }>
+			<li class="home { active: page == 'home' }">
+				<a href={ CONFIG.url }>
+					<i class="fa fa-home"></i>
+					<p>%i18n:desktop.tags.mk-ui-header-nav.home%</p>
+				</a>
+			</li>
+			<li class="messaging">
+				<a onclick={ messaging }>
+					<i class="fa fa-comments"></i>
+					<p>%i18n:desktop.tags.mk-ui-header-nav.messaging%</p>
+					<i class="fa fa-circle" if={ hasUnreadMessagingMessages }></i>
+				</a>
+			</li>
+		</virtual>
+		<li class="bbs">
+			<a href={ CONFIG.url + '/bbs' }>
+				<i class="fa fa-coffee"></i>
+				<p>%i18n:desktop.tags.mk-ui-header-nav.bbs%</p>
 			</a>
 		</li>
 		<li class="info">