From 6721d27e3f085a2335485eed0eb90409240539c1 Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 25 Apr 2019 13:25:10 +0900 Subject: [PATCH] Improve hashtag API --- src/models/index.ts | 4 +- src/models/repositories/hashtag.ts | 71 +++++++++++++++++++++++ src/server/api/endpoints/hashtags/list.ts | 2 +- src/server/api/endpoints/hashtags/show.ts | 48 +++++++++++++++ src/server/api/openapi/schemas.ts | 46 +-------------- 5 files changed, 124 insertions(+), 47 deletions(-) create mode 100644 src/models/repositories/hashtag.ts create mode 100644 src/server/api/endpoints/hashtags/show.ts diff --git a/src/models/index.ts b/src/models/index.ts index d66e4e710..826044e7a 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -7,7 +7,6 @@ import { Meta } from './entities/meta'; import { SwSubscription } from './entities/sw-subscription'; import { NoteWatching } from './entities/note-watching'; import { UserListJoining } from './entities/user-list-joining'; -import { Hashtag } from './entities/hashtag'; import { NoteUnread } from './entities/note-unread'; import { RegistrationTicket } from './entities/registration-tickets'; import { UserRepository } from './repositories/user'; @@ -35,6 +34,7 @@ import { FollowingRepository } from './repositories/following'; import { AbuseUserReportRepository } from './repositories/abuse-user-report'; import { AuthSessionRepository } from './repositories/auth-session'; import { UserProfile } from './entities/user-profile'; +import { HashtagRepository } from './repositories/hashtag'; export const Apps = getCustomRepository(AppRepository); export const Notes = getCustomRepository(NoteRepository); @@ -62,7 +62,7 @@ export const Metas = getRepository(Meta); export const Mutings = getCustomRepository(MutingRepository); export const Blockings = getCustomRepository(BlockingRepository); export const SwSubscriptions = getRepository(SwSubscription); -export const Hashtags = getRepository(Hashtag); +export const Hashtags = getCustomRepository(HashtagRepository); export const AbuseUserReports = getCustomRepository(AbuseUserReportRepository); export const RegistrationTickets = getRepository(RegistrationTicket); export const AuthSessions = getCustomRepository(AuthSessionRepository); diff --git a/src/models/repositories/hashtag.ts b/src/models/repositories/hashtag.ts new file mode 100644 index 000000000..22321fca8 --- /dev/null +++ b/src/models/repositories/hashtag.ts @@ -0,0 +1,71 @@ +import { EntityRepository, Repository } from 'typeorm'; +import { Hashtag } from '../entities/hashtag'; +import { SchemaType, types, bool } from '../../misc/schema'; + +export type PackedHashtag = SchemaType; + +@EntityRepository(Hashtag) +export class HashtagRepository extends Repository { + public packMany( + hashtags: Hashtag[], + ) { + return Promise.all(hashtags.map(x => this.pack(x))); + } + + public async pack( + src: Hashtag, + ): Promise { + return { + tag: src.name, + mentionedUsersCount: src.mentionedUsersCount, + mentionedLocalUsersCount: src.mentionedLocalUsersCount, + mentionedRemoteUsersCount: src.mentionedRemoteUsersCount, + attachedUsersCount: src.attachedUsersCount, + attachedLocalUsersCount: src.attachedLocalUsersCount, + attachedRemoteUsersCount: src.attachedRemoteUsersCount, + }; + } +} + +export const packedHashtagSchema = { + type: types.object, + optional: bool.false, nullable: bool.false, + properties: { + tag: { + type: types.string, + optional: bool.false, nullable: bool.false, + description: 'The hashtag name. No # prefixed.', + example: 'misskey', + }, + mentionedUsersCount: { + type: types.number, + optional: bool.false, nullable: bool.false, + description: 'Number of all users using this hashtag.' + }, + mentionedLocalUsersCount: { + type: types.number, + optional: bool.false, nullable: bool.false, + description: 'Number of local users using this hashtag.' + }, + mentionedRemoteUsersCount: { + type: types.number, + optional: bool.false, nullable: bool.false, + description: 'Number of remote users using this hashtag.' + }, + attachedUsersCount: { + type: types.number, + optional: bool.false, nullable: bool.false, + description: 'Number of all users who attached this hashtag to profile.' + }, + attachedLocalUsersCount: { + type: types.number, + optional: bool.false, nullable: bool.false, + description: 'Number of local users who attached this hashtag to profile.' + }, + attachedRemoteUsersCount: { + type: types.number, + optional: bool.false, nullable: bool.false, + description: 'Number of remote users who attached this hashtag to profile.' + }, + } +}; diff --git a/src/server/api/endpoints/hashtags/list.ts b/src/server/api/endpoints/hashtags/list.ts index 89cc92642..9023f1191 100644 --- a/src/server/api/endpoints/hashtags/list.ts +++ b/src/server/api/endpoints/hashtags/list.ts @@ -92,5 +92,5 @@ export default define(meta, async (ps, me) => { const tags = await query.take(ps.limit!).getMany(); - return tags; + return Hashtags.packMany(tags); }); diff --git a/src/server/api/endpoints/hashtags/show.ts b/src/server/api/endpoints/hashtags/show.ts new file mode 100644 index 000000000..72a4cc7c8 --- /dev/null +++ b/src/server/api/endpoints/hashtags/show.ts @@ -0,0 +1,48 @@ +import $ from 'cafy'; +import define from '../../define'; +import { ApiError } from '../../error'; +import { Hashtags } from '../../../../models'; +import { types, bool } from '../../../../misc/schema'; + +export const meta = { + desc: { + 'ja-JP': '指定したハッシュタグの情報を取得します。', + }, + + tags: ['hashtags'], + + requireCredential: false, + + params: { + tag: { + validator: $.str, + desc: { + 'ja-JP': '対象のハッシュタグ(#なし)', + 'en-US': 'Target hashtag. (no # prefixed)' + } + } + }, + + res: { + type: types.object, + optional: bool.false, nullable: bool.false, + ref: 'Hashtag', + }, + + errors: { + noSuchHashtag: { + message: 'No such hashtag.', + code: 'NO_SUCH_HASHTAG', + id: '110ee688-193e-4a3a-9ecf-c167b2e6981e' + } + } +}; + +export default define(meta, async (ps, user) => { + const hashtag = await Hashtags.findOne({ name: ps.tag.toLowerCase() }); + if (hashtag == null) { + throw new ApiError(meta.errors.noSuchHashtag); + } + + return await Hashtags.pack(hashtag); +}); diff --git a/src/server/api/openapi/schemas.ts b/src/server/api/openapi/schemas.ts index e54f989e7..34e6f8947 100644 --- a/src/server/api/openapi/schemas.ts +++ b/src/server/api/openapi/schemas.ts @@ -11,6 +11,7 @@ import { packedFollowingSchema } from '../../../models/repositories/following'; import { packedMutingSchema } from '../../../models/repositories/muting'; import { packedBlockingSchema } from '../../../models/repositories/blocking'; import { packedNoteReactionSchema } from '../../../models/repositories/note-reaction'; +import { packedHashtagSchema } from '../../../models/repositories/hashtag'; export function convertSchemaToOpenApiSchema(schema: Schema) { const res: any = schema; @@ -74,48 +75,5 @@ export const schemas = { Muting: convertSchemaToOpenApiSchema(packedMutingSchema), Blocking: convertSchemaToOpenApiSchema(packedBlockingSchema), NoteReaction: convertSchemaToOpenApiSchema(packedNoteReactionSchema), - - Hashtag: { - type: 'object', - properties: { - tag: { - type: 'string', - description: 'The hashtag name. No # prefixed.', - example: 'misskey', - }, - mentionedUsersCount: { - type: 'number', - description: 'Number of all users using this hashtag.' - }, - mentionedLocalUsersCount: { - type: 'number', - description: 'Number of local users using this hashtag.' - }, - mentionedRemoteUsersCount: { - type: 'number', - description: 'Number of remote users using this hashtag.' - }, - attachedUsersCount: { - type: 'number', - description: 'Number of all users who attached this hashtag to profile.' - }, - attachedLocalUsersCount: { - type: 'number', - description: 'Number of local users who attached this hashtag to profile.' - }, - attachedRemoteUsersCount: { - type: 'number', - description: 'Number of remote users who attached this hashtag to profile.' - }, - }, - required: [ - 'tag', - 'mentionedUsersCount', - 'mentionedLocalUsersCount', - 'mentionedRemoteUsersCount', - 'attachedUsersCount', - 'attachedLocalUsersCount', - 'attachedRemoteUsersCount', - ] - }, + Hashtag: convertSchemaToOpenApiSchema(packedHashtagSchema), };