summaryrefslogtreecommitdiff
path: root/packages/backend/src/core
diff options
context:
space:
mode:
authorおさむのひと <46447427+samunohito@users.noreply.github.com>2024-10-11 20:59:36 +0900
committerGitHub <noreply@github.com>2024-10-11 20:59:36 +0900
commita2cd6a7709ffacfabb738deac22cb0fd1eb7d493 (patch)
treedb473d5f5c9339db9798073c54409b3acb0cb848 /packages/backend/src/core
parentfix: admin/emoji/update で不正なエラーが発生する (#14750) (diff)
downloadsharkey-a2cd6a7709ffacfabb738deac22cb0fd1eb7d493.tar.gz
sharkey-a2cd6a7709ffacfabb738deac22cb0fd1eb7d493.tar.bz2
sharkey-a2cd6a7709ffacfabb738deac22cb0fd1eb7d493.zip
feat(backend): 7日間運営のアクティビティがないサーバを自動的に招待制にする (#14746)
* feat(backend): 7日間運営のアクティビティがないサーバを自動的に招待制にする * fix RoleService. * fix * fix * fix * add test and fix * fix * fix CHANGELOG.md * fix test
Diffstat (limited to 'packages/backend/src/core')
-rw-r--r--packages/backend/src/core/AbuseReportNotificationService.ts10
-rw-r--r--packages/backend/src/core/QueueService.ts7
-rw-r--r--packages/backend/src/core/RoleService.ts75
3 files changed, 68 insertions, 24 deletions
diff --git a/packages/backend/src/core/AbuseReportNotificationService.ts b/packages/backend/src/core/AbuseReportNotificationService.ts
index fb7c7bd2c3..7d030f2f16 100644
--- a/packages/backend/src/core/AbuseReportNotificationService.ts
+++ b/packages/backend/src/core/AbuseReportNotificationService.ts
@@ -61,7 +61,10 @@ export class AbuseReportNotificationService implements OnApplicationShutdown {
return;
}
- const moderatorIds = await this.roleService.getModeratorIds(true, true);
+ const moderatorIds = await this.roleService.getModeratorIds({
+ includeAdmins: true,
+ excludeExpire: true,
+ });
for (const moderatorId of moderatorIds) {
for (const abuseReport of abuseReports) {
@@ -370,7 +373,10 @@ export class AbuseReportNotificationService implements OnApplicationShutdown {
}
// モデレータ権限の有無で通知先設定を振り分ける
- const authorizedUserIds = await this.roleService.getModeratorIds(true, true);
+ const authorizedUserIds = await this.roleService.getModeratorIds({
+ includeAdmins: true,
+ excludeExpire: true,
+ });
const authorizedUserRecipients = Array.of<MiAbuseReportNotificationRecipient>();
const unauthorizedUserRecipients = Array.of<MiAbuseReportNotificationRecipient>();
for (const recipient of userRecipients) {
diff --git a/packages/backend/src/core/QueueService.ts b/packages/backend/src/core/QueueService.ts
index f35e456556..37028026cc 100644
--- a/packages/backend/src/core/QueueService.ts
+++ b/packages/backend/src/core/QueueService.ts
@@ -93,6 +93,13 @@ export class QueueService {
repeat: { pattern: '0 0 * * *' },
removeOnComplete: true,
});
+
+ this.systemQueue.add('checkModeratorsActivity', {
+ }, {
+ // 毎時30分に起動
+ repeat: { pattern: '30 * * * *' },
+ removeOnComplete: true,
+ });
}
@bindThis
diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts
index 583eea1a34..5af6b05942 100644
--- a/packages/backend/src/core/RoleService.ts
+++ b/packages/backend/src/core/RoleService.ts
@@ -101,6 +101,7 @@ export const DEFAULT_POLICIES: RolePolicies = {
@Injectable()
export class RoleService implements OnApplicationShutdown, OnModuleInit {
+ private rootUserIdCache: MemorySingleCache<MiUser['id']>;
private rolesCache: MemorySingleCache<MiRole[]>;
private roleAssignmentByUserIdCache: MemoryKVCache<MiRoleAssignment[]>;
private notificationService: NotificationService;
@@ -136,6 +137,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
private moderationLogService: ModerationLogService,
private fanoutTimelineService: FanoutTimelineService,
) {
+ this.rootUserIdCache = new MemorySingleCache<MiUser['id']>(1000 * 60 * 60 * 24 * 7); // 1week. rootユーザのIDは不変なので長めに
this.rolesCache = new MemorySingleCache<MiRole[]>(1000 * 60 * 60); // 1h
this.roleAssignmentByUserIdCache = new MemoryKVCache<MiRoleAssignment[]>(1000 * 60 * 5); // 5m
@@ -416,49 +418,78 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
}
@bindThis
- public async isExplorable(role: { id: MiRole['id']} | null): Promise<boolean> {
+ public async isExplorable(role: { id: MiRole['id'] } | null): Promise<boolean> {
if (role == null) return false;
const check = await this.rolesRepository.findOneBy({ id: role.id });
if (check == null) return false;
return check.isExplorable;
}
+ /**
+ * モデレーター権限のロールが割り当てられているユーザID一覧を取得する.
+ *
+ * @param opts.includeAdmins 管理者権限も含めるか(デフォルト: true)
+ * @param opts.includeRoot rootユーザも含めるか(デフォルト: false)
+ * @param opts.excludeExpire 期限切れのロールを除外するか(デフォルト: false)
+ */
@bindThis
- public async getModeratorIds(includeAdmins = true, excludeExpire = false): Promise<MiUser['id'][]> {
+ public async getModeratorIds(opts?: {
+ includeAdmins?: boolean,
+ includeRoot?: boolean,
+ excludeExpire?: boolean,
+ }): Promise<MiUser['id'][]> {
+ const includeAdmins = opts?.includeAdmins ?? true;
+ const includeRoot = opts?.includeRoot ?? false;
+ const excludeExpire = opts?.excludeExpire ?? false;
+
const roles = await this.rolesCache.fetch(() => this.rolesRepository.findBy({}));
const moderatorRoles = includeAdmins
? roles.filter(r => r.isModerator || r.isAdministrator)
: roles.filter(r => r.isModerator);
- // TODO: isRootなアカウントも含める
const assigns = moderatorRoles.length > 0
? await this.roleAssignmentsRepository.findBy({ roleId: In(moderatorRoles.map(r => r.id)) })
: [];
+ // Setを経由して重複を除去(ユーザIDは重複する可能性があるので)
const now = Date.now();
- const result = [
- // Setを経由して重複を除去(ユーザIDは重複する可能性があるので)
- ...new Set(
- assigns
- .filter(it =>
- (excludeExpire)
- ? (it.expiresAt == null || it.expiresAt.getTime() > now)
- : true,
- )
- .map(a => a.userId),
- ),
- ];
+ const resultSet = new Set(
+ assigns
+ .filter(it =>
+ (excludeExpire)
+ ? (it.expiresAt == null || it.expiresAt.getTime() > now)
+ : true,
+ )
+ .map(a => a.userId),
+ );
+
+ if (includeRoot) {
+ const rootUserId = await this.rootUserIdCache.fetch(async () => {
+ const it = await this.usersRepository.createQueryBuilder('users')
+ .select('id')
+ .where({ isRoot: true })
+ .getRawOne<{ id: string }>();
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ return it!.id;
+ });
+ resultSet.add(rootUserId);
+ }
- return result.sort((x, y) => x.localeCompare(y));
+ return [...resultSet].sort((x, y) => x.localeCompare(y));
}
@bindThis
- public async getModerators(includeAdmins = true): Promise<MiUser[]> {
- const ids = await this.getModeratorIds(includeAdmins);
- const users = ids.length > 0 ? await this.usersRepository.findBy({
- id: In(ids),
- }) : [];
- return users;
+ public async getModerators(opts?: {
+ includeAdmins?: boolean,
+ includeRoot?: boolean,
+ excludeExpire?: boolean,
+ }): Promise<MiUser[]> {
+ const ids = await this.getModeratorIds(opts);
+ return ids.length > 0
+ ? await this.usersRepository.findBy({
+ id: In(ids),
+ })
+ : [];
}
@bindThis