From 77528f022d2e9f76298331b55303cfc42359c7af Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 30 Oct 2017 17:30:32 +0900 Subject: wip --- src/api/endpoints/bbs/threads/create.ts | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/api/endpoints/bbs/threads/create.ts (limited to 'src/api/endpoints') 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} + */ +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)); +}); -- cgit v1.2.3-freya From dc9fddf839df7959a83819eb7064f402db05f200 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 31 Oct 2017 21:42:11 +0900 Subject: RENAME: bbs -> channel --- locales/en.yml | 7 ++--- locales/ja.yml | 7 ++--- src/api/endpoints/bbs/threads/create.ts | 12 ++++---- src/api/models/bbs-thread.ts | 13 --------- src/api/models/channel.ts | 13 +++++++++ src/api/serializers/bbs-thread.ts | 44 ----------------------------- src/api/serializers/channel.ts | 44 +++++++++++++++++++++++++++++ src/web/app/desktop/tags/index.js | 2 +- src/web/app/desktop/tags/pages/bbs.tag | 30 -------------------- src/web/app/desktop/tags/pages/channels.tag | 30 ++++++++++++++++++++ 10 files changed, 100 insertions(+), 102 deletions(-) delete mode 100644 src/api/models/bbs-thread.ts create mode 100644 src/api/models/channel.ts delete mode 100644 src/api/serializers/bbs-thread.ts create mode 100644 src/api/serializers/channel.ts delete mode 100644 src/web/app/desktop/tags/pages/bbs.tag create mode 100644 src/web/app/desktop/tags/pages/channels.tag (limited to 'src/api/endpoints') diff --git a/locales/en.yml b/locales/en.yml index f0204b52cb..da532fc78a 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -352,10 +352,9 @@ 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" + mk-channels-page: + new: "Create new channel" + channel-title: "Channel title" mobile: tags: diff --git a/locales/ja.yml b/locales/ja.yml index 65d92782f2..1ae94652b5 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -352,10 +352,9 @@ desktop: mk-repost-form-window: title: "この投稿をRepostしますか?" - mk-bbs-page: - title: "Misskey掲示板" - new: "スレッドを作成" - thread-title: "スレッドのタイトル" + mk-channels-page: + new: "チャンネルを作成" + channel-title: "チャンネルのタイトル" mobile: tags: diff --git a/src/api/endpoints/bbs/threads/create.ts b/src/api/endpoints/bbs/threads/create.ts index 71d61d8711..d9b4d34a0c 100644 --- a/src/api/endpoints/bbs/threads/create.ts +++ b/src/api/endpoints/bbs/threads/create.ts @@ -2,11 +2,11 @@ * Module dependencies */ import $ from 'cafy'; -import Thread from '../../../models/bbs-thread'; -import serialize from '../../../serializers/bbs-thread'; +import Channel from '../../../models/channel'; +import serialize from '../../../serializers/channel'; /** - * Create a thread + * Create a channel * * @param {any} params * @param {any} user @@ -17,13 +17,13 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { const [title, titleErr] = $(params.title).string().range(1, 100).$; if (titleErr) return rej('invalid title param'); - // Create a thread - const thread = await Thread.insert({ + // Create a channel + const channel = await Channel.insert({ created_at: new Date(), user_id: user._id, title: title }); // Response - res(await serialize(thread)); + res(await serialize(channel)); }); diff --git a/src/api/models/bbs-thread.ts b/src/api/models/bbs-thread.ts deleted file mode 100644 index a92157c6f4..0000000000 --- a/src/api/models/bbs-thread.ts +++ /dev/null @@ -1,13 +0,0 @@ -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/models/channel.ts b/src/api/models/channel.ts new file mode 100644 index 0000000000..79edb71367 --- /dev/null +++ b/src/api/models/channel.ts @@ -0,0 +1,13 @@ +import * as mongo from 'mongodb'; +import db from '../../db/mongodb'; + +const collection = db.get('channels'); + +export default collection as any; // fuck type definition + +export type IChannel = { + _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 deleted file mode 100644 index d9e41a8468..0000000000 --- a/src/api/serializers/bbs-thread.ts +++ /dev/null @@ -1,44 +0,0 @@ -/** - * 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(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/api/serializers/channel.ts b/src/api/serializers/channel.ts new file mode 100644 index 0000000000..d4e16d6be3 --- /dev/null +++ b/src/api/serializers/channel.ts @@ -0,0 +1,44 @@ +/** + * Module dependencies + */ +import * as mongo from 'mongodb'; +import deepcopy = require('deepcopy'); +import { IUser } from '../models/user'; +import { default as Channel, IChannel } from '../models/channel'; + +/** + * Serialize a channel + * + * @param channel target + * @param me? serializee + * @return response + */ +export default ( + channel: string | mongo.ObjectID | IChannel, + me?: string | mongo.ObjectID | IUser +) => new Promise(async (resolve, reject) => { + + let _channel: any; + + // Populate the channel if 'channel' is ID + if (mongo.ObjectID.prototype.isPrototypeOf(channel)) { + _channel = await Channel.findOne({ + _id: channel + }); + } else if (typeof channel === 'string') { + _channel = await Channel.findOne({ + _id: new mongo.ObjectID(channel) + }); + } else { + _channel = deepcopy(channel); + } + + // Rename _id to id + _channel.id = _channel._id; + delete _channel._id; + + // Remove needless properties + delete _channel.user_id; + + resolve(_channel); +}); diff --git a/src/web/app/desktop/tags/index.js b/src/web/app/desktop/tags/index.js index fa7161ddfa..6d49006526 100644 --- a/src/web/app/desktop/tags/index.js +++ b/src/web/app/desktop/tags/index.js @@ -61,7 +61,7 @@ require('./pages/user.tag'); require('./pages/post.tag'); require('./pages/search.tag'); require('./pages/not-found.tag'); -require('./pages/bbs.tag'); +require('./pages/channels.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 deleted file mode 100644 index cb58af1934..0000000000 --- a/src/web/app/desktop/tags/pages/bbs.tag +++ /dev/null @@ -1,30 +0,0 @@ - - -
-

%i18n:desktop.tags.mk-bbs-page.title%

- -
-
- - -
diff --git a/src/web/app/desktop/tags/pages/channels.tag b/src/web/app/desktop/tags/pages/channels.tag new file mode 100644 index 0000000000..9e47e52d25 --- /dev/null +++ b/src/web/app/desktop/tags/pages/channels.tag @@ -0,0 +1,30 @@ + + +
+

%i18n:desktop.tags.mk-bbs-page.title%

+ +
+
+ + +
-- cgit v1.2.3-freya From b4340b1d91a6fc1679c3cb891ea800e1b491109c Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 31 Oct 2017 22:09:09 +0900 Subject: wip --- src/api/endpoints/posts/create.ts | 47 ++++++++++++++++++++++++++++++++++----- src/api/models/post.ts | 1 + 2 files changed, 42 insertions(+), 6 deletions(-) (limited to 'src/api/endpoints') diff --git a/src/api/endpoints/posts/create.ts b/src/api/endpoints/posts/create.ts index 805dba7f83..42a55f850e 100644 --- a/src/api/endpoints/posts/create.ts +++ b/src/api/endpoints/posts/create.ts @@ -4,9 +4,9 @@ import $ from 'cafy'; import deepEqual = require('deep-equal'); import parse from '../../common/text'; -import Post from '../../models/post'; -import { isValidText } from '../../models/post'; +import { default as Post, IPost, isValidText } from '../../models/post'; import { default as User, IUser } from '../../models/user'; +import { default as Channel, IChannel } from '../../models/channel'; import Following from '../../models/following'; import DriveFile from '../../models/drive-file'; import Watching from '../../models/post-watching'; @@ -62,7 +62,8 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => { const [repostId, repostIdErr] = $(params.repost_id).optional.id().$; if (repostIdErr) return rej('invalid repost_id'); - let repost = null; + let repost: IPost = null; + let isQuote = false; if (repostId !== undefined) { // Fetch repost to post repost = await Post.findOne({ @@ -84,18 +85,20 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => { } }); + isQuote = text != null || files != null; + // 直近と同じRepost対象かつ引用じゃなかったらエラー if (latestPost && latestPost.repost_id && latestPost.repost_id.equals(repost._id) && - text === undefined && files === null) { + !isQuote) { return rej('cannot repost same post that already reposted in your latest post'); } // 直近がRepost対象かつ引用じゃなかったらエラー if (latestPost && latestPost._id.equals(repost._id) && - text === undefined && files === null) { + !isQuote) { return rej('cannot repost your latest post'); } } @@ -104,7 +107,7 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => { const [inReplyToPostId, inReplyToPostIdErr] = $(params.reply_to_id).optional.id().$; if (inReplyToPostIdErr) return rej('invalid in_reply_to_post_id'); - let inReplyToPost = null; + let inReplyToPost: IPost = null; if (inReplyToPostId !== undefined) { // Fetch reply inReplyToPost = await Post.findOne({ @@ -121,6 +124,37 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => { } } + // Get 'channel_id' parameter + const [channelId, channelIdErr] = $(params.channel_id).optional.id().$; + if (channelIdErr) return rej('invalid channel_id'); + + let channel: IChannel = null; + if (channelId !== undefined) { + // Fetch channel + channel = await Channel.findOne({ + _id: channelId + }); + + if (channel === null) { + return rej('channel not found'); + } + + // 返信対象の投稿がこのチャンネルじゃなかったらダメ + if (inReplyToPost && !channelId.equals(inReplyToPost.channel_id)) { + return rej('チャンネル内部からチャンネル外部の投稿に返信することはできません'); + } + + // Repost対象の投稿がこのチャンネルじゃなかったらダメ + if (repost && !channelId.equals(repost.channel_id)) { + return rej('チャンネル内部からチャンネル外部の投稿をRepostすることはできません'); + } + + // 引用ではないRepostはダメ + if (repost && !isQuote) { + return rej('チャンネル内部では引用ではないRepostをすることはできません'); + } + } + // Get 'poll' parameter const [poll, pollErr] = $(params.poll).optional.strict.object() .have('choices', $().array('string') @@ -164,6 +198,7 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => { // 投稿を作成 const post = await Post.insert({ created_at: new Date(), + channel_id: channel ? channel._id : undefined, media_ids: files ? files.map(file => file._id) : undefined, reply_to_id: inReplyToPost ? inReplyToPost._id : undefined, repost_id: repost ? repost._id : undefined, diff --git a/src/api/models/post.ts b/src/api/models/post.ts index 8b9f7f5ef6..fe07dcb0b1 100644 --- a/src/api/models/post.ts +++ b/src/api/models/post.ts @@ -10,6 +10,7 @@ export function isValidText(text: string): boolean { export type IPost = { _id: mongo.ObjectID; + channel_id: mongo.ObjectID; created_at: Date; media_ids: mongo.ObjectID[]; reply_to_id: mongo.ObjectID; -- cgit v1.2.3-freya From 30a4e839a687bed7ed839e3c17f6781bb4b76499 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 31 Oct 2017 22:14:12 +0900 Subject: Fix indent --- src/api/endpoints/posts/create.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/api/endpoints') diff --git a/src/api/endpoints/posts/create.ts b/src/api/endpoints/posts/create.ts index 42a55f850e..e0a02fa4a0 100644 --- a/src/api/endpoints/posts/create.ts +++ b/src/api/endpoints/posts/create.ts @@ -186,11 +186,11 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => { repost: user.latest_post.repost_id ? user.latest_post.repost_id.toString() : null, media_ids: (user.latest_post.media_ids || []).map(id => id.toString()) }, { - text: text, - reply: inReplyToPost ? inReplyToPost._id.toString() : null, - repost: repost ? repost._id.toString() : null, - media_ids: (files || []).map(file => file._id.toString()) - })) { + text: text, + reply: inReplyToPost ? inReplyToPost._id.toString() : null, + repost: repost ? repost._id.toString() : null, + media_ids: (files || []).map(file => file._id.toString()) + })) { return rej('duplicate'); } } -- cgit v1.2.3-freya From 5efb52b9f563ae7d6b5383d054a6c21fee676b68 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 31 Oct 2017 22:35:31 +0900 Subject: wip --- locales/en.yml | 2 +- locales/ja.yml | 2 +- src/api/endpoints.ts | 12 ++++++++++-- src/api/endpoints/bbs/threads/create.ts | 29 ----------------------------- src/api/endpoints/channels/create.ts | 29 +++++++++++++++++++++++++++++ src/web/app/desktop/router.js | 5 +++++ src/web/app/desktop/tags/pages/channels.tag | 8 +++----- src/web/app/desktop/tags/ui.tag | 8 ++++---- 8 files changed, 53 insertions(+), 42 deletions(-) delete mode 100644 src/api/endpoints/bbs/threads/create.ts create mode 100644 src/api/endpoints/channels/create.ts (limited to 'src/api/endpoints') diff --git a/locales/en.yml b/locales/en.yml index da532fc78a..5c7a1165ba 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -241,7 +241,7 @@ desktop: mk-ui-header-nav: home: "Home" messaging: "Messages" - bbs: "BBS" + channels: "Channels" info: "News" mk-ui-header-search: diff --git a/locales/ja.yml b/locales/ja.yml index 1ae94652b5..dd76a2b900 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -241,7 +241,7 @@ desktop: mk-ui-header-nav: home: "ホーム" messaging: "メッセージ" - bbs: "掲示板" + channels: "チャンネル" info: "お知らせ" mk-ui-header-search: diff --git a/src/api/endpoints.ts b/src/api/endpoints.ts index 29a97bcb8a..26177b8775 100644 --- a/src/api/endpoints.ts +++ b/src/api/endpoints.ts @@ -474,8 +474,16 @@ const endpoints: Endpoint[] = [ name: 'messaging/messages/create', withCredential: true, kind: 'messaging-write' - } - + }, + { + name: 'channels/create', + withCredential: true, + limit: { + duration: ms('1hour'), + max: 3, + minInterval: ms('10seconds') + } + }, ]; export default endpoints; diff --git a/src/api/endpoints/bbs/threads/create.ts b/src/api/endpoints/bbs/threads/create.ts deleted file mode 100644 index d9b4d34a0c..0000000000 --- a/src/api/endpoints/bbs/threads/create.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Module dependencies - */ -import $ from 'cafy'; -import Channel from '../../../models/channel'; -import serialize from '../../../serializers/channel'; - -/** - * Create a channel - * - * @param {any} params - * @param {any} user - * @return {Promise} - */ -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 channel - const channel = await Channel.insert({ - created_at: new Date(), - user_id: user._id, - title: title - }); - - // Response - res(await serialize(channel)); -}); diff --git a/src/api/endpoints/channels/create.ts b/src/api/endpoints/channels/create.ts new file mode 100644 index 0000000000..74b089dfc3 --- /dev/null +++ b/src/api/endpoints/channels/create.ts @@ -0,0 +1,29 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; +import Channel from '../../models/channel'; +import serialize from '../../serializers/channel'; + +/** + * Create a channel + * + * @param {any} params + * @param {any} user + * @return {Promise} + */ +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 channel + const channel = await Channel.insert({ + created_at: new Date(), + user_id: user._id, + title: title + }); + + // Response + res(await serialize(channel)); +}); diff --git a/src/web/app/desktop/router.js b/src/web/app/desktop/router.js index afa8a2dce3..51738f3afa 100644 --- a/src/web/app/desktop/router.js +++ b/src/web/app/desktop/router.js @@ -9,6 +9,7 @@ let page = null; export default me => { route('/', index); route('/i>mentions', mentions); + route('/channel', channels); route('/post::post', post); route('/search::query', search); route('/:user', user.bind(null, 'home')); @@ -54,6 +55,10 @@ export default me => { mount(el); } + function channels() { + mount(document.createElement('mk-channels-page')); + } + function notFound() { mount(document.createElement('mk-not-found')); } diff --git a/src/web/app/desktop/tags/pages/channels.tag b/src/web/app/desktop/tags/pages/channels.tag index 9e47e52d25..03fae3c8d1 100644 --- a/src/web/app/desktop/tags/pages/channels.tag +++ b/src/web/app/desktop/tags/pages/channels.tag @@ -1,8 +1,7 @@
-

%i18n:desktop.tags.mk-bbs-page.title%

- +
+ + diff --git a/src/web/app/desktop/tags/pages/channels.tag b/src/web/app/desktop/tags/pages/channels.tag index 03fae3c8d1..220f1ca50e 100644 --- a/src/web/app/desktop/tags/pages/channels.tag +++ b/src/web/app/desktop/tags/pages/channels.tag @@ -18,7 +18,7 @@ this.new = () => { const title = window.prompt('%i18n:desktop.tags.mk-channels-page.channel-title%'); - this.api('bbs/channels/create', { + this.api('channels/create', { title: title }).then(channel => { location.href = '/channel/' + channel.id; diff --git a/src/web/app/desktop/tags/pages/user.tag b/src/web/app/desktop/tags/pages/user.tag index 864fe22735..811ca5c0fd 100644 --- a/src/web/app/desktop/tags/pages/user.tag +++ b/src/web/app/desktop/tags/pages/user.tag @@ -16,7 +16,7 @@ this.refs.ui.refs.user.on('user-fetched', user => { Progress.set(0.5); - document.title = user.name + ' | Misskey' + document.title = user.name + ' | Misskey'; }); this.refs.ui.refs.user.on('loaded', () => { -- cgit v1.2.3-freya From 346c2959e058fa445ebb82e71eb37ef023ba6bd4 Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 1 Nov 2017 00:10:30 +0900 Subject: wip --- src/api/endpoints.ts | 3 + src/api/endpoints/channels/posts.ts | 79 +++++++++++++++++++++ src/web/app/common/scripts/channel-stream.js | 14 ++++ src/web/app/desktop/tags/pages/channel.tag | 87 ++++++++++++++++++++++++ src/web/app/desktop/tags/pages/drive-chooser.tag | 44 ++++++++++++ 5 files changed, 227 insertions(+) create mode 100644 src/api/endpoints/channels/posts.ts create mode 100644 src/web/app/common/scripts/channel-stream.js create mode 100644 src/web/app/desktop/tags/pages/drive-chooser.tag (limited to 'src/api/endpoints') diff --git a/src/api/endpoints.ts b/src/api/endpoints.ts index 45b83fc9e5..88c01d4e7f 100644 --- a/src/api/endpoints.ts +++ b/src/api/endpoints.ts @@ -487,6 +487,9 @@ const endpoints: Endpoint[] = [ { name: 'channels/show' }, + { + name: 'channels/posts' + }, ]; export default endpoints; diff --git a/src/api/endpoints/channels/posts.ts b/src/api/endpoints/channels/posts.ts new file mode 100644 index 0000000000..fa91fb93ee --- /dev/null +++ b/src/api/endpoints/channels/posts.ts @@ -0,0 +1,79 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; +import { default as Channel, IChannel } from '../../models/channel'; +import { default as Post, IPost } from '../../models/post'; +import serialize from '../../serializers/post'; + +/** + * Show a posts of a channel + * + * @param {any} params + * @param {any} user + * @return {Promise} + */ +module.exports = (params, user) => new Promise(async (res, rej) => { + // Get 'limit' parameter + const [limit = 1000, limitErr] = $(params.limit).optional.number().range(1, 1000).$; + if (limitErr) return rej('invalid limit param'); + + // Get 'since_id' parameter + const [sinceId, sinceIdErr] = $(params.since_id).optional.id().$; + if (sinceIdErr) return rej('invalid since_id param'); + + // Get 'max_id' parameter + const [maxId, maxIdErr] = $(params.max_id).optional.id().$; + if (maxIdErr) return rej('invalid max_id param'); + + // Check if both of since_id and max_id is specified + if (sinceId && maxId) { + return rej('cannot set since_id and max_id'); + } + + // Get 'channel_id' parameter + const [channelId, channelIdErr] = $(params.channel_id).id().$; + if (channelIdErr) return rej('invalid channel_id param'); + + // Fetch channel + const channel: IChannel = await Channel.findOne({ + _id: channelId + }); + + if (channel === null) { + return rej('channel not found'); + } + + //#region Construct query + const sort = { + _id: -1 + }; + + const query = { + channel_id: channel._id + } as any; + + if (sinceId) { + sort._id = 1; + query._id = { + $gt: sinceId + }; + } else if (maxId) { + query._id = { + $lt: maxId + }; + } + //#endregion Construct query + + // Issue query + const posts = await Post + .find(query, { + limit: limit, + sort: sort + }); + + // Serialize + res(await Promise.all(posts.map(async (post) => + await serialize(post, user) + ))); +}); diff --git a/src/web/app/common/scripts/channel-stream.js b/src/web/app/common/scripts/channel-stream.js new file mode 100644 index 0000000000..38e7d91132 --- /dev/null +++ b/src/web/app/common/scripts/channel-stream.js @@ -0,0 +1,14 @@ +'use strict'; + +import Stream from './stream'; + +/** + * Channel stream connection + */ +class Connection extends Stream { + constructor() { + super('channel'); + } +} + +export default Connection; diff --git a/src/web/app/desktop/tags/pages/channel.tag b/src/web/app/desktop/tags/pages/channel.tag index 4fa172f99d..8a3034f40c 100644 --- a/src/web/app/desktop/tags/pages/channel.tag +++ b/src/web/app/desktop/tags/pages/channel.tag @@ -2,6 +2,8 @@

{ parent.channel.title }

+ +
+ + +
+ { post.user.name } +
+
+ { post.text } +
+ + +
+ + +

{ reply.user.name }への返信: (or キャンセル)

+ + + + + +
diff --git a/src/web/app/desktop/tags/pages/drive-chooser.tag b/src/web/app/desktop/tags/pages/drive-chooser.tag new file mode 100644 index 0000000000..49741ad40c --- /dev/null +++ b/src/web/app/desktop/tags/pages/drive-chooser.tag @@ -0,0 +1,44 @@ + + +
+ + + +
+ + + +
-- cgit v1.2.3-freya From 71c3e11708dad327924bdcb95193d44c2b11a907 Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 1 Nov 2017 01:38:19 +0900 Subject: wip --- src/api/endpoints/channels/create.ts | 3 ++- src/api/endpoints/posts/create.ts | 17 +++++++++++++++ src/api/models/channel.ts | 1 + src/api/serializers/post.ts | 8 ++++++- src/web/app/desktop/tags/pages/channel.tag | 35 +++++++++++++++++++++++++----- src/web/app/desktop/tags/timeline.tag | 4 ++++ src/web/app/mobile/tags/timeline.tag | 4 ++++ 7 files changed, 65 insertions(+), 7 deletions(-) (limited to 'src/api/endpoints') diff --git a/src/api/endpoints/channels/create.ts b/src/api/endpoints/channels/create.ts index 74b089dfc3..e0c0e0192a 100644 --- a/src/api/endpoints/channels/create.ts +++ b/src/api/endpoints/channels/create.ts @@ -21,7 +21,8 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { const channel = await Channel.insert({ created_at: new Date(), user_id: user._id, - title: title + title: title, + index: 0 }); // Response diff --git a/src/api/endpoints/posts/create.ts b/src/api/endpoints/posts/create.ts index e0a02fa4a0..183cabf135 100644 --- a/src/api/endpoints/posts/create.ts +++ b/src/api/endpoints/posts/create.ts @@ -153,6 +153,16 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => { if (repost && !isQuote) { return rej('チャンネル内部では引用ではないRepostをすることはできません'); } + } else { + // 返信対象の投稿がチャンネルへの投稿だったらダメ + if (inReplyToPost && inReplyToPost.channel_id != null) { + return rej('チャンネル外部からチャンネル内部の投稿に返信することはできません'); + } + + // Repost対象の投稿がチャンネルへの投稿だったらダメ + if (repost && repost.channel_id != null) { + return rej('チャンネル外部からチャンネル内部の投稿をRepostすることはできません'); + } } // Get 'poll' parameter @@ -199,6 +209,7 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => { const post = await Post.insert({ created_at: new Date(), channel_id: channel ? channel._id : undefined, + index: channel ? channel.index + 1 : undefined, media_ids: files ? files.map(file => file._id) : undefined, reply_to_id: inReplyToPost ? inReplyToPost._id : undefined, repost_id: repost ? repost._id : undefined, @@ -217,6 +228,12 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => { // ----------------------------------------------------------- // Post processes + Channel.update({ _id: channel._id }, { + $inc: { + index: 1 + } + }); + User.update({ _id: user._id }, { $set: { latest_post: post diff --git a/src/api/models/channel.ts b/src/api/models/channel.ts index 79edb71367..c80e84dbc8 100644 --- a/src/api/models/channel.ts +++ b/src/api/models/channel.ts @@ -10,4 +10,5 @@ export type IChannel = { created_at: Date; title: string; user_id: mongo.ObjectID; + index: number; }; diff --git a/src/api/serializers/post.ts b/src/api/serializers/post.ts index df917a8595..7d40df2d6a 100644 --- a/src/api/serializers/post.ts +++ b/src/api/serializers/post.ts @@ -8,6 +8,7 @@ import Reaction from '../models/post-reaction'; import { IUser } from '../models/user'; import Vote from '../models/poll-vote'; import serializeApp from './app'; +import serializeChannel from './channel'; import serializeUser from './user'; import serializeDriveFile from './drive-file'; import parse from '../common/text'; @@ -76,8 +77,13 @@ const self = ( _post.app = await serializeApp(_post.app_id); } + // Populate channel + if (_post.channel_id) { + _post.channel = await serializeChannel(_post.channel_id); + } + + // Populate media if (_post.media_ids) { - // Populate media _post.media = await Promise.all(_post.media_ids.map(async fileId => await serializeDriveFile(fileId) )); diff --git a/src/web/app/desktop/tags/pages/channel.tag b/src/web/app/desktop/tags/pages/channel.tag index 8a3034f40c..ebd26f07b8 100644 --- a/src/web/app/desktop/tags/pages/channel.tag +++ b/src/web/app/desktop/tags/pages/channel.tag @@ -2,8 +2,9 @@

{ parent.channel.title }

- - + +
+
@@ -57,9 +60,13 @@
- { post.user.name } + { post.index }: + { post.user.name } + + ID:{ post.user.username }
+ >>{ post.reply_to.index } { post.text }
-

{ reply.user.name }への返信: (or キャンセル)

+

>>{ reply.index } ({ reply.user.name }): [x]

+
+ +
    +
  1. { name }
  2. +
+ + +
diff --git a/src/web/app/ch/tags/index.js b/src/web/app/ch/tags/index.js new file mode 100644 index 0000000000..1e99ccd43e --- /dev/null +++ b/src/web/app/ch/tags/index.js @@ -0,0 +1,2 @@ +require('./index.tag'); +require('./channel.tag'); diff --git a/src/web/app/ch/tags/index.tag b/src/web/app/ch/tags/index.tag new file mode 100644 index 0000000000..1c0a037c2d --- /dev/null +++ b/src/web/app/ch/tags/index.tag @@ -0,0 +1,24 @@ + + + + + diff --git a/src/web/app/common/scripts/channel-stream.js b/src/web/app/common/scripts/channel-stream.js index 38e7d91132..17944dbe45 100644 --- a/src/web/app/common/scripts/channel-stream.js +++ b/src/web/app/common/scripts/channel-stream.js @@ -6,8 +6,10 @@ import Stream from './stream'; * Channel stream connection */ class Connection extends Stream { - constructor() { - super('channel'); + constructor(channelId) { + super('channel', { + channel: channelId + }); } } diff --git a/src/web/app/common/scripts/config.js b/src/web/app/common/scripts/config.js index 75a7abba29..c5015622f0 100644 --- a/src/web/app/common/scripts/config.js +++ b/src/web/app/common/scripts/config.js @@ -6,6 +6,7 @@ const host = isRoot ? Url.host : Url.host.substring(Url.host.indexOf('.') + 1, U const scheme = Url.protocol; const url = `${scheme}//${host}`; const apiUrl = `${scheme}//api.${host}`; +const chUrl = `${scheme}//ch.${host}`; const devUrl = `${scheme}//dev.${host}`; const aboutUrl = `${scheme}//about.${host}`; const statsUrl = `${scheme}//stats.${host}`; @@ -16,6 +17,7 @@ export default { scheme, url, apiUrl, + chUrl, devUrl, aboutUrl, statsUrl, diff --git a/src/web/app/desktop/router.js b/src/web/app/desktop/router.js index df67bb7b7c..977e3fa9a6 100644 --- a/src/web/app/desktop/router.js +++ b/src/web/app/desktop/router.js @@ -10,8 +10,6 @@ export default me => { route('/', index); route('/selectdrive', selectDrive); route('/i>mentions', mentions); - route('/channel', channels); - route('/channel/:channel', channel); route('/post::post', post); route('/search::query', search); route('/:user', user.bind(null, 'home')); @@ -57,16 +55,6 @@ export default me => { mount(el); } - function channel(ctx) { - const el = document.createElement('mk-channel-page'); - el.setAttribute('id', ctx.params.channel); - mount(el); - } - - function channels() { - mount(document.createElement('mk-channels-page')); - } - function selectDrive() { mount(document.createElement('mk-selectdrive-page')); } diff --git a/src/web/app/desktop/tags/index.js b/src/web/app/desktop/tags/index.js index 0b92d8c236..37fdfe37e4 100644 --- a/src/web/app/desktop/tags/index.js +++ b/src/web/app/desktop/tags/index.js @@ -61,8 +61,6 @@ require('./pages/user.tag'); require('./pages/post.tag'); require('./pages/search.tag'); require('./pages/not-found.tag'); -require('./pages/channel.tag'); -require('./pages/channels.tag'); require('./pages/selectdrive.tag'); require('./autocomplete-suggestion.tag'); require('./progress-dialog.tag'); diff --git a/src/web/app/desktop/tags/pages/channel.tag b/src/web/app/desktop/tags/pages/channel.tag deleted file mode 100644 index a14c0648c4..0000000000 --- a/src/web/app/desktop/tags/pages/channel.tag +++ /dev/null @@ -1,184 +0,0 @@ - - -
-

{ parent.channel.title }

- - - -
- -
-
- - -
- - -
- { post.index }: - { post.user.name } - - ID:{ post.user.username } -
-
- >>{ post.reply_to.index } - { post.text } -
- - { - -
-
- - -
- - -

>>{ reply.index } ({ reply.user.name }): [x]

- - -
- -
    -
  1. { name }
  2. -
- - -
diff --git a/src/web/app/desktop/tags/pages/channels.tag b/src/web/app/desktop/tags/pages/channels.tag deleted file mode 100644 index 220f1ca50e..0000000000 --- a/src/web/app/desktop/tags/pages/channels.tag +++ /dev/null @@ -1,28 +0,0 @@ - - -
- -
-
- - -
diff --git a/src/web/app/desktop/tags/timeline.tag b/src/web/app/desktop/tags/timeline.tag index 17b2c66dc8..64b64f902f 100644 --- a/src/web/app/desktop/tags/timeline.tag +++ b/src/web/app/desktop/tags/timeline.tag @@ -112,7 +112,7 @@
-

{ p.channel.title }:

+

{ p.channel.title }:

diff --git a/src/web/app/desktop/tags/ui.tag b/src/web/app/desktop/tags/ui.tag index 7527358dce..3123c34f4f 100644 --- a/src/web/app/desktop/tags/ui.tag +++ b/src/web/app/desktop/tags/ui.tag @@ -335,10 +335,10 @@ -
  • - +
  • + -

    %i18n:desktop.tags.mk-ui-header-nav.channels%

    +

    %i18n:desktop.tags.mk-ui-header-nav.ch%

  • diff --git a/src/web/app/mobile/tags/timeline.tag b/src/web/app/mobile/tags/timeline.tag index b26a5cb108..ad18521df6 100644 --- a/src/web/app/mobile/tags/timeline.tag +++ b/src/web/app/mobile/tags/timeline.tag @@ -164,7 +164,7 @@
    -

    { p.channel.title }:

    +

    { p.channel.title }:

    diff --git a/src/web/app/mobile/tags/ui.tag b/src/web/app/mobile/tags/ui.tag index fb8cbcdbd2..b2d96f6b8b 100644 --- a/src/web/app/mobile/tags/ui.tag +++ b/src/web/app/mobile/tags/ui.tag @@ -231,10 +231,11 @@
  • %i18n:mobile.tags.mk-ui-nav.messaging%
    • %i18n:mobile.tags.mk-ui-nav.settings%
    • diff --git a/webpack/webpack.config.ts b/webpack/webpack.config.ts index 5199285d55..066df18157 100644 --- a/webpack/webpack.config.ts +++ b/webpack/webpack.config.ts @@ -16,6 +16,7 @@ module.exports = langs.map(([lang, locale]) => { const entry = { desktop: './src/web/app/desktop/script.js', mobile: './src/web/app/mobile/script.js', + ch: './src/web/app/ch/script.js', stats: './src/web/app/stats/script.js', status: './src/web/app/status/script.js', dev: './src/web/app/dev/script.js', -- cgit v1.2.3-freya From 42be937fcb6f02037ff4024a2fb1cf463c50ce0c Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 1 Nov 2017 04:11:56 +0900 Subject: wip --- src/api/endpoints.ts | 3 +++ src/api/endpoints/channels.ts | 59 +++++++++++++++++++++++++++++++++++++++++ src/web/app/ch/tags/channel.tag | 7 ++--- src/web/app/ch/tags/index.tag | 13 +++++++-- 4 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 src/api/endpoints/channels.ts (limited to 'src/api/endpoints') diff --git a/src/api/endpoints.ts b/src/api/endpoints.ts index 88c01d4e7f..c4dacad857 100644 --- a/src/api/endpoints.ts +++ b/src/api/endpoints.ts @@ -490,6 +490,9 @@ const endpoints: Endpoint[] = [ { name: 'channels/posts' }, + { + name: 'channels' + }, ]; export default endpoints; diff --git a/src/api/endpoints/channels.ts b/src/api/endpoints/channels.ts new file mode 100644 index 0000000000..e10c943896 --- /dev/null +++ b/src/api/endpoints/channels.ts @@ -0,0 +1,59 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; +import Channel from '../models/channel'; +import serialize from '../serializers/channel'; + +/** + * Get all channels + * + * @param {any} params + * @param {any} me + * @return {Promise} + */ +module.exports = (params, me) => new Promise(async (res, rej) => { + // Get 'limit' parameter + const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$; + if (limitErr) return rej('invalid limit param'); + + // Get 'since_id' parameter + const [sinceId, sinceIdErr] = $(params.since_id).optional.id().$; + if (sinceIdErr) return rej('invalid since_id param'); + + // Get 'max_id' parameter + const [maxId, maxIdErr] = $(params.max_id).optional.id().$; + if (maxIdErr) return rej('invalid max_id param'); + + // Check if both of since_id and max_id is specified + if (sinceId && maxId) { + return rej('cannot set since_id and max_id'); + } + + // Construct query + const sort = { + _id: -1 + }; + const query = {} as any; + if (sinceId) { + sort._id = 1; + query._id = { + $gt: sinceId + }; + } else if (maxId) { + query._id = { + $lt: maxId + }; + } + + // Issue query + const channels = await Channel + .find(query, { + limit: limit, + sort: sort + }); + + // Serialize + res(await Promise.all(channels.map(async channel => + await serialize(channel, me)))); +}); diff --git a/src/web/app/ch/tags/channel.tag b/src/web/app/ch/tags/channel.tag index 43a1f851f8..12a6b5a3b9 100644 --- a/src/web/app/ch/tags/channel.tag +++ b/src/web/app/ch/tags/channel.tag @@ -1,4 +1,6 @@ +
      Misskey Channels
      +

      { channel.title }

      読み込み中

      @@ -21,10 +23,9 @@ diff --git a/src/web/app/ch/tags/index.tag b/src/web/app/ch/tags/index.tag index 1c0a037c2d..a64ddb6ccd 100644 --- a/src/web/app/ch/tags/index.tag +++ b/src/web/app/ch/tags/index.tag @@ -1,5 +1,9 @@ - + +
      +