mirror of
https://github.com/misskey-dev/misskey.git
synced 2025-01-01 02:46:20 +01:00
feat(backend): implement liked
collection of ActivityPub actors
This commit is contained in:
parent
f50941389d
commit
4ad43bca42
2 changed files with 96 additions and 1 deletions
|
@ -486,6 +486,7 @@ export class ApRendererService {
|
|||
outbox: `${id}/outbox`,
|
||||
followers: `${id}/followers`,
|
||||
following: `${id}/following`,
|
||||
liked: `${id}/liked`,
|
||||
featured: `${id}/collections/featured`,
|
||||
sharedInbox: `${this.config.url}/inbox`,
|
||||
endpoints: { sharedInbox: `${this.config.url}/inbox` },
|
||||
|
|
|
@ -13,7 +13,7 @@ import accepts from 'accepts';
|
|||
import vary from 'vary';
|
||||
import secureJson from 'secure-json-parse';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { FollowingsRepository, NotesRepository, EmojisRepository, NoteReactionsRepository, UserProfilesRepository, UserNotePiningsRepository, UsersRepository, FollowRequestsRepository } from '@/models/_.js';
|
||||
import type { FollowingsRepository, NotesRepository, EmojisRepository, NoteReactionsRepository, UserProfilesRepository, UserNotePiningsRepository, UsersRepository, FollowRequestsRepository, MiNoteReaction } from '@/models/_.js';
|
||||
import * as url from '@/misc/prelude/url.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
||||
|
@ -351,6 +351,94 @@ export class ActivityPubServerService {
|
|||
}
|
||||
}
|
||||
|
||||
@bindThis
|
||||
private async liked(
|
||||
request: FastifyRequest<{ Params: { user: string; }; Querystring: { cursor?: string; page?: string; }; }>,
|
||||
reply: FastifyReply,
|
||||
) {
|
||||
const userId = request.params.user;
|
||||
|
||||
const cursor = request.query.cursor;
|
||||
if (cursor != null && typeof cursor !== 'string') {
|
||||
reply.code(400);
|
||||
return;
|
||||
}
|
||||
|
||||
const page = request.query.page === 'true';
|
||||
|
||||
const user = await this.usersRepository.findOneBy({
|
||||
id: userId,
|
||||
host: IsNull(),
|
||||
});
|
||||
|
||||
if (user == null) {
|
||||
reply.code(404);
|
||||
return;
|
||||
}
|
||||
|
||||
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id });
|
||||
|
||||
if (!profile.publicReactions) {
|
||||
reply.code(403);
|
||||
reply.header('Cache-Control', 'public, max-age=30');
|
||||
return;
|
||||
}
|
||||
|
||||
const limit = 10;
|
||||
const partOf = `${this.config.url}/users/${userId}/liked`;
|
||||
const query = {
|
||||
userId: user.id,
|
||||
} as FindOptionsWhere<MiNoteReaction>;
|
||||
|
||||
if (page) {
|
||||
// カーソルが指定されている場合
|
||||
if (cursor) {
|
||||
query.id = LessThan(cursor);
|
||||
}
|
||||
|
||||
const [reactions, reactionsCount] = await Promise.all([
|
||||
this.noteReactionsRepository.find({
|
||||
where: query,
|
||||
take: limit + 1,
|
||||
order: { id: -1 },
|
||||
}),
|
||||
this.noteReactionsRepository.count({ where: query }),
|
||||
]);
|
||||
|
||||
// 「次のページ」があるかどうか
|
||||
const inStock = reactions.length === limit + 1;
|
||||
if (inStock) reactions.pop();
|
||||
|
||||
const renderedLikes = await Promise.all(reactions.map(reaction => this.apRendererService.renderLike(reaction, { uri: null })));
|
||||
const rendered = this.apRendererService.renderOrderedCollectionPage(
|
||||
`${partOf}?${url.query({
|
||||
page: 'true',
|
||||
cursor,
|
||||
})}`,
|
||||
reactionsCount, renderedLikes, partOf,
|
||||
undefined,
|
||||
inStock ? `${partOf}?${url.query({
|
||||
page: 'true',
|
||||
cursor: reactions.at(-1)!.id,
|
||||
})}` : undefined,
|
||||
);
|
||||
|
||||
this.setResponseType(request, reply);
|
||||
return (this.apRendererService.addContext(rendered));
|
||||
} else {
|
||||
// index page
|
||||
const reactionsCount = await this.noteReactionsRepository.count({ where: query });
|
||||
const rendered = this.apRendererService.renderOrderedCollection(
|
||||
partOf,
|
||||
reactionsCount,
|
||||
`${partOf}?page=true`,
|
||||
);
|
||||
reply.header('Cache-Control', 'public, max-age=180');
|
||||
this.setResponseType(request, reply);
|
||||
return (this.apRendererService.addContext(rendered));
|
||||
}
|
||||
}
|
||||
|
||||
@bindThis
|
||||
private async featured(request: FastifyRequest<{ Params: { user: string; }; }>, reply: FastifyReply) {
|
||||
const userId = request.params.user;
|
||||
|
@ -618,6 +706,12 @@ export class ActivityPubServerService {
|
|||
Querystring: { cursor?: string; page?: string; };
|
||||
}>('/users/:user/following', async (request, reply) => await this.following(request, reply));
|
||||
|
||||
// liked
|
||||
fastify.get<{
|
||||
Params: { user: string; };
|
||||
Querystring: { cursor?: string; page?: string; };
|
||||
}>('/users/:user/liked', async (request, reply) => await this.liked(request, reply));
|
||||
|
||||
// featured
|
||||
fastify.get<{ Params: { user: string; }; }>('/users/:user/collections/featured', async (request, reply) => await this.featured(request, reply));
|
||||
|
||||
|
|
Loading…
Reference in a new issue