summaryrefslogtreecommitdiff
path: root/packages/backend
diff options
context:
space:
mode:
authorHazelnoot <acomputerdog@gmail.com>2025-05-09 21:33:30 -0400
committerHazelnoot <acomputerdog@gmail.com>2025-05-14 23:24:24 -0400
commit2e4ec0dd9e8f2d34592a4b8aa418c5bbe1ac5a67 (patch)
tree4c70257ab939c60735039fb3d42ef3bc3f7cdbbc /packages/backend
parentmerge: Allow port ranges in allowedPrivateIps (!1025) (diff)
downloadsharkey-2e4ec0dd9e8f2d34592a4b8aa418c5bbe1ac5a67.tar.gz
sharkey-2e4ec0dd9e8f2d34592a4b8aa418c5bbe1ac5a67.tar.bz2
sharkey-2e4ec0dd9e8f2d34592a4b8aa418c5bbe1ac5a67.zip
add role policy to allow note trending
Diffstat (limited to 'packages/backend')
-rw-r--r--packages/backend/src/core/FeaturedService.ts30
-rw-r--r--packages/backend/src/core/NoteCreateService.ts6
-rw-r--r--packages/backend/src/core/ReactionService.ts6
-rw-r--r--packages/backend/src/core/RoleService.ts4
-rw-r--r--packages/backend/src/models/json-schema/role.ts4
-rw-r--r--packages/backend/src/server/api/endpoints/gallery/posts/like.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts2
7 files changed, 36 insertions, 18 deletions
diff --git a/packages/backend/src/core/FeaturedService.ts b/packages/backend/src/core/FeaturedService.ts
index b3335e38da..cabbb46504 100644
--- a/packages/backend/src/core/FeaturedService.ts
+++ b/packages/backend/src/core/FeaturedService.ts
@@ -8,6 +8,7 @@ import * as Redis from 'ioredis';
import type { MiGalleryPost, MiNote, MiUser } from '@/models/_.js';
import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
+import { RoleService } from '@/core/RoleService.js';
const GLOBAL_NOTES_RANKING_WINDOW = 1000 * 60 * 60 * 24 * 3; // 3日ごと
export const GALLERY_POSTS_RANKING_WINDOW = 1000 * 60 * 60 * 24 * 3; // 3日ごと
@@ -21,6 +22,8 @@ export class FeaturedService {
constructor(
@Inject(DI.redis)
private redisClient: Redis.Redis, // TODO: 専用のRedisサーバーを設定できるようにする
+
+ private readonly roleService: RoleService,
) {
}
@@ -31,7 +34,14 @@ export class FeaturedService {
}
@bindThis
- private async updateRankingOf(name: string, windowRange: number, element: string, score = 1): Promise<void> {
+ private async updateRankingOf(name: string, windowRange: number, element: string, score: number, userId: string | null): Promise<void> {
+ if (userId) {
+ const policies = await this.roleService.getUserPolicies(userId);
+ if (!policies.canTrend) {
+ return;
+ }
+ }
+
const currentWindow = this.getCurrentWindow(windowRange);
const redisTransaction = this.redisClient.multi();
redisTransaction.zincrby(
@@ -89,28 +99,28 @@ export class FeaturedService {
}
@bindThis
- public updateGlobalNotesRanking(noteId: MiNote['id'], score = 1): Promise<void> {
- return this.updateRankingOf('featuredGlobalNotesRanking', GLOBAL_NOTES_RANKING_WINDOW, noteId, score);
+ public updateGlobalNotesRanking(note: Pick<MiNote, 'id' | 'userId'>, score = 1): Promise<void> {
+ return this.updateRankingOf('featuredGlobalNotesRanking', GLOBAL_NOTES_RANKING_WINDOW, note.id, score, note.userId);
}
@bindThis
- public updateGalleryPostsRanking(galleryPostId: MiGalleryPost['id'], score = 1): Promise<void> {
- return this.updateRankingOf('featuredGalleryPostsRanking', GALLERY_POSTS_RANKING_WINDOW, galleryPostId, score);
+ public updateGalleryPostsRanking(galleryPost: Pick<MiGalleryPost, 'id' | 'userId'>, score = 1): Promise<void> {
+ return this.updateRankingOf('featuredGalleryPostsRanking', GALLERY_POSTS_RANKING_WINDOW, galleryPost.id, score, galleryPost.userId);
}
@bindThis
- public updateInChannelNotesRanking(channelId: MiNote['channelId'], noteId: MiNote['id'], score = 1): Promise<void> {
- return this.updateRankingOf(`featuredInChannelNotesRanking:${channelId}`, GLOBAL_NOTES_RANKING_WINDOW, noteId, score);
+ public updateInChannelNotesRanking(channelId: MiNote['channelId'], note: Pick<MiNote, 'id' | 'userId'>, score = 1): Promise<void> {
+ return this.updateRankingOf(`featuredInChannelNotesRanking:${channelId}`, GLOBAL_NOTES_RANKING_WINDOW, note.id, score, note.userId);
}
@bindThis
- public updatePerUserNotesRanking(userId: MiUser['id'], noteId: MiNote['id'], score = 1): Promise<void> {
- return this.updateRankingOf(`featuredPerUserNotesRanking:${userId}`, PER_USER_NOTES_RANKING_WINDOW, noteId, score);
+ public updatePerUserNotesRanking(userId: MiUser['id'], note: Pick<MiNote, 'id'>, score = 1): Promise<void> {
+ return this.updateRankingOf(`featuredPerUserNotesRanking:${userId}`, PER_USER_NOTES_RANKING_WINDOW, note.id, score, userId);
}
@bindThis
public updateHashtagsRanking(hashtag: string, score = 1): Promise<void> {
- return this.updateRankingOf('featuredHashtagsRanking', HASHTAG_RANKING_WINDOW, hashtag, score);
+ return this.updateRankingOf('featuredHashtagsRanking', HASHTAG_RANKING_WINDOW, hashtag, score, null);
}
@bindThis
diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts
index e961d4236c..b810ae0b5b 100644
--- a/packages/backend/src/core/NoteCreateService.ts
+++ b/packages/backend/src/core/NoteCreateService.ts
@@ -826,12 +826,12 @@ export class NoteCreateService implements OnApplicationShutdown {
if (Math.random() < 0.3 && (Date.now() - this.idService.parse(renote.id).date.getTime()) < 1000 * 60 * 60 * 24 * 3) {
if (renote.channelId != null) {
if (renote.replyId == null) {
- this.featuredService.updateInChannelNotesRanking(renote.channelId, renote.id, 5);
+ this.featuredService.updateInChannelNotesRanking(renote.channelId, renote, 5);
}
} else {
if (renote.visibility === 'public' && renote.userHost == null && renote.replyId == null) {
- this.featuredService.updateGlobalNotesRanking(renote.id, 5);
- this.featuredService.updatePerUserNotesRanking(renote.userId, renote.id, 5);
+ this.featuredService.updateGlobalNotesRanking(renote, 5);
+ this.featuredService.updatePerUserNotesRanking(renote.userId, renote, 5);
}
}
}
diff --git a/packages/backend/src/core/ReactionService.ts b/packages/backend/src/core/ReactionService.ts
index 0179b0680f..6cc4ef4205 100644
--- a/packages/backend/src/core/ReactionService.ts
+++ b/packages/backend/src/core/ReactionService.ts
@@ -220,12 +220,12 @@ export class ReactionService {
) {
if (note.channelId != null) {
if (note.replyId == null) {
- this.featuredService.updateInChannelNotesRanking(note.channelId, note.id, 1);
+ this.featuredService.updateInChannelNotesRanking(note.channelId, note, 1);
}
} else {
if (note.visibility === 'public' && note.userHost == null && note.replyId == null) {
- this.featuredService.updateGlobalNotesRanking(note.id, 1);
- this.featuredService.updatePerUserNotesRanking(note.userId, note.id, 1);
+ this.featuredService.updateGlobalNotesRanking(note, 1);
+ this.featuredService.updatePerUserNotesRanking(note.userId, note, 1);
}
}
}
diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts
index 039932b76d..c3b60837cf 100644
--- a/packages/backend/src/core/RoleService.ts
+++ b/packages/backend/src/core/RoleService.ts
@@ -69,6 +69,7 @@ export type RolePolicies = {
canImportMuting: boolean;
canImportUserLists: boolean;
chatAvailability: 'available' | 'readonly' | 'unavailable';
+ canTrend: boolean;
};
export const DEFAULT_POLICIES: RolePolicies = {
@@ -108,6 +109,7 @@ export const DEFAULT_POLICIES: RolePolicies = {
canImportMuting: true,
canImportUserLists: true,
chatAvailability: 'available',
+ canTrend: true,
};
@Injectable()
@@ -149,6 +151,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
) {
this.rolesCache = new MemorySingleCache<MiRole[]>(1000 * 60 * 60); // 1h
this.roleAssignmentByUserIdCache = new MemoryKVCache<MiRoleAssignment[]>(1000 * 60 * 5); // 5m
+ // TODO additional cache for final calculation?
this.redisForSub.on('message', this.onMessage);
}
@@ -465,6 +468,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
canImportMuting: calc('canImportMuting', vs => vs.some(v => v === true)),
canImportUserLists: calc('canImportUserLists', vs => vs.some(v => v === true)),
chatAvailability: calc('chatAvailability', aggregateChatAvailability),
+ canTrend: calc('canTrend', vs => vs.some(v => v === true)),
};
}
diff --git a/packages/backend/src/models/json-schema/role.ts b/packages/backend/src/models/json-schema/role.ts
index 307c114c96..363be921ed 100644
--- a/packages/backend/src/models/json-schema/role.ts
+++ b/packages/backend/src/models/json-schema/role.ts
@@ -309,6 +309,10 @@ export const packedRolePoliciesSchema = {
optional: false, nullable: false,
enum: ['available', 'readonly', 'unavailable'],
},
+ canTrend: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
},
} as const;
diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/like.ts b/packages/backend/src/server/api/endpoints/gallery/posts/like.ts
index e73110648c..ae8ad6c044 100644
--- a/packages/backend/src/server/api/endpoints/gallery/posts/like.ts
+++ b/packages/backend/src/server/api/endpoints/gallery/posts/like.ts
@@ -98,7 +98,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
// ランキング更新
if (Date.now() - this.idService.parse(post.id).date.getTime() < GALLERY_POSTS_RANKING_WINDOW) {
- await this.featuredService.updateGalleryPostsRanking(post.id, 1);
+ await this.featuredService.updateGalleryPostsRanking(post, 1);
}
this.galleryPostsRepository.increment({ id: post.id }, 'likedCount', 1);
diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts b/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts
index b0fad1eff2..be0a5a5584 100644
--- a/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts
+++ b/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts
@@ -81,7 +81,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
// ランキング更新
if (Date.now() - this.idService.parse(post.id).date.getTime() < GALLERY_POSTS_RANKING_WINDOW) {
- await this.featuredService.updateGalleryPostsRanking(post.id, -1);
+ await this.featuredService.updateGalleryPostsRanking(post, -1);
}
this.galleryPostsRepository.decrement({ id: post.id }, 'likedCount', 1);