From 1ba5dfd79c66edd871f922d21861557e6152cc6c Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 25 Apr 2018 06:34:50 +0900 Subject: wip --- src/server/api/endpoints/users/lists/create.ts | 25 ++++++++++++++ src/server/api/endpoints/users/lists/list.ts | 13 +++++++ src/server/api/endpoints/users/lists/push.ts | 48 ++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 src/server/api/endpoints/users/lists/create.ts create mode 100644 src/server/api/endpoints/users/lists/list.ts create mode 100644 src/server/api/endpoints/users/lists/push.ts (limited to 'src/server/api/endpoints/users/lists') diff --git a/src/server/api/endpoints/users/lists/create.ts b/src/server/api/endpoints/users/lists/create.ts new file mode 100644 index 0000000000..6ae510f52b --- /dev/null +++ b/src/server/api/endpoints/users/lists/create.ts @@ -0,0 +1,25 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; +import UserList, { pack } from '../../../../../models/user-list'; + +/** + * Create a user list + */ +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'); + + // insert + const userList = await UserList.insert({ + createdAt: new Date(), + userId: user._id, + title: title, + userIds: [] + }); + + // Response + res(await pack(userList)); +}); diff --git a/src/server/api/endpoints/users/lists/list.ts b/src/server/api/endpoints/users/lists/list.ts new file mode 100644 index 0000000000..d19339a1f5 --- /dev/null +++ b/src/server/api/endpoints/users/lists/list.ts @@ -0,0 +1,13 @@ +import UserList, { pack } from '../../../../../models/user-list'; + +/** + * Add a user to a user list + */ +module.exports = async (params, me) => new Promise(async (res, rej) => { + // Fetch lists + const userLists = await UserList.find({ + userId: me._id, + }); + + res(await Promise.all(userLists.map(x => pack(x)))); +}); diff --git a/src/server/api/endpoints/users/lists/push.ts b/src/server/api/endpoints/users/lists/push.ts new file mode 100644 index 0000000000..f21234775d --- /dev/null +++ b/src/server/api/endpoints/users/lists/push.ts @@ -0,0 +1,48 @@ +import $ from 'cafy'; import ID from '../../../../../cafy-id'; +import UserList from '../../../../../models/user-list'; +import User from '../../../../../models/user'; + +/** + * Add a user to a user list + */ +module.exports = async (params, me) => new Promise(async (res, rej) => { + // Get 'listId' parameter + const [listId, listIdErr] = $(params.listId).type(ID).$; + if (listIdErr) return rej('invalid listId param'); + + // Fetch the list + const userList = await UserList.findOne({ + _id: listId, + userId: me._id, + }); + + if (userList == null) { + return rej('list not found'); + } + + // Get 'userId' parameter + const [userId, userIdErr] = $(params.userId).type(ID).$; + if (userIdErr) return rej('invalid userId param'); + + // Fetch the user + const user = await User.findOne({ + _id: userId + }); + + if (user == null) { + return rej('user not found'); + } + + if (userList.userIds.map(id => id.toHexString()).includes(user._id.toHexString())) { + return rej('the user already added'); + } + + // Push the user + await UserList.update({ _id: userList._id }, { + $push: { + userIds: user._id + } + }); + + res(); +}); -- cgit v1.2.3-freya From 3d9ac6387e4f698c15bdca0d8dbd1f0a2b02161f Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 25 Apr 2018 18:04:16 +0900 Subject: wip --- src/publishers/stream.ts | 5 ++ src/server/api/endpoints/users/lists/push.ts | 5 +- src/services/note/create.ts | 110 +++++++++++++++------------ 3 files changed, 71 insertions(+), 49 deletions(-) (limited to 'src/server/api/endpoints/users/lists') diff --git a/src/publishers/stream.ts b/src/publishers/stream.ts index 2ecbfa0dd8..dcc03e39f1 100644 --- a/src/publishers/stream.ts +++ b/src/publishers/stream.ts @@ -25,6 +25,10 @@ class MisskeyEvent { this.publish(`note-stream:${noteId}`, type, typeof value === 'undefined' ? null : value); } + public publishUserListStream(listId: ID, type: string, value?: any): void { + this.publish(`user-list-stream:${listId}`, type, typeof value === 'undefined' ? null : value); + } + public publishMessagingStream(userId: ID, otherpartyId: ID, type: string, value?: any): void { this.publish(`messaging-stream:${userId}-${otherpartyId}`, type, typeof value === 'undefined' ? null : value); } @@ -69,6 +73,7 @@ export default ev.publishUserStream.bind(ev); export const publishLocalTimelineStream = ev.publishLocalTimelineStream.bind(ev); export const publishGlobalTimelineStream = ev.publishGlobalTimelineStream.bind(ev); export const publishDriveStream = ev.publishDriveStream.bind(ev); +export const publishUserListStream = ev.publishUserListStream.bind(ev); export const publishNoteStream = ev.publishNoteStream.bind(ev); export const publishMessagingStream = ev.publishMessagingStream.bind(ev); export const publishMessagingIndexStream = ev.publishMessagingIndexStream.bind(ev); diff --git a/src/server/api/endpoints/users/lists/push.ts b/src/server/api/endpoints/users/lists/push.ts index f21234775d..467c08efd4 100644 --- a/src/server/api/endpoints/users/lists/push.ts +++ b/src/server/api/endpoints/users/lists/push.ts @@ -1,6 +1,7 @@ import $ from 'cafy'; import ID from '../../../../../cafy-id'; import UserList from '../../../../../models/user-list'; -import User from '../../../../../models/user'; +import User, { pack as packUser } from '../../../../../models/user'; +import { publishUserListStream } from '../../../../../publishers/stream'; /** * Add a user to a user list @@ -45,4 +46,6 @@ module.exports = async (params, me) => new Promise(async (res, rej) => { }); res(); + + publishUserListStream(userList._id, 'userAdded', await packUser(user)); }); diff --git a/src/services/note/create.ts b/src/services/note/create.ts index e5ad96898f..4808edfda4 100644 --- a/src/services/note/create.ts +++ b/src/services/note/create.ts @@ -1,6 +1,6 @@ import Note, { pack, INote } from '../../models/note'; import User, { isLocalUser, IUser, isRemoteUser } from '../../models/user'; -import stream, { publishLocalTimelineStream, publishGlobalTimelineStream } from '../../publishers/stream'; +import stream, { publishLocalTimelineStream, publishGlobalTimelineStream, publishUserListStream } from '../../publishers/stream'; import Following from '../../models/following'; import { deliver } from '../../queue'; import renderNote from '../../remote/activitypub/renderer/note'; @@ -16,6 +16,7 @@ import pushSw from '../../publishers/push-sw'; import event from '../../publishers/stream'; import parse from '../../text/parse'; import { IApp } from '../../models/app'; +import UserList from '../../models/user-list'; export default async (user: IUser, data: { createdAt?: Date; @@ -110,60 +111,73 @@ export default async (user: IUser, data: { // タイムラインへの投稿 if (note.channelId == null) { - if (isLocalUser(user)) { - // Publish event to myself's stream - stream(note.userId, 'note', noteObj); - - // Publish note to local timeline stream - publishLocalTimelineStream(noteObj); - } - - // Publish note to global timeline stream - publishGlobalTimelineStream(noteObj); - - // Fetch all followers - const followers = await Following.find({ - followeeId: note.userId - }); - if (!silent) { - const render = async () => { - const content = data.renote && data.text == null - ? renderAnnounce(data.renote.uri ? data.renote.uri : await renderNote(data.renote)) - : renderCreate(await renderNote(note)); - return packAp(content); - }; - - // 投稿がリプライかつ投稿者がローカルユーザーかつリプライ先の投稿の投稿者がリモートユーザーなら配送 - if (data.reply && isLocalUser(user) && isRemoteUser(data.reply._user)) { - deliver(user, await render(), data.reply._user.inbox); - } + if (isLocalUser(user)) { + // Publish event to myself's stream + stream(note.userId, 'note', noteObj); - // 投稿がRenoteかつ投稿者がローカルユーザーかつRenote元の投稿の投稿者がリモートユーザーなら配送 - if (data.renote && isLocalUser(user) && isRemoteUser(data.renote._user)) { - deliver(user, await render(), data.renote._user.inbox); + // Publish note to local timeline stream + publishLocalTimelineStream(noteObj); } - Promise.all(followers.map(async following => { - const follower = following._follower; - - if (isLocalUser(follower)) { - // ストーキングしていない場合 - if (!following.stalk) { - // この投稿が返信ならスキップ - if (note.replyId && !note._reply.userId.equals(following.followerId) && !note._reply.userId.equals(note.userId)) return; + // Publish note to global timeline stream + publishGlobalTimelineStream(noteObj); + + // フォロワーに配信 + Following.find({ + followeeId: note.userId + }).then(followers => { + followers.map(async following => { + const follower = following._follower; + + if (isLocalUser(follower)) { + // ストーキングしていない場合 + if (!following.stalk) { + // この投稿が返信ならスキップ + if (note.replyId && !note._reply.userId.equals(following.followerId) && !note._reply.userId.equals(note.userId)) return; + } + + // Publish event to followers stream + stream(following.followerId, 'note', noteObj); + } else { + //#region AP配送 + // フォロワーがリモートユーザーかつ投稿者がローカルユーザーなら投稿を配信 + if (isLocalUser(user)) { + deliver(user, await render(), follower.inbox); + } + //#endergion } + }); + }); - // Publish event to followers stream - stream(following.followerId, 'note', noteObj); - } else { - // フォロワーがリモートユーザーかつ投稿者がローカルユーザーなら投稿を配信 - if (isLocalUser(user)) { - deliver(user, await render(), follower.inbox); - } - } - })); + // リストに配信 + UserList.find({ + userIds: note.userId + }).then(lists => { + lists.forEach(list => { + publishUserListStream(list._id, 'note', noteObj); + }); + }); + } + + //#region AP配送 + const render = async () => { + const content = data.renote && data.text == null + ? renderAnnounce(data.renote.uri ? data.renote.uri : await renderNote(data.renote)) + : renderCreate(await renderNote(note)); + return packAp(content); + }; + + // 投稿がリプライかつ投稿者がローカルユーザーかつリプライ先の投稿の投稿者がリモートユーザーなら配送 + if (data.reply && isLocalUser(user) && isRemoteUser(data.reply._user)) { + deliver(user, await render(), data.reply._user.inbox); + } + + // 投稿がRenoteかつ投稿者がローカルユーザーかつRenote元の投稿の投稿者がリモートユーザーなら配送 + if (data.renote && isLocalUser(user) && isRemoteUser(data.renote._user)) { + deliver(user, await render(), data.renote._user.inbox); } + //#endergion } // チャンネルへの投稿 -- cgit v1.2.3-freya From c2e053a208609d59188dce9e328c1ab9706aa35c Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 25 Apr 2018 19:53:16 +0900 Subject: wip --- src/client/app/desktop/script.ts | 2 + src/client/app/desktop/views/components/index.ts | 2 + .../app/desktop/views/components/list-timeline.vue | 74 --------- .../app/desktop/views/components/lists-window.vue | 2 +- src/client/app/desktop/views/components/notes.vue | 53 +++++- .../app/desktop/views/components/timeline.core.vue | 81 +++++----- .../views/components/user-list-timeline.vue | 91 +++++++++++ src/client/app/desktop/views/pages/list.vue | 72 --------- src/client/app/desktop/views/pages/user-list.vue | 74 +++++++++ src/server/api/endpoints.ts | 29 ++++ .../api/endpoints/notes/user-list-timeline.ts | 179 +++++++++++++++++++++ src/server/api/endpoints/users/lists/show.ts | 23 +++ .../api/endpoints/users/search_by_username.ts | 6 +- 13 files changed, 486 insertions(+), 202 deletions(-) delete mode 100644 src/client/app/desktop/views/components/list-timeline.vue create mode 100644 src/client/app/desktop/views/components/user-list-timeline.vue delete mode 100644 src/client/app/desktop/views/pages/list.vue create mode 100644 src/client/app/desktop/views/pages/user-list.vue create mode 100644 src/server/api/endpoints/notes/user-list-timeline.ts create mode 100644 src/server/api/endpoints/users/lists/show.ts (limited to 'src/server/api/endpoints/users/lists') diff --git a/src/client/app/desktop/script.ts b/src/client/app/desktop/script.ts index 3b0ed48cd0..2658a86b95 100644 --- a/src/client/app/desktop/script.ts +++ b/src/client/app/desktop/script.ts @@ -28,6 +28,7 @@ import MkUser from './views/pages/user/user.vue'; import MkFavorites from './views/pages/favorites.vue'; import MkSelectDrive from './views/pages/selectdrive.vue'; import MkDrive from './views/pages/drive.vue'; +import MkUserList from './views/pages/user-list.vue'; import MkHomeCustomize from './views/pages/home-customize.vue'; import MkMessagingRoom from './views/pages/messaging-room.vue'; import MkNote from './views/pages/note.vue'; @@ -55,6 +56,7 @@ init(async (launch) => { { path: '/i/messaging/:user', component: MkMessagingRoom }, { path: '/i/drive', component: MkDrive }, { path: '/i/drive/folder/:folder', component: MkDrive }, + { path: '/i/lists/:list', component: MkUserList }, { path: '/selectdrive', component: MkSelectDrive }, { path: '/search', component: MkSearch }, { path: '/othello', component: MkOthello }, diff --git a/src/client/app/desktop/views/components/index.ts b/src/client/app/desktop/views/components/index.ts index 4f61f43692..f58d0706df 100644 --- a/src/client/app/desktop/views/components/index.ts +++ b/src/client/app/desktop/views/components/index.ts @@ -28,6 +28,7 @@ import friendsMaker from './friends-maker.vue'; import followers from './followers.vue'; import following from './following.vue'; import usersList from './users-list.vue'; +import userListTimeline from './user-list-timeline.vue'; import widgetContainer from './widget-container.vue'; Vue.component('mk-ui', ui); @@ -58,4 +59,5 @@ Vue.component('mk-friends-maker', friendsMaker); Vue.component('mk-followers', followers); Vue.component('mk-following', following); Vue.component('mk-users-list', usersList); +Vue.component('mk-user-list-timeline', userListTimeline); Vue.component('mk-widget-container', widgetContainer); diff --git a/src/client/app/desktop/views/components/list-timeline.vue b/src/client/app/desktop/views/components/list-timeline.vue deleted file mode 100644 index e946453f40..0000000000 --- a/src/client/app/desktop/views/components/list-timeline.vue +++ /dev/null @@ -1,74 +0,0 @@ - - - diff --git a/src/client/app/desktop/views/components/lists-window.vue b/src/client/app/desktop/views/components/lists-window.vue index 7097e5ed4b..30b1794a29 100644 --- a/src/client/app/desktop/views/components/lists-window.vue +++ b/src/client/app/desktop/views/components/lists-window.vue @@ -1,6 +1,6 @@