diff options
Diffstat (limited to 'packages/backend/src/server/api/endpoints/channels')
9 files changed, 301 insertions, 165 deletions
diff --git a/packages/backend/src/server/api/endpoints/channels/create.ts b/packages/backend/src/server/api/endpoints/channels/create.ts index 94dcfe5023..21979884f9 100644 --- a/packages/backend/src/server/api/endpoints/channels/create.ts +++ b/packages/backend/src/server/api/endpoints/channels/create.ts @@ -1,8 +1,11 @@ -import define from '../../define.js'; +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { ChannelsRepository, DriveFilesRepository } from '@/models/index.js'; +import type { Channel } from '@/models/entities/Channel.js'; +import { IdService } from '@/core/IdService.js'; +import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js'; +import { DI } from '@/di-symbols.js'; import { ApiError } from '../../error.js'; -import { Channels, DriveFiles } from '@/models/index.js'; -import { Channel } from '@/models/entities/channel.js'; -import { genId } from '@/misc/gen-id.js'; export const meta = { tags: ['channels'], @@ -37,27 +40,41 @@ export const paramDef = { } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, paramDef, async (ps, user) => { - let banner = null; - if (ps.bannerId != null) { - banner = await DriveFiles.findOneBy({ - id: ps.bannerId, - userId: user.id, - }); +@Injectable() +export default class extends Endpoint<typeof meta, typeof paramDef> { + constructor( + @Inject(DI.driveFilesRepository) + private driveFilesRepository: DriveFilesRepository, - if (banner == null) { - throw new ApiError(meta.errors.noSuchFile); - } - } + @Inject(DI.channelsRepository) + private channelsRepository: ChannelsRepository, + + private idService: IdService, + private channelEntityService: ChannelEntityService, + ) { + super(meta, paramDef, async (ps, me) => { + let banner = null; + if (ps.bannerId != null) { + banner = await this.driveFilesRepository.findOneBy({ + id: ps.bannerId, + userId: me.id, + }); - const channel = await Channels.insert({ - id: genId(), - createdAt: new Date(), - userId: user.id, - name: ps.name, - description: ps.description || null, - bannerId: banner ? banner.id : null, - } as Channel).then(x => Channels.findOneByOrFail(x.identifiers[0])); + if (banner == null) { + throw new ApiError(meta.errors.noSuchFile); + } + } - return await Channels.pack(channel, user); -}); + const channel = await this.channelsRepository.insert({ + id: this.idService.genId(), + createdAt: new Date(), + userId: me.id, + name: ps.name, + description: ps.description ?? null, + bannerId: banner ? banner.id : null, + } as Channel).then(x => this.channelsRepository.findOneByOrFail(x.identifiers[0])); + + return await this.channelEntityService.pack(channel, me); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/channels/featured.ts b/packages/backend/src/server/api/endpoints/channels/featured.ts index 73980c0fad..0c3f9509d1 100644 --- a/packages/backend/src/server/api/endpoints/channels/featured.ts +++ b/packages/backend/src/server/api/endpoints/channels/featured.ts @@ -1,5 +1,8 @@ -import define from '../../define.js'; -import { Channels } from '@/models/index.js'; +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { ChannelsRepository } from '@/models/index.js'; +import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js'; +import { DI } from '@/di-symbols.js'; export const meta = { tags: ['channels'], @@ -24,12 +27,22 @@ export const paramDef = { } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, paramDef, async (ps, me) => { - const query = Channels.createQueryBuilder('channel') - .where('channel.lastNotedAt IS NOT NULL') - .orderBy('channel.lastNotedAt', 'DESC'); +@Injectable() +export default class extends Endpoint<typeof meta, typeof paramDef> { + constructor( + @Inject(DI.channelsRepository) + private channelsRepository: ChannelsRepository, - const channels = await query.take(10).getMany(); + private channelEntityService: ChannelEntityService, + ) { + super(meta, paramDef, async (ps, me) => { + const query = this.channelsRepository.createQueryBuilder('channel') + .where('channel.lastNotedAt IS NOT NULL') + .orderBy('channel.lastNotedAt', 'DESC'); - return await Promise.all(channels.map(x => Channels.pack(x, me))); -}); + const channels = await query.take(10).getMany(); + + return await Promise.all(channels.map(x => this.channelEntityService.pack(x, me))); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/channels/follow.ts b/packages/backend/src/server/api/endpoints/channels/follow.ts index 895ffed0bd..6c6b498a94 100644 --- a/packages/backend/src/server/api/endpoints/channels/follow.ts +++ b/packages/backend/src/server/api/endpoints/channels/follow.ts @@ -1,8 +1,10 @@ -import define from '../../define.js'; +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { ChannelFollowingsRepository, ChannelsRepository } from '@/models/index.js'; +import { IdService } from '@/core/IdService.js'; +import { GlobalEventService } from '@/core/GlobalEventService.js'; +import { DI } from '@/di-symbols.js'; import { ApiError } from '../../error.js'; -import { Channels, ChannelFollowings } from '@/models/index.js'; -import { genId } from '@/misc/gen-id.js'; -import { publishUserEvent } from '@/services/stream.js'; export const meta = { tags: ['channels'], @@ -29,21 +31,35 @@ export const paramDef = { } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, paramDef, async (ps, user) => { - const channel = await Channels.findOneBy({ - id: ps.channelId, - }); +@Injectable() +export default class extends Endpoint<typeof meta, typeof paramDef> { + constructor( + @Inject(DI.channelsRepository) + private channelsRepository: ChannelsRepository, - if (channel == null) { - throw new ApiError(meta.errors.noSuchChannel); - } + @Inject(DI.channelFollowingsRepository) + private channelFollowingsRepository: ChannelFollowingsRepository, + + private idService: IdService, + private globalEventService: GlobalEventService, + ) { + super(meta, paramDef, async (ps, me) => { + const channel = await Channels.findOneBy({ + id: ps.channelId, + }); - await ChannelFollowings.insert({ - id: genId(), - createdAt: new Date(), - followerId: user.id, - followeeId: channel.id, - }); + if (channel == null) { + throw new ApiError(meta.errors.noSuchChannel); + } - publishUserEvent(user.id, 'followChannel', channel); -}); + await this.channelFollowingsRepository.insert({ + id: this.idService.genId(), + createdAt: new Date(), + followerId: me.id, + followeeId: channel.id, + }); + + this.globalEventService.publishUserEvent(me.id, 'followChannel', channel); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/channels/followed.ts b/packages/backend/src/server/api/endpoints/channels/followed.ts index e4aa4d1614..5a8ab26af9 100644 --- a/packages/backend/src/server/api/endpoints/channels/followed.ts +++ b/packages/backend/src/server/api/endpoints/channels/followed.ts @@ -1,6 +1,9 @@ -import define from '../../define.js'; -import { Channels, ChannelFollowings } from '@/models/index.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { ChannelFollowingsRepository } from '@/models/index.js'; +import { QueryService } from '@/core/QueryService.js'; +import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js'; +import { DI } from '@/di-symbols.js'; export const meta = { tags: ['channels', 'account'], @@ -31,13 +34,24 @@ export const paramDef = { } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, paramDef, async (ps, me) => { - const query = makePaginationQuery(ChannelFollowings.createQueryBuilder(), ps.sinceId, ps.untilId) - .andWhere({ followerId: me.id }); +@Injectable() +export default class extends Endpoint<typeof meta, typeof paramDef> { + constructor( + @Inject(DI.channelFollowingsRepository) + private channelFollowingsRepository: ChannelFollowingsRepository, - const followings = await query - .take(ps.limit) - .getMany(); + private channelEntityService: ChannelEntityService, + private queryService: QueryService, + ) { + super(meta, paramDef, async (ps, me) => { + const query = this.queryService.makePaginationQuery(this.channelFollowingsRepository.createQueryBuilder(), ps.sinceId, ps.untilId) + .andWhere({ followerId: me.id }); - return await Promise.all(followings.map(x => Channels.pack(x.followeeId, me))); -}); + const followings = await query + .take(ps.limit) + .getMany(); + + return await Promise.all(followings.map(x => this.channelEntityService.pack(x.followeeId, me))); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/channels/owned.ts b/packages/backend/src/server/api/endpoints/channels/owned.ts index ed7e41cac2..8b8b5819e6 100644 --- a/packages/backend/src/server/api/endpoints/channels/owned.ts +++ b/packages/backend/src/server/api/endpoints/channels/owned.ts @@ -1,6 +1,9 @@ -import define from '../../define.js'; -import { Channels } from '@/models/index.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { ChannelsRepository } from '@/models/index.js'; +import { QueryService } from '@/core/QueryService.js'; +import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js'; +import { DI } from '@/di-symbols.js'; export const meta = { tags: ['channels', 'account'], @@ -31,13 +34,24 @@ export const paramDef = { } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, paramDef, async (ps, me) => { - const query = makePaginationQuery(Channels.createQueryBuilder(), ps.sinceId, ps.untilId) - .andWhere({ userId: me.id }); +@Injectable() +export default class extends Endpoint<typeof meta, typeof paramDef> { + constructor( + @Inject(DI.channelsRepository) + private channelsRepository: ChannelsRepository, - const channels = await query - .take(ps.limit) - .getMany(); + private channelEntityService: ChannelEntityService, + private queryService: QueryService, + ) { + super(meta, paramDef, async (ps, me) => { + const query = this.queryService.makePaginationQuery(this.channelsRepository.createQueryBuilder(), ps.sinceId, ps.untilId) + .andWhere({ userId: me.id }); - return await Promise.all(channels.map(x => Channels.pack(x, me))); -}); + const channels = await query + .take(ps.limit) + .getMany(); + + return await Promise.all(channels.map(x => this.channelEntityService.pack(x, me))); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/channels/show.ts b/packages/backend/src/server/api/endpoints/channels/show.ts index 87665a9865..54ae31790b 100644 --- a/packages/backend/src/server/api/endpoints/channels/show.ts +++ b/packages/backend/src/server/api/endpoints/channels/show.ts @@ -1,6 +1,9 @@ -import define from '../../define.js'; +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { ChannelsRepository } from '@/models/index.js'; +import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js'; +import { DI } from '@/di-symbols.js'; import { ApiError } from '../../error.js'; -import { Channels } from '@/models/index.js'; export const meta = { tags: ['channels'], @@ -31,14 +34,24 @@ export const paramDef = { } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, paramDef, async (ps, me) => { - const channel = await Channels.findOneBy({ - id: ps.channelId, - }); +@Injectable() +export default class extends Endpoint<typeof meta, typeof paramDef> { + constructor( + @Inject(DI.channelsRepository) + private channelsRepository: ChannelsRepository, - if (channel == null) { - throw new ApiError(meta.errors.noSuchChannel); - } + private channelEntityService: ChannelEntityService, + ) { + super(meta, paramDef, async (ps, me) => { + const channel = await this.channelsRepository.findOneBy({ + id: ps.channelId, + }); + + if (channel == null) { + throw new ApiError(meta.errors.noSuchChannel); + } - return await Channels.pack(channel, me); -}); + return await this.channelEntityService.pack(channel, me); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/channels/timeline.ts b/packages/backend/src/server/api/endpoints/channels/timeline.ts index deaa299013..1c7f1360b9 100644 --- a/packages/backend/src/server/api/endpoints/channels/timeline.ts +++ b/packages/backend/src/server/api/endpoints/channels/timeline.ts @@ -1,8 +1,11 @@ -import define from '../../define.js'; +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { ChannelsRepository, NotesRepository } from '@/models/index.js'; +import { QueryService } from '@/core/QueryService.js'; +import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; +import ActiveUsersChart from '@/core/chart/charts/active-users.js'; +import { DI } from '@/di-symbols.js'; import { ApiError } from '../../error.js'; -import { Notes, Channels } from '@/models/index.js'; -import { makePaginationQuery } from '../../common/make-pagination-query.js'; -import { activeUsersChart } from '@/services/chart/index.js'; export const meta = { tags: ['notes', 'channels'], @@ -42,35 +45,50 @@ export const paramDef = { } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, paramDef, async (ps, user) => { - const channel = await Channels.findOneBy({ - id: ps.channelId, - }); +@Injectable() +export default class extends Endpoint<typeof meta, typeof paramDef> { + constructor( + @Inject(DI.notesRepository) + private notesRepository: NotesRepository, - if (channel == null) { - throw new ApiError(meta.errors.noSuchChannel); - } + @Inject(DI.channelsRepository) + private channelsRepository: ChannelsRepository, + + private noteEntityService: NoteEntityService, + private queryService: QueryService, + private activeUsersChart: ActiveUsersChart, + ) { + super(meta, paramDef, async (ps, me) => { + const channel = await this.channelsRepository.findOneBy({ + id: ps.channelId, + }); - //#region Construct query - const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) - .andWhere('note.channelId = :channelId', { channelId: channel.id }) - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('user.avatar', 'avatar') - .leftJoinAndSelect('user.banner', 'banner') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') - .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') - .leftJoinAndSelect('renote.user', 'renoteUser') - .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') - .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') - .leftJoinAndSelect('note.channel', 'channel'); - //#endregion + if (channel == null) { + throw new ApiError(meta.errors.noSuchChannel); + } - const timeline = await query.take(ps.limit).getMany(); + //#region Construct query + const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) + .andWhere('note.channelId = :channelId', { channelId: channel.id }) + .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') + .leftJoinAndSelect('note.channel', 'channel'); + //#endregion - if (user) activeUsersChart.read(user); + const timeline = await query.take(ps.limit).getMany(); - return await Notes.packMany(timeline, user); -}); + if (me) this.activeUsersChart.read(me); + + return await this.noteEntityService.packMany(timeline, me); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/channels/unfollow.ts b/packages/backend/src/server/api/endpoints/channels/unfollow.ts index e065d897a5..b464c55097 100644 --- a/packages/backend/src/server/api/endpoints/channels/unfollow.ts +++ b/packages/backend/src/server/api/endpoints/channels/unfollow.ts @@ -1,7 +1,9 @@ -import define from '../../define.js'; +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { ChannelFollowingsRepository, ChannelsRepository } from '@/models/index.js'; +import { GlobalEventService } from '@/core/GlobalEventService.js'; +import { DI } from '@/di-symbols.js'; import { ApiError } from '../../error.js'; -import { Channels, ChannelFollowings } from '@/models/index.js'; -import { publishUserEvent } from '@/services/stream.js'; export const meta = { tags: ['channels'], @@ -28,19 +30,32 @@ export const paramDef = { } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, paramDef, async (ps, user) => { - const channel = await Channels.findOneBy({ - id: ps.channelId, - }); +@Injectable() +export default class extends Endpoint<typeof meta, typeof paramDef> { + constructor( + @Inject(DI.channelsRepository) + private channelsRepository: ChannelsRepository, - if (channel == null) { - throw new ApiError(meta.errors.noSuchChannel); - } + @Inject(DI.channelFollowingsRepository) + private channelFollowingsRepository: ChannelFollowingsRepository, + + private globalEventService: GlobalEventService, + ) { + super(meta, paramDef, async (ps, me) => { + const channel = await this.channelsRepository.findOneBy({ + id: ps.channelId, + }); - await ChannelFollowings.delete({ - followerId: user.id, - followeeId: channel.id, - }); + if (channel == null) { + throw new ApiError(meta.errors.noSuchChannel); + } - publishUserEvent(user.id, 'unfollowChannel', channel); -}); + await this.channelFollowingsRepository.delete({ + followerId: me.id, + followeeId: channel.id, + }); + + this.globalEventService.publishUserEvent(me.id, 'unfollowChannel', channel); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/channels/update.ts b/packages/backend/src/server/api/endpoints/channels/update.ts index 13104f324f..ba62e9d371 100644 --- a/packages/backend/src/server/api/endpoints/channels/update.ts +++ b/packages/backend/src/server/api/endpoints/channels/update.ts @@ -1,6 +1,9 @@ -import define from '../../define.js'; +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { DriveFilesRepository, ChannelsRepository } from '@/models/index.js'; +import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js'; +import { DI } from '@/di-symbols.js'; import { ApiError } from '../../error.js'; -import { Channels, DriveFiles } from '@/models/index.js'; export const meta = { tags: ['channels'], @@ -48,39 +51,52 @@ export const paramDef = { } as const; // eslint-disable-next-line import/no-default-export -export default define(meta, paramDef, async (ps, me) => { - const channel = await Channels.findOneBy({ - id: ps.channelId, - }); +@Injectable() +export default class extends Endpoint<typeof meta, typeof paramDef> { + constructor( + @Inject(DI.channelsRepository) + private channelsRepository: ChannelsRepository, - if (channel == null) { - throw new ApiError(meta.errors.noSuchChannel); - } + @Inject(DI.driveFilesRepository) + private driveFilesRepository: DriveFilesRepository, - if (channel.userId !== me.id) { - throw new ApiError(meta.errors.accessDenied); - } + private channelEntityService: ChannelEntityService, + ) { + super(meta, paramDef, async (ps, me) => { + const channel = await this.channelsRepository.findOneBy({ + id: ps.channelId, + }); - // eslint:disable-next-line:no-unnecessary-initializer - let banner = undefined; - if (ps.bannerId != null) { - banner = await DriveFiles.findOneBy({ - id: ps.bannerId, - userId: me.id, - }); + if (channel == null) { + throw new ApiError(meta.errors.noSuchChannel); + } - if (banner == null) { - throw new ApiError(meta.errors.noSuchFile); - } - } else if (ps.bannerId === null) { - banner = null; - } + if (channel.userId !== me.id) { + throw new ApiError(meta.errors.accessDenied); + } - await Channels.update(channel.id, { - ...(ps.name !== undefined ? { name: ps.name } : {}), - ...(ps.description !== undefined ? { description: ps.description } : {}), - ...(banner ? { bannerId: banner.id } : {}), - }); + // eslint:disable-next-line:no-unnecessary-initializer + let banner = undefined; + if (ps.bannerId != null) { + banner = await this.driveFilesRepository.findOneBy({ + id: ps.bannerId, + userId: me.id, + }); - return await Channels.pack(channel.id, me); -}); + if (banner == null) { + throw new ApiError(meta.errors.noSuchFile); + } + } else if (ps.bannerId === null) { + banner = null; + } + + await this.channelsRepository.update(channel.id, { + ...(ps.name !== undefined ? { name: ps.name } : {}), + ...(ps.description !== undefined ? { description: ps.description } : {}), + ...(banner ? { bannerId: banner.id } : {}), + }); + + return await this.channelEntityService.pack(channel.id, me); + }); + } +} |