diff --git a/CHANGELOG.md b/CHANGELOG.md index b071274d3..cf3d82f70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ChangeLog (Release Notes) unreleased ---------- * New: ユーザーページによく使うドメインを表示 (#771) +* New: よくリプライするユーザーをユーザーページに表示 (#770) 2566 (2017/09/07) ----------------- diff --git a/locales/en.yml b/locales/en.yml index fd07be2ae..a7dd3aea2 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -499,6 +499,7 @@ mobile: activity: "Activity" keywords: "Keywords" domains: "Domains" + frequently-replied-users: "Frequently talking users" followers-you-know: "Followers you know" last-used-at: "Latest used at" @@ -516,6 +517,10 @@ mobile: mk-user-overview-domains: no-domains: "No domains" + mk-user-overview-frequently-replied-users: + loading: "Loading" + no-users: "No users" + mk-user-overview-followers-you-know: loading: "Loading" no-users: "No users" diff --git a/locales/ja.yml b/locales/ja.yml index 832390f5f..451650ef7 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -499,6 +499,7 @@ mobile: activity: "アクティビティ" keywords: "キーワード" domains: "頻出ドメイン" + frequently-replied-users: "よく会話するユーザー" followers-you-know: "知り合いのフォロワー" last-used-at: "最終ログイン" @@ -516,6 +517,10 @@ mobile: mk-user-overview-domains: no-domains: "よく表れるドメインは検出されませんでした" + mk-user-overview-frequently-replied-users: + loading: "読み込み中" + no-users: "よく会話するユーザーはいません" + mk-user-overview-followers-you-know: loading: "読み込み中" no-users: "知り合いのユーザーはいません" diff --git a/src/api/endpoints.ts b/src/api/endpoints.ts index 97b98895b..f05762340 100644 --- a/src/api/endpoints.ts +++ b/src/api/endpoints.ts @@ -326,6 +326,9 @@ const endpoints: Endpoint[] = [ withCredential: true, kind: 'account-read' }, + { + name: 'users/get_frequently_replied_users' + }, { name: 'following/create', diff --git a/src/api/endpoints/users/get_frequently_replied_users.ts b/src/api/endpoints/users/get_frequently_replied_users.ts new file mode 100644 index 000000000..2e0e2e40a --- /dev/null +++ b/src/api/endpoints/users/get_frequently_replied_users.ts @@ -0,0 +1,96 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; +import Post from '../../models/post'; +import User from '../../models/user'; +import serialize from '../../serializers/user'; + +module.exports = (params, me) => new Promise(async (res, rej) => { + // Get 'user_id' parameter + const [userId, userIdErr] = $(params.user_id).id().$; + if (userIdErr) return rej('invalid user_id param'); + + // Lookup user + const user = await User.findOne({ + _id: userId + }, { + fields: { + _id: true + } + }); + + if (user === null) { + return rej('user not found'); + } + + // Fetch recent posts + const recentPosts = await Post.find({ + user_id: user._id, + reply_to_id: { + $exists: true, + $ne: null + } + }, { + sort: { + _id: -1 + }, + limit: 1000, + fields: { + _id: false, + reply_to_id: true + } + }); + + // 投稿が少なかったら中断 + if (recentPosts.length === 0) { + return res([]); + } + + const replyTargetPosts = await Post.find({ + _id: { + $in: recentPosts.map(p => p.reply_to_id) + }, + user_id: { + $ne: user._id + } + }, { + fields: { + _id: false, + user_id: true + } + }); + + const repliedUsers = {}; + + // Extract replies from recent posts + replyTargetPosts.forEach(post => { + const userId = post.user_id.toString(); + if (repliedUsers[userId]) { + repliedUsers[userId]++; + } else { + repliedUsers[userId] = 1; + } + }); + + // Calc peak + let peak = 0; + Object.keys(repliedUsers).forEach(user => { + if (repliedUsers[user] > peak) peak = repliedUsers[user]; + }); + + // Sort replies by frequency + const repliedUsersSorted = Object.keys(repliedUsers).sort((a, b) => repliedUsers[b] - repliedUsers[a]); + + // Lookup top 10 replies + const topRepliedUsers = repliedUsersSorted.slice(0, 10); + + // Make replies object (includes weights) + const repliesObj = await Promise.all(topRepliedUsers.map(async (user) => ({ + user: await serialize(user, me, { detail: true }), + weight: repliedUsers[user] / peak + }))); + + // Response + res(repliesObj); +}); diff --git a/src/web/app/mobile/tags/index.js b/src/web/app/mobile/tags/index.js index 6f985a91f..c5aafd20b 100644 --- a/src/web/app/mobile/tags/index.js +++ b/src/web/app/mobile/tags/index.js @@ -49,3 +49,4 @@ require('./users-list.tag'); require('./user-following.tag'); require('./user-followers.tag'); require('./init-following.tag'); +require('./user-card.tag'); diff --git a/src/web/app/mobile/tags/init-following.tag b/src/web/app/mobile/tags/init-following.tag index d0b63ff5d..6357f86a2 100644 --- a/src/web/app/mobile/tags/init-following.tag +++ b/src/web/app/mobile/tags/init-following.tag @@ -1,16 +1,9 @@

気になるユーザーをフォロー:

0 }> -
-
- - avatar - -
- { name } -

@{ username }

- -
+ + +

おすすめのユーザーは見つかりませんでした。

読み込んでいます

@@ -37,49 +30,10 @@ padding 16px background #eee - > .user - display inline-block - width 200px - text-align center - border-radius 8px - background #fff - + > mk-user-card &:not(:last-child) margin-right 16px - > header - display block - height 80px - background-color #ddd - background-size cover - background-position center - border-radius 8px 8px 0 0 - - > a - > img - position absolute - top 20px - left calc(50% - 40px) - width 80px - height 80px - border solid 2px #fff - border-radius 8px - - > .name - display block - margin 24px 0 0 0 - font-size 16px - color #555 - - > .username - margin 0 - font-size 15px - color #ccc - - > mk-follow-button - display inline-block - margin 8px 0 16px 0 - > .empty margin 0 padding 16px diff --git a/src/web/app/mobile/tags/user-card.tag b/src/web/app/mobile/tags/user-card.tag new file mode 100644 index 000000000..d0c79698c --- /dev/null +++ b/src/web/app/mobile/tags/user-card.tag @@ -0,0 +1,55 @@ + +
+ + avatar + +
+ { user.name } +

@{ user.username }

+ + + +
diff --git a/src/web/app/mobile/tags/user.tag b/src/web/app/mobile/tags/user.tag index a32355921..f29f0a0c8 100644 --- a/src/web/app/mobile/tags/user.tag +++ b/src/web/app/mobile/tags/user.tag @@ -246,6 +246,12 @@ +
+

%i18n:mobile.tags.mk-user-overview.frequently-replied-users%

+
+ +
+

%i18n:mobile.tags.mk-user-overview.followers-you-know%

@@ -619,6 +625,58 @@ + +

%i18n:mobile.tags.mk-user-overview-frequently-replied-users.loading%

+
0 }> + + + +
+

%i18n:mobile.tags.mk-user-overview-frequently-replied-users.no-users%

+ + +
+

%i18n:mobile.tags.mk-user-overview-followers-you-know.loading%

0 }>