From ecaa6a1ae0446657ac473fde55cd2234d217c337 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 17 Oct 2021 01:33:15 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=E3=83=A6=E3=83=BC=E3=82=B6=E3=83=BC?= =?UTF-8?q?=E3=81=AE=E3=83=AA=E3=82=A2=E3=82=AF=E3=82=B7=E3=83=A7=E3=83=B3?= =?UTF-8?q?=E4=B8=80=E8=A6=A7=E3=82=92=E8=A6=8B=E3=82=8C=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 9 ++- src/client/pages/user/index.vue | 7 ++ src/client/pages/user/reactions.vue | 81 +++++++++++++++++++++ src/models/repositories/note-reaction.ts | 14 +++- src/server/api/endpoints/users/reactions.ts | 67 +++++++++++++++++ 5 files changed, 175 insertions(+), 3 deletions(-) create mode 100644 src/client/pages/user/reactions.vue create mode 100644 src/server/api/endpoints/users/reactions.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 873716a3d..1139707b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,19 @@ ## 12.x.x (unreleased) ### Improvements -- ページロードエラーページにリロードボタンを追加 ### Bugfixes --> +## 12.x.x (unreleased) + +### Improvements +- クライアント: ユーザーのリアクション一覧を見れるように +- API: ユーザーのリアクション一覧を取得する users/reactions を追加 + +### Bugfixes + ## 12.92.0 (2021/10/16) ### Improvements diff --git a/src/client/pages/user/index.vue b/src/client/pages/user/index.vue index 0ddf73d57..6811dff2d 100644 --- a/src/client/pages/user/index.vue +++ b/src/client/pages/user/index.vue @@ -181,6 +181,7 @@ + @@ -223,6 +224,7 @@ export default defineComponent({ MkTab, MkInfo, XFollowList: defineAsyncComponent(() => import('./follow-list.vue')), + XReactions: defineAsyncComponent(() => import('./reactions.vue')), XClips: defineAsyncComponent(() => import('./clips.vue')), XPages: defineAsyncComponent(() => import('./pages.vue')), XGallery: defineAsyncComponent(() => import('./gallery.vue')), @@ -268,6 +270,11 @@ export default defineComponent({ title: this.$ts.overview, icon: 'fas fa-home', onClick: () => { this.$router.push('/@' + getAcct(this.user)); }, + }, { + active: this.page === 'reactions', + title: this.$ts.reaction, + icon: 'fas fa-laugh', + onClick: () => { this.$router.push('/@' + getAcct(this.user) + '/reactions'); }, }, { active: this.page === 'clips', title: this.$ts.clips, diff --git a/src/client/pages/user/reactions.vue b/src/client/pages/user/reactions.vue new file mode 100644 index 000000000..5ac7e0102 --- /dev/null +++ b/src/client/pages/user/reactions.vue @@ -0,0 +1,81 @@ + + + + + diff --git a/src/models/repositories/note-reaction.ts b/src/models/repositories/note-reaction.ts index ba74076f6..5d8606552 100644 --- a/src/models/repositories/note-reaction.ts +++ b/src/models/repositories/note-reaction.ts @@ -1,6 +1,6 @@ import { EntityRepository, Repository } from 'typeorm'; import { NoteReaction } from '@/models/entities/note-reaction'; -import { Users } from '../index'; +import { Notes, Users } from '../index'; import { Packed } from '@/misc/schema'; import { convertLegacyReaction } from '@/misc/reaction-lib'; import { User } from '@/models/entities/user'; @@ -9,8 +9,15 @@ import { User } from '@/models/entities/user'; export class NoteReactionRepository extends Repository { public async pack( src: NoteReaction['id'] | NoteReaction, - me?: { id: User['id'] } | null | undefined + me?: { id: User['id'] } | null | undefined, + options?: { + withNote: boolean; + }, ): Promise> { + const opts = Object.assign({ + withNote: false, + }, options); + const reaction = typeof src === 'object' ? src : await this.findOneOrFail(src); return { @@ -18,6 +25,9 @@ export class NoteReactionRepository extends Repository { createdAt: reaction.createdAt.toISOString(), user: await Users.pack(reaction.userId, me), type: convertLegacyReaction(reaction.reaction), + ...(opts.withNote ? { + note: await Notes.pack(reaction.noteId, me), + } : {}) }; } } diff --git a/src/server/api/endpoints/users/reactions.ts b/src/server/api/endpoints/users/reactions.ts new file mode 100644 index 000000000..44d788748 --- /dev/null +++ b/src/server/api/endpoints/users/reactions.ts @@ -0,0 +1,67 @@ +import $ from 'cafy'; +import { ID } from '@/misc/cafy-id'; +import define from '../../define'; +import { NoteReactions } from '@/models/index'; +import { makePaginationQuery } from '../../common/make-pagination-query'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query'; + +export const meta = { + tags: ['users', 'reactions'], + + requireCredential: false as const, + + params: { + userId: { + validator: $.type(ID), + }, + + limit: { + validator: $.optional.num.range(1, 100), + default: 10, + }, + + sinceId: { + validator: $.optional.type(ID), + }, + + untilId: { + validator: $.optional.type(ID), + }, + + sinceDate: { + validator: $.optional.num, + }, + + untilDate: { + validator: $.optional.num, + }, + }, + + res: { + type: 'array' as const, + optional: false as const, nullable: false as const, + items: { + type: 'object' as const, + optional: false as const, nullable: false as const, + ref: 'NoteReaction', + } + }, + + errors: { + } +}; + +export default define(meta, async (ps, me) => { + const query = makePaginationQuery(NoteReactions.createQueryBuilder('reaction'), + ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) + .andWhere(`reaction.userId = :userId`, { userId: ps.userId }) + .leftJoinAndSelect('reaction.note', 'note'); + + generateVisibilityQuery(query, me); + + const reactions = await query + .take(ps.limit!) + .getMany(); + + return await Promise.all(reactions.map(reaction => NoteReactions.pack(reaction, me, { withNote: true }))); +});