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">