refactor/perf(backend): provide metadata statically (#14601)
* wip * Update ReactionService.ts * Update ApiCallService.ts * Update timeline.ts * Update GlobalModule.ts * Update GlobalModule.ts * Update NoteEntityService.ts * wip * wip * wip * Update ApPersonService.ts * wip * Update GlobalModule.ts * Update mock-resolver.ts * Update RoleService.ts * Update activitypub.ts * Update activitypub.ts * Update activitypub.ts * Update activitypub.ts * Update activitypub.ts * clean up * Update utils.ts * Update UtilityService.ts * Revert "Update utils.ts" This reverts commita27d4be764
. * Revert "Update UtilityService.ts" This reverts commite5fd9e004c
. * vuwa- * Revert "vuwa-" This reverts commit0c3bd12472
. * Update entry.ts * Update entry.ts * Update entry.ts * Update entry.ts * Update jest.setup.ts
This commit is contained in:
@@ -14,10 +14,10 @@ import type {
|
||||
AbuseReportNotificationRecipientRepository,
|
||||
MiAbuseReportNotificationRecipient,
|
||||
MiAbuseUserReport,
|
||||
MiMeta,
|
||||
MiUser,
|
||||
} from '@/models/_.js';
|
||||
import { EmailService } from '@/core/EmailService.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { RoleService } from '@/core/RoleService.js';
|
||||
import { RecipientMethod } from '@/models/AbuseReportNotificationRecipient.js';
|
||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||
@@ -27,15 +27,19 @@ import { IdService } from './IdService.js';
|
||||
@Injectable()
|
||||
export class AbuseReportNotificationService implements OnApplicationShutdown {
|
||||
constructor(
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.abuseReportNotificationRecipientRepository)
|
||||
private abuseReportNotificationRecipientRepository: AbuseReportNotificationRecipientRepository,
|
||||
|
||||
@Inject(DI.redisForSub)
|
||||
private redisForSub: Redis.Redis,
|
||||
|
||||
private idService: IdService,
|
||||
private roleService: RoleService,
|
||||
private systemWebhookService: SystemWebhookService,
|
||||
private emailService: EmailService,
|
||||
private metaService: MetaService,
|
||||
private moderationLogService: ModerationLogService,
|
||||
private globalEventService: GlobalEventService,
|
||||
) {
|
||||
@@ -93,10 +97,8 @@ export class AbuseReportNotificationService implements OnApplicationShutdown {
|
||||
.filter(x => x != null),
|
||||
);
|
||||
|
||||
// 送信先の鮮度を保つため、毎回取得する
|
||||
const meta = await this.metaService.fetch(true);
|
||||
recipientEMailAddresses.push(
|
||||
...(meta.email ? [meta.email] : []),
|
||||
...(this.meta.email ? [this.meta.email] : []),
|
||||
);
|
||||
|
||||
if (recipientEMailAddresses.length <= 0) {
|
||||
|
@@ -9,7 +9,7 @@ import { IsNull, In, MoreThan, Not } from 'typeorm';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { MiLocalUser, MiRemoteUser, MiUser } from '@/models/User.js';
|
||||
import type { BlockingsRepository, FollowingsRepository, InstancesRepository, MutingsRepository, UserListMembershipsRepository, UsersRepository } from '@/models/_.js';
|
||||
import type { BlockingsRepository, FollowingsRepository, InstancesRepository, MiMeta, MutingsRepository, UserListMembershipsRepository, UsersRepository } from '@/models/_.js';
|
||||
import type { RelationshipJobData, ThinUser } from '@/queue/types.js';
|
||||
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
@@ -22,13 +22,15 @@ import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { ProxyAccountService } from '@/core/ProxyAccountService.js';
|
||||
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import InstanceChart from '@/core/chart/charts/instance.js';
|
||||
import PerUserFollowingChart from '@/core/chart/charts/per-user-following.js';
|
||||
|
||||
@Injectable()
|
||||
export class AccountMoveService {
|
||||
constructor(
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.usersRepository)
|
||||
private usersRepository: UsersRepository,
|
||||
|
||||
@@ -57,7 +59,6 @@ export class AccountMoveService {
|
||||
private perUserFollowingChart: PerUserFollowingChart,
|
||||
private federatedInstanceService: FederatedInstanceService,
|
||||
private instanceChart: InstanceChart,
|
||||
private metaService: MetaService,
|
||||
private relayService: RelayService,
|
||||
private queueService: QueueService,
|
||||
) {
|
||||
@@ -276,7 +277,7 @@ export class AccountMoveService {
|
||||
if (this.userEntityService.isRemoteUser(oldAccount)) {
|
||||
this.federatedInstanceService.fetch(oldAccount.host).then(async i => {
|
||||
this.instancesRepository.decrement({ id: i.id }, 'followersCount', localFollowerIds.length);
|
||||
if ((await this.metaService.fetch()).enableChartsForFederatedInstances) {
|
||||
if (this.meta.enableChartsForFederatedInstances) {
|
||||
this.instanceChart.updateFollowers(i.host, false);
|
||||
}
|
||||
});
|
||||
|
@@ -11,11 +11,10 @@ import { sharpBmp } from '@misskey-dev/sharp-read-bmp';
|
||||
import { IsNull } from 'typeorm';
|
||||
import { DeleteObjectCommandInput, PutObjectCommandInput, NoSuchKey } from '@aws-sdk/client-s3';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { DriveFilesRepository, UsersRepository, DriveFoldersRepository, UserProfilesRepository } from '@/models/_.js';
|
||||
import type { DriveFilesRepository, UsersRepository, DriveFoldersRepository, UserProfilesRepository, MiMeta } from '@/models/_.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import Logger from '@/logger.js';
|
||||
import type { MiRemoteUser, MiUser } from '@/models/User.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { MiDriveFile } from '@/models/DriveFile.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js';
|
||||
@@ -99,6 +98,9 @@ export class DriveService {
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.usersRepository)
|
||||
private usersRepository: UsersRepository,
|
||||
|
||||
@@ -115,7 +117,6 @@ export class DriveService {
|
||||
private userEntityService: UserEntityService,
|
||||
private driveFileEntityService: DriveFileEntityService,
|
||||
private idService: IdService,
|
||||
private metaService: MetaService,
|
||||
private downloadService: DownloadService,
|
||||
private internalStorageService: InternalStorageService,
|
||||
private s3Service: S3Service,
|
||||
@@ -149,9 +150,7 @@ export class DriveService {
|
||||
// thunbnail, webpublic を必要なら生成
|
||||
const alts = await this.generateAlts(path, type, !file.uri);
|
||||
|
||||
const meta = await this.metaService.fetch();
|
||||
|
||||
if (meta.useObjectStorage) {
|
||||
if (this.meta.useObjectStorage) {
|
||||
//#region ObjectStorage params
|
||||
let [ext] = (name.match(/\.([a-zA-Z0-9_-]+)$/) ?? ['']);
|
||||
|
||||
@@ -170,11 +169,11 @@ export class DriveService {
|
||||
ext = '';
|
||||
}
|
||||
|
||||
const baseUrl = meta.objectStorageBaseUrl
|
||||
?? `${ meta.objectStorageUseSSL ? 'https' : 'http' }://${ meta.objectStorageEndpoint }${ meta.objectStoragePort ? `:${meta.objectStoragePort}` : '' }/${ meta.objectStorageBucket }`;
|
||||
const baseUrl = this.meta.objectStorageBaseUrl
|
||||
?? `${ this.meta.objectStorageUseSSL ? 'https' : 'http' }://${ this.meta.objectStorageEndpoint }${ this.meta.objectStoragePort ? `:${this.meta.objectStoragePort}` : '' }/${ this.meta.objectStorageBucket }`;
|
||||
|
||||
// for original
|
||||
const key = `${meta.objectStoragePrefix}/${randomUUID()}${ext}`;
|
||||
const key = `${this.meta.objectStoragePrefix}/${randomUUID()}${ext}`;
|
||||
const url = `${ baseUrl }/${ key }`;
|
||||
|
||||
// for alts
|
||||
@@ -191,7 +190,7 @@ export class DriveService {
|
||||
];
|
||||
|
||||
if (alts.webpublic) {
|
||||
webpublicKey = `${meta.objectStoragePrefix}/webpublic-${randomUUID()}.${alts.webpublic.ext}`;
|
||||
webpublicKey = `${this.meta.objectStoragePrefix}/webpublic-${randomUUID()}.${alts.webpublic.ext}`;
|
||||
webpublicUrl = `${ baseUrl }/${ webpublicKey }`;
|
||||
|
||||
this.registerLogger.info(`uploading webpublic: ${webpublicKey}`);
|
||||
@@ -199,7 +198,7 @@ export class DriveService {
|
||||
}
|
||||
|
||||
if (alts.thumbnail) {
|
||||
thumbnailKey = `${meta.objectStoragePrefix}/thumbnail-${randomUUID()}.${alts.thumbnail.ext}`;
|
||||
thumbnailKey = `${this.meta.objectStoragePrefix}/thumbnail-${randomUUID()}.${alts.thumbnail.ext}`;
|
||||
thumbnailUrl = `${ baseUrl }/${ thumbnailKey }`;
|
||||
|
||||
this.registerLogger.info(`uploading thumbnail: ${thumbnailKey}`);
|
||||
@@ -376,10 +375,8 @@ export class DriveService {
|
||||
if (type === 'image/apng') type = 'image/png';
|
||||
if (!FILE_TYPE_BROWSERSAFE.includes(type)) type = 'application/octet-stream';
|
||||
|
||||
const meta = await this.metaService.fetch();
|
||||
|
||||
const params = {
|
||||
Bucket: meta.objectStorageBucket,
|
||||
Bucket: this.meta.objectStorageBucket,
|
||||
Key: key,
|
||||
Body: stream,
|
||||
ContentType: type,
|
||||
@@ -392,9 +389,9 @@ export class DriveService {
|
||||
// 許可されているファイル形式でしか拡張子をつけない
|
||||
ext ? correctFilename(filename, ext) : filename,
|
||||
);
|
||||
if (meta.objectStorageSetPublicRead) params.ACL = 'public-read';
|
||||
if (this.meta.objectStorageSetPublicRead) params.ACL = 'public-read';
|
||||
|
||||
await this.s3Service.upload(meta, params)
|
||||
await this.s3Service.upload(this.meta, params)
|
||||
.then(
|
||||
result => {
|
||||
if ('Bucket' in result) { // CompleteMultipartUploadCommandOutput
|
||||
@@ -460,32 +457,31 @@ export class DriveService {
|
||||
ext = null,
|
||||
}: AddFileArgs): Promise<MiDriveFile> {
|
||||
let skipNsfwCheck = false;
|
||||
const instance = await this.metaService.fetch();
|
||||
const userRoleNSFW = user && (await this.roleService.getUserPolicies(user.id)).alwaysMarkNsfw;
|
||||
if (user == null) {
|
||||
skipNsfwCheck = true;
|
||||
} else if (userRoleNSFW) {
|
||||
skipNsfwCheck = true;
|
||||
}
|
||||
if (instance.sensitiveMediaDetection === 'none') skipNsfwCheck = true;
|
||||
if (user && instance.sensitiveMediaDetection === 'local' && this.userEntityService.isRemoteUser(user)) skipNsfwCheck = true;
|
||||
if (user && instance.sensitiveMediaDetection === 'remote' && this.userEntityService.isLocalUser(user)) skipNsfwCheck = true;
|
||||
if (this.meta.sensitiveMediaDetection === 'none') skipNsfwCheck = true;
|
||||
if (user && this.meta.sensitiveMediaDetection === 'local' && this.userEntityService.isRemoteUser(user)) skipNsfwCheck = true;
|
||||
if (user && this.meta.sensitiveMediaDetection === 'remote' && this.userEntityService.isLocalUser(user)) skipNsfwCheck = true;
|
||||
|
||||
const info = await this.fileInfoService.getFileInfo(path, {
|
||||
skipSensitiveDetection: skipNsfwCheck,
|
||||
sensitiveThreshold: // 感度が高いほどしきい値は低くすることになる
|
||||
instance.sensitiveMediaDetectionSensitivity === 'veryHigh' ? 0.1 :
|
||||
instance.sensitiveMediaDetectionSensitivity === 'high' ? 0.3 :
|
||||
instance.sensitiveMediaDetectionSensitivity === 'low' ? 0.7 :
|
||||
instance.sensitiveMediaDetectionSensitivity === 'veryLow' ? 0.9 :
|
||||
this.meta.sensitiveMediaDetectionSensitivity === 'veryHigh' ? 0.1 :
|
||||
this.meta.sensitiveMediaDetectionSensitivity === 'high' ? 0.3 :
|
||||
this.meta.sensitiveMediaDetectionSensitivity === 'low' ? 0.7 :
|
||||
this.meta.sensitiveMediaDetectionSensitivity === 'veryLow' ? 0.9 :
|
||||
0.5,
|
||||
sensitiveThresholdForPorn: 0.75,
|
||||
enableSensitiveMediaDetectionForVideos: instance.enableSensitiveMediaDetectionForVideos,
|
||||
enableSensitiveMediaDetectionForVideos: this.meta.enableSensitiveMediaDetectionForVideos,
|
||||
});
|
||||
this.registerLogger.info(`${JSON.stringify(info)}`);
|
||||
|
||||
// 現状 false positive が多すぎて実用に耐えない
|
||||
//if (info.porn && instance.disallowUploadWhenPredictedAsPorn) {
|
||||
//if (info.porn && this.meta.disallowUploadWhenPredictedAsPorn) {
|
||||
// throw new IdentifiableError('282f77bf-5816-4f72-9264-aa14d8261a21', 'Detected as porn.');
|
||||
//}
|
||||
|
||||
@@ -589,9 +585,9 @@ export class DriveService {
|
||||
sensitive ?? false
|
||||
: false;
|
||||
|
||||
if (user && this.utilityService.isMediaSilencedHost(instance.mediaSilencedHosts, user.host)) file.isSensitive = true;
|
||||
if (user && this.utilityService.isMediaSilencedHost(this.meta.mediaSilencedHosts, user.host)) file.isSensitive = true;
|
||||
if (info.sensitive && profile!.autoSensitive) file.isSensitive = true;
|
||||
if (info.sensitive && instance.setSensitiveFlagAutomatically) file.isSensitive = true;
|
||||
if (info.sensitive && this.meta.setSensitiveFlagAutomatically) file.isSensitive = true;
|
||||
if (userRoleNSFW) file.isSensitive = true;
|
||||
|
||||
if (url !== null) {
|
||||
@@ -652,7 +648,7 @@ export class DriveService {
|
||||
// ローカルユーザーのみ
|
||||
this.perUserDriveChart.update(file, true);
|
||||
} else {
|
||||
if ((await this.metaService.fetch()).enableChartsForFederatedInstances) {
|
||||
if (this.meta.enableChartsForFederatedInstances) {
|
||||
this.instanceChart.updateDrive(file, true);
|
||||
}
|
||||
}
|
||||
@@ -798,7 +794,7 @@ export class DriveService {
|
||||
// ローカルユーザーのみ
|
||||
this.perUserDriveChart.update(file, false);
|
||||
} else {
|
||||
if ((await this.metaService.fetch()).enableChartsForFederatedInstances) {
|
||||
if (this.meta.enableChartsForFederatedInstances) {
|
||||
this.instanceChart.updateDrive(file, false);
|
||||
}
|
||||
}
|
||||
@@ -820,14 +816,13 @@ export class DriveService {
|
||||
|
||||
@bindThis
|
||||
public async deleteObjectStorageFile(key: string) {
|
||||
const meta = await this.metaService.fetch();
|
||||
try {
|
||||
const param = {
|
||||
Bucket: meta.objectStorageBucket,
|
||||
Bucket: this.meta.objectStorageBucket,
|
||||
Key: key,
|
||||
} as DeleteObjectCommandInput;
|
||||
|
||||
await this.s3Service.delete(meta, param);
|
||||
await this.s3Service.delete(this.meta, param);
|
||||
} catch (err: any) {
|
||||
if (err.name === 'NoSuchKey') {
|
||||
this.deleteLogger.warn(`The object storage had no such key to delete: ${key}. Skipping this.`, err as Error);
|
||||
|
@@ -8,16 +8,14 @@ import * as nodemailer from 'nodemailer';
|
||||
import juice from 'juice';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { validate as validateEmail } from 'deep-email-validator';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { UtilityService } from '@/core/UtilityService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import type Logger from '@/logger.js';
|
||||
import type { UserProfilesRepository } from '@/models/_.js';
|
||||
import type { MiMeta, UserProfilesRepository } from '@/models/_.js';
|
||||
import { LoggerService } from '@/core/LoggerService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
||||
import { QueueService } from '@/core/QueueService.js';
|
||||
|
||||
@Injectable()
|
||||
export class EmailService {
|
||||
@@ -27,38 +25,37 @@ export class EmailService {
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.userProfilesRepository)
|
||||
private userProfilesRepository: UserProfilesRepository,
|
||||
|
||||
private metaService: MetaService,
|
||||
private loggerService: LoggerService,
|
||||
private utilityService: UtilityService,
|
||||
private httpRequestService: HttpRequestService,
|
||||
private queueService: QueueService,
|
||||
) {
|
||||
this.logger = this.loggerService.getLogger('email');
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async sendEmail(to: string, subject: string, html: string, text: string) {
|
||||
const meta = await this.metaService.fetch(true);
|
||||
|
||||
if (!meta.enableEmail) return;
|
||||
if (!this.meta.enableEmail) return;
|
||||
|
||||
const iconUrl = `${this.config.url}/static-assets/mi-white.png`;
|
||||
const emailSettingUrl = `${this.config.url}/settings/email`;
|
||||
|
||||
const enableAuth = meta.smtpUser != null && meta.smtpUser !== '';
|
||||
const enableAuth = this.meta.smtpUser != null && this.meta.smtpUser !== '';
|
||||
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: meta.smtpHost,
|
||||
port: meta.smtpPort,
|
||||
secure: meta.smtpSecure,
|
||||
host: this.meta.smtpHost,
|
||||
port: this.meta.smtpPort,
|
||||
secure: this.meta.smtpSecure,
|
||||
ignoreTLS: !enableAuth,
|
||||
proxy: this.config.proxySmtp,
|
||||
auth: enableAuth ? {
|
||||
user: meta.smtpUser,
|
||||
pass: meta.smtpPass,
|
||||
user: this.meta.smtpUser,
|
||||
pass: this.meta.smtpPass,
|
||||
} : undefined,
|
||||
} as any);
|
||||
|
||||
@@ -127,7 +124,7 @@ export class EmailService {
|
||||
<body>
|
||||
<main>
|
||||
<header>
|
||||
<img src="${ meta.logoImageUrl ?? meta.iconUrl ?? iconUrl }"/>
|
||||
<img src="${ this.meta.logoImageUrl ?? this.meta.iconUrl ?? iconUrl }"/>
|
||||
</header>
|
||||
<article>
|
||||
<h1>${ subject }</h1>
|
||||
@@ -148,7 +145,7 @@ export class EmailService {
|
||||
try {
|
||||
// TODO: htmlサニタイズ
|
||||
const info = await transporter.sendMail({
|
||||
from: meta.email!,
|
||||
from: this.meta.email!,
|
||||
to: to,
|
||||
subject: subject,
|
||||
text: text,
|
||||
@@ -167,8 +164,6 @@ export class EmailService {
|
||||
available: boolean;
|
||||
reason: null | 'used' | 'format' | 'disposable' | 'mx' | 'smtp' | 'banned' | 'network' | 'blacklist';
|
||||
}> {
|
||||
const meta = await this.metaService.fetch();
|
||||
|
||||
const exist = await this.userProfilesRepository.countBy({
|
||||
emailVerified: true,
|
||||
email: emailAddress,
|
||||
@@ -186,11 +181,11 @@ export class EmailService {
|
||||
reason?: string | null,
|
||||
} = { valid: true, reason: null };
|
||||
|
||||
if (meta.enableActiveEmailValidation) {
|
||||
if (meta.enableVerifymailApi && meta.verifymailAuthKey != null) {
|
||||
validated = await this.verifyMail(emailAddress, meta.verifymailAuthKey);
|
||||
} else if (meta.enableTruemailApi && meta.truemailInstance && meta.truemailAuthKey != null) {
|
||||
validated = await this.trueMail(meta.truemailInstance, emailAddress, meta.truemailAuthKey);
|
||||
if (this.meta.enableActiveEmailValidation) {
|
||||
if (this.meta.enableVerifymailApi && this.meta.verifymailAuthKey != null) {
|
||||
validated = await this.verifyMail(emailAddress, this.meta.verifymailAuthKey);
|
||||
} else if (this.meta.enableTruemailApi && this.meta.truemailInstance && this.meta.truemailAuthKey != null) {
|
||||
validated = await this.trueMail(this.meta.truemailInstance, emailAddress, this.meta.truemailAuthKey);
|
||||
} else {
|
||||
validated = await validateEmail({
|
||||
email: emailAddress,
|
||||
@@ -220,7 +215,7 @@ export class EmailService {
|
||||
}
|
||||
|
||||
const emailDomain: string = emailAddress.split('@')[1];
|
||||
const isBanned = this.utilityService.isBlockedHost(meta.bannedEmailDomains, emailDomain);
|
||||
const isBanned = this.utilityService.isBlockedHost(this.meta.bannedEmailDomains, emailDomain);
|
||||
|
||||
if (isBanned) {
|
||||
return {
|
||||
|
@@ -10,16 +10,18 @@ import type { MiUser } from '@/models/User.js';
|
||||
import { normalizeForSearch } from '@/misc/normalize-for-search.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import type { MiHashtag } from '@/models/Hashtag.js';
|
||||
import type { HashtagsRepository } from '@/models/_.js';
|
||||
import type { HashtagsRepository, MiMeta } from '@/models/_.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { FeaturedService } from '@/core/FeaturedService.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { UtilityService } from '@/core/UtilityService.js';
|
||||
|
||||
@Injectable()
|
||||
export class HashtagService {
|
||||
constructor(
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.redis)
|
||||
private redisClient: Redis.Redis, // TODO: 専用のRedisサーバーを設定できるようにする
|
||||
|
||||
@@ -29,7 +31,6 @@ export class HashtagService {
|
||||
private userEntityService: UserEntityService,
|
||||
private featuredService: FeaturedService,
|
||||
private idService: IdService,
|
||||
private metaService: MetaService,
|
||||
private utilityService: UtilityService,
|
||||
) {
|
||||
}
|
||||
@@ -160,10 +161,9 @@ export class HashtagService {
|
||||
|
||||
@bindThis
|
||||
public async updateHashtagsRanking(hashtag: string, userId: MiUser['id']): Promise<void> {
|
||||
const instance = await this.metaService.fetch();
|
||||
const hiddenTags = instance.hiddenTags.map(t => normalizeForSearch(t));
|
||||
const hiddenTags = this.meta.hiddenTags.map(t => normalizeForSearch(t));
|
||||
if (hiddenTags.includes(hashtag)) return;
|
||||
if (this.utilityService.isKeyWordIncluded(hashtag, instance.sensitiveWords)) return;
|
||||
if (this.utilityService.isKeyWordIncluded(hashtag, this.meta.sensitiveWords)) return;
|
||||
|
||||
// YYYYMMDDHHmm (10分間隔)
|
||||
const now = new Date();
|
||||
|
@@ -8,13 +8,12 @@ import * as mfm from 'mfm-js';
|
||||
import { In, DataSource, IsNull, LessThan } from 'typeorm';
|
||||
import * as Redis from 'ioredis';
|
||||
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
|
||||
import RE2 from 're2';
|
||||
import { extractMentions } from '@/misc/extract-mentions.js';
|
||||
import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mfm.js';
|
||||
import { extractHashtags } from '@/misc/extract-hashtags.js';
|
||||
import type { IMentionedRemoteUsers } from '@/models/Note.js';
|
||||
import { MiNote } from '@/models/Note.js';
|
||||
import type { ChannelFollowingsRepository, ChannelsRepository, FollowingsRepository, InstancesRepository, MiFollowing, MutingsRepository, NotesRepository, NoteThreadMutingsRepository, UserListMembershipsRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js';
|
||||
import type { ChannelFollowingsRepository, ChannelsRepository, FollowingsRepository, InstancesRepository, MiFollowing, MiMeta, MutingsRepository, NotesRepository, NoteThreadMutingsRepository, UserListMembershipsRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js';
|
||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||
import type { MiApp } from '@/models/App.js';
|
||||
import { concat } from '@/misc/prelude/array.js';
|
||||
@@ -23,11 +22,8 @@ import type { MiUser, MiLocalUser, MiRemoteUser } from '@/models/User.js';
|
||||
import type { IPoll } from '@/models/Poll.js';
|
||||
import { MiPoll } from '@/models/Poll.js';
|
||||
import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js';
|
||||
import { checkWordMute } from '@/misc/check-word-mute.js';
|
||||
import type { MiChannel } from '@/models/Channel.js';
|
||||
import { normalizeForSearch } from '@/misc/normalize-for-search.js';
|
||||
import { MemorySingleCache } from '@/misc/cache.js';
|
||||
import type { MiUserProfile } from '@/models/UserProfile.js';
|
||||
import { RelayService } from '@/core/RelayService.js';
|
||||
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
@@ -51,7 +47,6 @@ import { RemoteUserResolveService } from '@/core/RemoteUserResolveService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { DB_MAX_NOTE_TEXT_LENGTH } from '@/const.js';
|
||||
import { RoleService } from '@/core/RoleService.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { SearchService } from '@/core/SearchService.js';
|
||||
import { FeaturedService } from '@/core/FeaturedService.js';
|
||||
import { FanoutTimelineService } from '@/core/FanoutTimelineService.js';
|
||||
@@ -156,6 +151,9 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.db)
|
||||
private db: DataSource,
|
||||
|
||||
@@ -210,7 +208,6 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||
private apDeliverManagerService: ApDeliverManagerService,
|
||||
private apRendererService: ApRendererService,
|
||||
private roleService: RoleService,
|
||||
private metaService: MetaService,
|
||||
private searchService: SearchService,
|
||||
private notesChart: NotesChart,
|
||||
private perUserNotesChart: PerUserNotesChart,
|
||||
@@ -251,10 +248,8 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||
if (data.channel != null) data.visibleUsers = [];
|
||||
if (data.channel != null) data.localOnly = true;
|
||||
|
||||
const meta = await this.metaService.fetch();
|
||||
|
||||
if (data.visibility === 'public' && data.channel == null) {
|
||||
const sensitiveWords = meta.sensitiveWords;
|
||||
const sensitiveWords = this.meta.sensitiveWords;
|
||||
if (this.utilityService.isKeyWordIncluded(data.cw ?? data.text ?? '', sensitiveWords)) {
|
||||
data.visibility = 'home';
|
||||
} else if ((await this.roleService.getUserPolicies(user.id)).canPublicNote === false) {
|
||||
@@ -262,17 +257,17 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||
}
|
||||
}
|
||||
|
||||
const hasProhibitedWords = await this.checkProhibitedWordsContain({
|
||||
const hasProhibitedWords = this.checkProhibitedWordsContain({
|
||||
cw: data.cw,
|
||||
text: data.text,
|
||||
pollChoices: data.poll?.choices,
|
||||
}, meta.prohibitedWords);
|
||||
}, this.meta.prohibitedWords);
|
||||
|
||||
if (hasProhibitedWords) {
|
||||
throw new IdentifiableError('689ee33f-f97c-479a-ac49-1b9f8140af99', 'Note contains prohibited words');
|
||||
}
|
||||
|
||||
const inSilencedInstance = this.utilityService.isSilencedHost(meta.silencedHosts, user.host);
|
||||
const inSilencedInstance = this.utilityService.isSilencedHost(this.meta.silencedHosts, user.host);
|
||||
|
||||
if (data.visibility === 'public' && inSilencedInstance && user.host !== null) {
|
||||
data.visibility = 'home';
|
||||
@@ -365,7 +360,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||
}
|
||||
|
||||
// if the host is media-silenced, custom emojis are not allowed
|
||||
if (this.utilityService.isMediaSilencedHost(meta.mediaSilencedHosts, user.host)) emojis = [];
|
||||
if (this.utilityService.isMediaSilencedHost(this.meta.mediaSilencedHosts, user.host)) emojis = [];
|
||||
|
||||
tags = tags.filter(tag => Array.from(tag).length <= 128).splice(0, 32);
|
||||
|
||||
@@ -506,10 +501,8 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||
host: MiUser['host'];
|
||||
isBot: MiUser['isBot'];
|
||||
}, data: Option, silent: boolean, tags: string[], mentionedUsers: MinimumUser[]) {
|
||||
const meta = await this.metaService.fetch();
|
||||
|
||||
this.notesChart.update(note, true);
|
||||
if (note.visibility !== 'specified' && (meta.enableChartsForRemoteUser || (user.host == null))) {
|
||||
if (note.visibility !== 'specified' && (this.meta.enableChartsForRemoteUser || (user.host == null))) {
|
||||
this.perUserNotesChart.update(user, note, true);
|
||||
}
|
||||
|
||||
@@ -517,7 +510,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||
if (this.userEntityService.isRemoteUser(user)) {
|
||||
this.federatedInstanceService.fetch(user.host).then(async i => {
|
||||
this.instancesRepository.increment({ id: i.id }, 'notesCount', 1);
|
||||
if ((await this.metaService.fetch()).enableChartsForFederatedInstances) {
|
||||
if (this.meta.enableChartsForFederatedInstances) {
|
||||
this.instanceChart.updateNote(i.host, note, true);
|
||||
}
|
||||
});
|
||||
@@ -853,15 +846,14 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||
|
||||
@bindThis
|
||||
private async pushToTl(note: MiNote, user: { id: MiUser['id']; host: MiUser['host']; }) {
|
||||
const meta = await this.metaService.fetch();
|
||||
if (!meta.enableFanoutTimeline) return;
|
||||
if (!this.meta.enableFanoutTimeline) return;
|
||||
|
||||
const r = this.redisForTimelines.pipeline();
|
||||
|
||||
if (note.channelId) {
|
||||
this.fanoutTimelineService.push(`channelTimeline:${note.channelId}`, note.id, this.config.perChannelMaxNoteCacheCount, r);
|
||||
|
||||
this.fanoutTimelineService.push(`userTimelineWithChannel:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r);
|
||||
this.fanoutTimelineService.push(`userTimelineWithChannel:${user.id}`, note.id, note.userHost == null ? this.meta.perLocalUserUserTimelineCacheMax : this.meta.perRemoteUserUserTimelineCacheMax, r);
|
||||
|
||||
const channelFollowings = await this.channelFollowingsRepository.find({
|
||||
where: {
|
||||
@@ -871,9 +863,9 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||
});
|
||||
|
||||
for (const channelFollowing of channelFollowings) {
|
||||
this.fanoutTimelineService.push(`homeTimeline:${channelFollowing.followerId}`, note.id, meta.perUserHomeTimelineCacheMax, r);
|
||||
this.fanoutTimelineService.push(`homeTimeline:${channelFollowing.followerId}`, note.id, this.meta.perUserHomeTimelineCacheMax, r);
|
||||
if (note.fileIds.length > 0) {
|
||||
this.fanoutTimelineService.push(`homeTimelineWithFiles:${channelFollowing.followerId}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r);
|
||||
this.fanoutTimelineService.push(`homeTimelineWithFiles:${channelFollowing.followerId}`, note.id, this.meta.perUserHomeTimelineCacheMax / 2, r);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -911,9 +903,9 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||
if (!following.withReplies) continue;
|
||||
}
|
||||
|
||||
this.fanoutTimelineService.push(`homeTimeline:${following.followerId}`, note.id, meta.perUserHomeTimelineCacheMax, r);
|
||||
this.fanoutTimelineService.push(`homeTimeline:${following.followerId}`, note.id, this.meta.perUserHomeTimelineCacheMax, r);
|
||||
if (note.fileIds.length > 0) {
|
||||
this.fanoutTimelineService.push(`homeTimelineWithFiles:${following.followerId}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r);
|
||||
this.fanoutTimelineService.push(`homeTimelineWithFiles:${following.followerId}`, note.id, this.meta.perUserHomeTimelineCacheMax / 2, r);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -930,25 +922,25 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||
if (!userListMembership.withReplies) continue;
|
||||
}
|
||||
|
||||
this.fanoutTimelineService.push(`userListTimeline:${userListMembership.userListId}`, note.id, meta.perUserListTimelineCacheMax, r);
|
||||
this.fanoutTimelineService.push(`userListTimeline:${userListMembership.userListId}`, note.id, this.meta.perUserListTimelineCacheMax, r);
|
||||
if (note.fileIds.length > 0) {
|
||||
this.fanoutTimelineService.push(`userListTimelineWithFiles:${userListMembership.userListId}`, note.id, meta.perUserListTimelineCacheMax / 2, r);
|
||||
this.fanoutTimelineService.push(`userListTimelineWithFiles:${userListMembership.userListId}`, note.id, this.meta.perUserListTimelineCacheMax / 2, r);
|
||||
}
|
||||
}
|
||||
|
||||
// 自分自身のHTL
|
||||
if (note.userHost == null) {
|
||||
if (note.visibility !== 'specified' || !note.visibleUserIds.some(v => v === user.id)) {
|
||||
this.fanoutTimelineService.push(`homeTimeline:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax, r);
|
||||
this.fanoutTimelineService.push(`homeTimeline:${user.id}`, note.id, this.meta.perUserHomeTimelineCacheMax, r);
|
||||
if (note.fileIds.length > 0) {
|
||||
this.fanoutTimelineService.push(`homeTimelineWithFiles:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r);
|
||||
this.fanoutTimelineService.push(`homeTimelineWithFiles:${user.id}`, note.id, this.meta.perUserHomeTimelineCacheMax / 2, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 自分自身以外への返信
|
||||
if (isReply(note)) {
|
||||
this.fanoutTimelineService.push(`userTimelineWithReplies:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r);
|
||||
this.fanoutTimelineService.push(`userTimelineWithReplies:${user.id}`, note.id, note.userHost == null ? this.meta.perLocalUserUserTimelineCacheMax : this.meta.perRemoteUserUserTimelineCacheMax, r);
|
||||
|
||||
if (note.visibility === 'public' && note.userHost == null) {
|
||||
this.fanoutTimelineService.push('localTimelineWithReplies', note.id, 300, r);
|
||||
@@ -957,9 +949,9 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.fanoutTimelineService.push(`userTimeline:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r);
|
||||
this.fanoutTimelineService.push(`userTimeline:${user.id}`, note.id, note.userHost == null ? this.meta.perLocalUserUserTimelineCacheMax : this.meta.perRemoteUserUserTimelineCacheMax, r);
|
||||
if (note.fileIds.length > 0) {
|
||||
this.fanoutTimelineService.push(`userTimelineWithFiles:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax / 2 : meta.perRemoteUserUserTimelineCacheMax / 2, r);
|
||||
this.fanoutTimelineService.push(`userTimelineWithFiles:${user.id}`, note.id, note.userHost == null ? this.meta.perLocalUserUserTimelineCacheMax / 2 : this.meta.perRemoteUserUserTimelineCacheMax / 2, r);
|
||||
}
|
||||
|
||||
if (note.visibility === 'public' && note.userHost == null) {
|
||||
@@ -1018,9 +1010,9 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||
}
|
||||
}
|
||||
|
||||
public async checkProhibitedWordsContain(content: Parameters<UtilityService['concatNoteContentsForKeyWordCheck']>[0], prohibitedWords?: string[]) {
|
||||
public checkProhibitedWordsContain(content: Parameters<UtilityService['concatNoteContentsForKeyWordCheck']>[0], prohibitedWords?: string[]) {
|
||||
if (prohibitedWords == null) {
|
||||
prohibitedWords = (await this.metaService.fetch()).prohibitedWords;
|
||||
prohibitedWords = this.meta.prohibitedWords;
|
||||
}
|
||||
|
||||
if (
|
||||
|
@@ -7,7 +7,7 @@ import { Brackets, In } from 'typeorm';
|
||||
import { Injectable, Inject } from '@nestjs/common';
|
||||
import type { MiUser, MiLocalUser, MiRemoteUser } from '@/models/User.js';
|
||||
import type { MiNote, IMentionedRemoteUsers } from '@/models/Note.js';
|
||||
import type { InstancesRepository, NotesRepository, UsersRepository } from '@/models/_.js';
|
||||
import type { InstancesRepository, MiMeta, NotesRepository, UsersRepository } from '@/models/_.js';
|
||||
import { RelayService } from '@/core/RelayService.js';
|
||||
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
@@ -19,9 +19,7 @@ import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
||||
import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { SearchService } from '@/core/SearchService.js';
|
||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||
import { isQuote, isRenote } from '@/misc/is-renote.js';
|
||||
@@ -32,6 +30,9 @@ export class NoteDeleteService {
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.usersRepository)
|
||||
private usersRepository: UsersRepository,
|
||||
|
||||
@@ -42,13 +43,11 @@ export class NoteDeleteService {
|
||||
private instancesRepository: InstancesRepository,
|
||||
|
||||
private userEntityService: UserEntityService,
|
||||
private noteEntityService: NoteEntityService,
|
||||
private globalEventService: GlobalEventService,
|
||||
private relayService: RelayService,
|
||||
private federatedInstanceService: FederatedInstanceService,
|
||||
private apRendererService: ApRendererService,
|
||||
private apDeliverManagerService: ApDeliverManagerService,
|
||||
private metaService: MetaService,
|
||||
private searchService: SearchService,
|
||||
private moderationLogService: ModerationLogService,
|
||||
private notesChart: NotesChart,
|
||||
@@ -102,17 +101,15 @@ export class NoteDeleteService {
|
||||
}
|
||||
//#endregion
|
||||
|
||||
const meta = await this.metaService.fetch();
|
||||
|
||||
this.notesChart.update(note, false);
|
||||
if (meta.enableChartsForRemoteUser || (user.host == null)) {
|
||||
if (this.meta.enableChartsForRemoteUser || (user.host == null)) {
|
||||
this.perUserNotesChart.update(user, note, false);
|
||||
}
|
||||
|
||||
if (this.userEntityService.isRemoteUser(user)) {
|
||||
this.federatedInstanceService.fetch(user.host).then(async i => {
|
||||
this.instancesRepository.decrement({ id: i.id }, 'notesCount', 1);
|
||||
if ((await this.metaService.fetch()).enableChartsForFederatedInstances) {
|
||||
if (this.meta.enableChartsForFederatedInstances) {
|
||||
this.instanceChart.updateNote(i.host, note, false);
|
||||
}
|
||||
});
|
||||
|
@@ -4,26 +4,25 @@
|
||||
*/
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import type { UsersRepository } from '@/models/_.js';
|
||||
import type { MiMeta, UsersRepository } from '@/models/_.js';
|
||||
import type { MiLocalUser } from '@/models/User.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
|
||||
@Injectable()
|
||||
export class ProxyAccountService {
|
||||
constructor(
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.usersRepository)
|
||||
private usersRepository: UsersRepository,
|
||||
|
||||
private metaService: MetaService,
|
||||
) {
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async fetch(): Promise<MiLocalUser | null> {
|
||||
const meta = await this.metaService.fetch();
|
||||
if (meta.proxyAccountId == null) return null;
|
||||
return await this.usersRepository.findOneByOrFail({ id: meta.proxyAccountId }) as MiLocalUser;
|
||||
if (this.meta.proxyAccountId == null) return null;
|
||||
return await this.usersRepository.findOneByOrFail({ id: this.meta.proxyAccountId }) as MiLocalUser;
|
||||
}
|
||||
}
|
||||
|
@@ -10,8 +10,7 @@ import { DI } from '@/di-symbols.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import type { Packed } from '@/misc/json-schema.js';
|
||||
import { getNoteSummary } from '@/misc/get-note-summary.js';
|
||||
import type { MiSwSubscription, SwSubscriptionsRepository } from '@/models/_.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import type { MiMeta, MiSwSubscription, SwSubscriptionsRepository } from '@/models/_.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { RedisKVCache } from '@/misc/cache.js';
|
||||
|
||||
@@ -54,13 +53,14 @@ export class PushNotificationService implements OnApplicationShutdown {
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.redis)
|
||||
private redisClient: Redis.Redis,
|
||||
|
||||
@Inject(DI.swSubscriptionsRepository)
|
||||
private swSubscriptionsRepository: SwSubscriptionsRepository,
|
||||
|
||||
private metaService: MetaService,
|
||||
) {
|
||||
this.subscriptionsCache = new RedisKVCache<MiSwSubscription[]>(this.redisClient, 'userSwSubscriptions', {
|
||||
lifetime: 1000 * 60 * 60 * 1, // 1h
|
||||
@@ -73,14 +73,12 @@ export class PushNotificationService implements OnApplicationShutdown {
|
||||
|
||||
@bindThis
|
||||
public async pushNotification<T extends keyof PushNotificationsTypes>(userId: string, type: T, body: PushNotificationsTypes[T]) {
|
||||
const meta = await this.metaService.fetch();
|
||||
|
||||
if (!meta.enableServiceWorker || meta.swPublicKey == null || meta.swPrivateKey == null) return;
|
||||
if (!this.meta.enableServiceWorker || this.meta.swPublicKey == null || this.meta.swPrivateKey == null) return;
|
||||
|
||||
// アプリケーションの連絡先と、サーバーサイドの鍵ペアの情報を登録
|
||||
push.setVapidDetails(this.config.url,
|
||||
meta.swPublicKey,
|
||||
meta.swPrivateKey);
|
||||
this.meta.swPublicKey,
|
||||
this.meta.swPrivateKey);
|
||||
|
||||
const subscriptions = await this.subscriptionsCache.fetch(userId);
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { EmojisRepository, NoteReactionsRepository, UsersRepository, NotesRepository } from '@/models/_.js';
|
||||
import type { EmojisRepository, NoteReactionsRepository, UsersRepository, NotesRepository, MiMeta } from '@/models/_.js';
|
||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||
import type { MiRemoteUser, MiUser } from '@/models/User.js';
|
||||
import type { MiNote } from '@/models/Note.js';
|
||||
@@ -20,7 +20,6 @@ import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerServ
|
||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { UtilityService } from '@/core/UtilityService.js';
|
||||
import { UserBlockingService } from '@/core/UserBlockingService.js';
|
||||
@@ -71,6 +70,9 @@ const decodeCustomEmojiRegexp = /^:([\w+-]+)(?:@([\w.-]+))?:$/;
|
||||
@Injectable()
|
||||
export class ReactionService {
|
||||
constructor(
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.usersRepository)
|
||||
private usersRepository: UsersRepository,
|
||||
|
||||
@@ -84,7 +86,6 @@ export class ReactionService {
|
||||
private emojisRepository: EmojisRepository,
|
||||
|
||||
private utilityService: UtilityService,
|
||||
private metaService: MetaService,
|
||||
private customEmojiService: CustomEmojiService,
|
||||
private roleService: RoleService,
|
||||
private userEntityService: UserEntityService,
|
||||
@@ -103,8 +104,6 @@ export class ReactionService {
|
||||
|
||||
@bindThis
|
||||
public async create(user: { id: MiUser['id']; host: MiUser['host']; isBot: MiUser['isBot'] }, note: MiNote, _reaction?: string | null) {
|
||||
const meta = await this.metaService.fetch();
|
||||
|
||||
// Check blocking
|
||||
if (note.userId !== user.id) {
|
||||
const blocked = await this.userBlockingService.checkBlocked(note.userId, user.id);
|
||||
@@ -150,7 +149,7 @@ export class ReactionService {
|
||||
}
|
||||
|
||||
// for media silenced host, custom emoji reactions are not allowed
|
||||
if (reacterHost != null && this.utilityService.isMediaSilencedHost(meta.mediaSilencedHosts, reacterHost)) {
|
||||
if (reacterHost != null && this.utilityService.isMediaSilencedHost(this.meta.mediaSilencedHosts, reacterHost)) {
|
||||
reaction = FALLBACK;
|
||||
}
|
||||
} else {
|
||||
@@ -195,7 +194,7 @@ export class ReactionService {
|
||||
}
|
||||
|
||||
// Increment reactions count
|
||||
if (meta.enableReactionsBuffering) {
|
||||
if (this.meta.enableReactionsBuffering) {
|
||||
await this.reactionsBufferingService.create(note.id, user.id, reaction, note.reactionAndUserPairCache);
|
||||
} else {
|
||||
const sql = `jsonb_set("reactions", '{${reaction}}', (COALESCE("reactions"->>'${reaction}', '0')::int + 1)::text::jsonb)`;
|
||||
@@ -228,7 +227,7 @@ export class ReactionService {
|
||||
}
|
||||
}
|
||||
|
||||
if (meta.enableChartsForRemoteUser || (user.host == null)) {
|
||||
if (this.meta.enableChartsForRemoteUser || (user.host == null)) {
|
||||
this.perUserReactionsChart.update(user, note);
|
||||
}
|
||||
|
||||
@@ -305,10 +304,8 @@ export class ReactionService {
|
||||
throw new IdentifiableError('60527ec9-b4cb-4a88-a6bd-32d3ad26817d', 'not reacted');
|
||||
}
|
||||
|
||||
const meta = await this.metaService.fetch();
|
||||
|
||||
// Decrement reactions count
|
||||
if (meta.enableReactionsBuffering) {
|
||||
if (this.meta.enableReactionsBuffering) {
|
||||
await this.reactionsBufferingService.delete(note.id, user.id, exist.reaction);
|
||||
} else {
|
||||
const sql = `jsonb_set("reactions", '{${exist.reaction}}', (COALESCE("reactions"->>'${exist.reaction}', '0')::int - 1)::text::jsonb)`;
|
||||
|
@@ -8,6 +8,7 @@ import * as Redis from 'ioredis';
|
||||
import { In } from 'typeorm';
|
||||
import { ModuleRef } from '@nestjs/core';
|
||||
import type {
|
||||
MiMeta,
|
||||
MiRole,
|
||||
MiRoleAssignment,
|
||||
RoleAssignmentsRepository,
|
||||
@@ -18,7 +19,6 @@ import { MemoryKVCache, MemorySingleCache } from '@/misc/cache.js';
|
||||
import type { MiUser } from '@/models/User.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { CacheService } from '@/core/CacheService.js';
|
||||
import type { RoleCondFormulaValue } from '@/models/Role.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
@@ -111,8 +111,8 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
|
||||
constructor(
|
||||
private moduleRef: ModuleRef,
|
||||
|
||||
@Inject(DI.redis)
|
||||
private redisClient: Redis.Redis,
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.redisForTimelines)
|
||||
private redisForTimelines: Redis.Redis,
|
||||
@@ -129,7 +129,6 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
|
||||
@Inject(DI.roleAssignmentsRepository)
|
||||
private roleAssignmentsRepository: RoleAssignmentsRepository,
|
||||
|
||||
private metaService: MetaService,
|
||||
private cacheService: CacheService,
|
||||
private userEntityService: UserEntityService,
|
||||
private globalEventService: GlobalEventService,
|
||||
@@ -349,8 +348,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
|
||||
|
||||
@bindThis
|
||||
public async getUserPolicies(userId: MiUser['id'] | null): Promise<RolePolicies> {
|
||||
const meta = await this.metaService.fetch();
|
||||
const basePolicies = { ...DEFAULT_POLICIES, ...meta.policies };
|
||||
const basePolicies = { ...DEFAULT_POLICIES, ...this.meta.policies };
|
||||
|
||||
if (userId == null) return basePolicies;
|
||||
|
||||
|
@@ -8,7 +8,7 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||
import bcrypt from 'bcryptjs';
|
||||
import { DataSource, IsNull } from 'typeorm';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { UsedUsernamesRepository, UsersRepository } from '@/models/_.js';
|
||||
import type { MiMeta, UsedUsernamesRepository, UsersRepository } from '@/models/_.js';
|
||||
import { MiUser } from '@/models/User.js';
|
||||
import { MiUserProfile } from '@/models/UserProfile.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
@@ -20,7 +20,6 @@ import { InstanceActorService } from '@/core/InstanceActorService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import UsersChart from '@/core/chart/charts/users.js';
|
||||
import { UtilityService } from '@/core/UtilityService.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { UserService } from '@/core/UserService.js';
|
||||
|
||||
@Injectable()
|
||||
@@ -29,6 +28,9 @@ export class SignupService {
|
||||
@Inject(DI.db)
|
||||
private db: DataSource,
|
||||
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.usersRepository)
|
||||
private usersRepository: UsersRepository,
|
||||
|
||||
@@ -39,7 +41,6 @@ export class SignupService {
|
||||
private userService: UserService,
|
||||
private userEntityService: UserEntityService,
|
||||
private idService: IdService,
|
||||
private metaService: MetaService,
|
||||
private instanceActorService: InstanceActorService,
|
||||
private usersChart: UsersChart,
|
||||
) {
|
||||
@@ -88,8 +89,7 @@ export class SignupService {
|
||||
const isTheFirstUser = !await this.instanceActorService.realLocalUsersPresent();
|
||||
|
||||
if (!opts.ignorePreservedUsernames && !isTheFirstUser) {
|
||||
const instance = await this.metaService.fetch(true);
|
||||
const isPreserved = instance.preservedUsernames.map(x => x.toLowerCase()).includes(username.toLowerCase());
|
||||
const isPreserved = this.meta.preservedUsernames.map(x => x.toLowerCase()).includes(username.toLowerCase());
|
||||
if (isPreserved) {
|
||||
throw new Error('USED_USERNAME');
|
||||
}
|
||||
|
@@ -13,23 +13,20 @@ import PerUserFollowingChart from '@/core/chart/charts/per-user-following.js';
|
||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js';
|
||||
import type { Packed } from '@/misc/json-schema.js';
|
||||
import InstanceChart from '@/core/chart/charts/instance.js';
|
||||
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
|
||||
import { UserWebhookService } from '@/core/UserWebhookService.js';
|
||||
import { NotificationService } from '@/core/NotificationService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { FollowingsRepository, FollowRequestsRepository, InstancesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js';
|
||||
import type { FollowingsRepository, FollowRequestsRepository, InstancesRepository, MiMeta, UserProfilesRepository, UsersRepository } from '@/models/_.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { UserBlockingService } from '@/core/UserBlockingService.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { CacheService } from '@/core/CacheService.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import { AccountMoveService } from '@/core/AccountMoveService.js';
|
||||
import { UtilityService } from '@/core/UtilityService.js';
|
||||
import { FanoutTimelineService } from '@/core/FanoutTimelineService.js';
|
||||
import type { ThinUser } from '@/queue/types.js';
|
||||
import Logger from '../logger.js';
|
||||
|
||||
@@ -58,6 +55,9 @@ export class UserFollowingService implements OnModuleInit {
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.usersRepository)
|
||||
private usersRepository: UsersRepository,
|
||||
|
||||
@@ -79,13 +79,11 @@ export class UserFollowingService implements OnModuleInit {
|
||||
private idService: IdService,
|
||||
private queueService: QueueService,
|
||||
private globalEventService: GlobalEventService,
|
||||
private metaService: MetaService,
|
||||
private notificationService: NotificationService,
|
||||
private federatedInstanceService: FederatedInstanceService,
|
||||
private webhookService: UserWebhookService,
|
||||
private apRendererService: ApRendererService,
|
||||
private accountMoveService: AccountMoveService,
|
||||
private fanoutTimelineService: FanoutTimelineService,
|
||||
private perUserFollowingChart: PerUserFollowingChart,
|
||||
private instanceChart: InstanceChart,
|
||||
) {
|
||||
@@ -172,7 +170,7 @@ export class UserFollowingService implements OnModuleInit {
|
||||
followee.isLocked ||
|
||||
(followeeProfile.carefulBot && follower.isBot) ||
|
||||
(this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee) && process.env.FORCE_FOLLOW_REMOTE_USER_FOR_TESTING !== 'true') ||
|
||||
(this.userEntityService.isLocalUser(followee) && this.userEntityService.isRemoteUser(follower) && this.utilityService.isSilencedHost((await this.metaService.fetch()).silencedHosts, follower.host))
|
||||
(this.userEntityService.isLocalUser(followee) && this.userEntityService.isRemoteUser(follower) && this.utilityService.isSilencedHost(this.meta.silencedHosts, follower.host))
|
||||
) {
|
||||
let autoAccept = false;
|
||||
|
||||
@@ -307,14 +305,14 @@ export class UserFollowingService implements OnModuleInit {
|
||||
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
|
||||
this.federatedInstanceService.fetch(follower.host).then(async i => {
|
||||
this.instancesRepository.increment({ id: i.id }, 'followingCount', 1);
|
||||
if ((await this.metaService.fetch()).enableChartsForFederatedInstances) {
|
||||
if (this.meta.enableChartsForFederatedInstances) {
|
||||
this.instanceChart.updateFollowing(i.host, true);
|
||||
}
|
||||
});
|
||||
} else if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) {
|
||||
this.federatedInstanceService.fetch(followee.host).then(async i => {
|
||||
this.instancesRepository.increment({ id: i.id }, 'followersCount', 1);
|
||||
if ((await this.metaService.fetch()).enableChartsForFederatedInstances) {
|
||||
if (this.meta.enableChartsForFederatedInstances) {
|
||||
this.instanceChart.updateFollowers(i.host, true);
|
||||
}
|
||||
});
|
||||
@@ -439,14 +437,14 @@ export class UserFollowingService implements OnModuleInit {
|
||||
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
|
||||
this.federatedInstanceService.fetch(follower.host).then(async i => {
|
||||
this.instancesRepository.decrement({ id: i.id }, 'followingCount', 1);
|
||||
if ((await this.metaService.fetch()).enableChartsForFederatedInstances) {
|
||||
if (this.meta.enableChartsForFederatedInstances) {
|
||||
this.instanceChart.updateFollowing(i.host, false);
|
||||
}
|
||||
});
|
||||
} else if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) {
|
||||
this.federatedInstanceService.fetch(followee.host).then(async i => {
|
||||
this.instancesRepository.decrement({ id: i.id }, 'followersCount', 1);
|
||||
if ((await this.metaService.fetch()).enableChartsForFederatedInstances) {
|
||||
if (this.meta.enableChartsForFederatedInstances) {
|
||||
this.instanceChart.updateFollowers(i.host, false);
|
||||
}
|
||||
});
|
||||
|
@@ -12,10 +12,9 @@ import {
|
||||
} from '@simplewebauthn/server';
|
||||
import { AttestationFormat, isoCBOR, isoUint8Array } from '@simplewebauthn/server/helpers';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { UserSecurityKeysRepository } from '@/models/_.js';
|
||||
import type { MiMeta, UserSecurityKeysRepository } from '@/models/_.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { MiUser } from '@/models/_.js';
|
||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||
import type {
|
||||
@@ -23,7 +22,6 @@ import type {
|
||||
AuthenticatorTransportFuture,
|
||||
CredentialDeviceType,
|
||||
PublicKeyCredentialCreationOptionsJSON,
|
||||
PublicKeyCredentialDescriptorFuture,
|
||||
PublicKeyCredentialRequestOptionsJSON,
|
||||
RegistrationResponseJSON,
|
||||
} from '@simplewebauthn/types';
|
||||
@@ -31,33 +29,33 @@ import type {
|
||||
@Injectable()
|
||||
export class WebAuthnService {
|
||||
constructor(
|
||||
@Inject(DI.redis)
|
||||
private redisClient: Redis.Redis,
|
||||
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.redis)
|
||||
private redisClient: Redis.Redis,
|
||||
|
||||
@Inject(DI.userSecurityKeysRepository)
|
||||
private userSecurityKeysRepository: UserSecurityKeysRepository,
|
||||
|
||||
private metaService: MetaService,
|
||||
) {
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async getRelyingParty(): Promise<{ origin: string; rpId: string; rpName: string; rpIcon?: string; }> {
|
||||
const instance = await this.metaService.fetch();
|
||||
public getRelyingParty(): { origin: string; rpId: string; rpName: string; rpIcon?: string; } {
|
||||
return {
|
||||
origin: this.config.url,
|
||||
rpId: this.config.hostname,
|
||||
rpName: instance.name ?? this.config.host,
|
||||
rpIcon: instance.iconUrl ?? undefined,
|
||||
rpName: this.meta.name ?? this.config.host,
|
||||
rpIcon: this.meta.iconUrl ?? undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async initiateRegistration(userId: MiUser['id'], userName: string, userDisplayName?: string): Promise<PublicKeyCredentialCreationOptionsJSON> {
|
||||
const relyingParty = await this.getRelyingParty();
|
||||
const relyingParty = this.getRelyingParty();
|
||||
const keys = await this.userSecurityKeysRepository.findBy({
|
||||
userId: userId,
|
||||
});
|
||||
@@ -104,7 +102,7 @@ export class WebAuthnService {
|
||||
|
||||
await this.redisClient.del(`webauthn:challenge:${userId}`);
|
||||
|
||||
const relyingParty = await this.getRelyingParty();
|
||||
const relyingParty = this.getRelyingParty();
|
||||
|
||||
let verification;
|
||||
try {
|
||||
@@ -143,7 +141,7 @@ export class WebAuthnService {
|
||||
|
||||
@bindThis
|
||||
public async initiateAuthentication(userId: MiUser['id']): Promise<PublicKeyCredentialRequestOptionsJSON> {
|
||||
const relyingParty = await this.getRelyingParty();
|
||||
const relyingParty = this.getRelyingParty();
|
||||
const keys = await this.userSecurityKeysRepository.findBy({
|
||||
userId: userId,
|
||||
});
|
||||
@@ -209,7 +207,7 @@ export class WebAuthnService {
|
||||
}
|
||||
}
|
||||
|
||||
const relyingParty = await this.getRelyingParty();
|
||||
const relyingParty = this.getRelyingParty();
|
||||
|
||||
let verification;
|
||||
try {
|
||||
|
@@ -17,14 +17,13 @@ import { NoteCreateService } from '@/core/NoteCreateService.js';
|
||||
import { concat, toArray, toSingle, unique } from '@/misc/prelude/array.js';
|
||||
import { AppLockService } from '@/core/AppLockService.js';
|
||||
import type Logger from '@/logger.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import { StatusError } from '@/misc/status-error.js';
|
||||
import { UtilityService } from '@/core/UtilityService.js';
|
||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { QueueService } from '@/core/QueueService.js';
|
||||
import type { UsersRepository, NotesRepository, FollowingsRepository, AbuseUserReportsRepository, FollowRequestsRepository } from '@/models/_.js';
|
||||
import type { UsersRepository, NotesRepository, FollowingsRepository, AbuseUserReportsRepository, FollowRequestsRepository, MiMeta } from '@/models/_.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import type { MiRemoteUser } from '@/models/User.js';
|
||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||
@@ -48,6 +47,9 @@ export class ApInboxService {
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.usersRepository)
|
||||
private usersRepository: UsersRepository,
|
||||
|
||||
@@ -64,7 +66,6 @@ export class ApInboxService {
|
||||
private noteEntityService: NoteEntityService,
|
||||
private utilityService: UtilityService,
|
||||
private idService: IdService,
|
||||
private metaService: MetaService,
|
||||
private abuseReportService: AbuseReportService,
|
||||
private userFollowingService: UserFollowingService,
|
||||
private apAudienceService: ApAudienceService,
|
||||
@@ -290,8 +291,7 @@ export class ApInboxService {
|
||||
}
|
||||
|
||||
// アナウンス先をブロックしてたら中断
|
||||
const meta = await this.metaService.fetch();
|
||||
if (this.utilityService.isBlockedHost(meta.blockedHosts, this.utilityService.extractDbHost(uri))) return;
|
||||
if (this.utilityService.isBlockedHost(this.meta.blockedHosts, this.utilityService.extractDbHost(uri))) return;
|
||||
|
||||
const unlock = await this.appLockService.getApLock(uri);
|
||||
|
||||
|
@@ -7,9 +7,8 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||
import { IsNull, Not } from 'typeorm';
|
||||
import type { MiLocalUser, MiRemoteUser } from '@/models/User.js';
|
||||
import { InstanceActorService } from '@/core/InstanceActorService.js';
|
||||
import type { NotesRepository, PollsRepository, NoteReactionsRepository, UsersRepository, FollowRequestsRepository } from '@/models/_.js';
|
||||
import type { NotesRepository, PollsRepository, NoteReactionsRepository, UsersRepository, FollowRequestsRepository, MiMeta } from '@/models/_.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { UtilityService } from '@/core/UtilityService.js';
|
||||
@@ -29,6 +28,7 @@ export class Resolver {
|
||||
|
||||
constructor(
|
||||
private config: Config,
|
||||
private meta: MiMeta,
|
||||
private usersRepository: UsersRepository,
|
||||
private notesRepository: NotesRepository,
|
||||
private pollsRepository: PollsRepository,
|
||||
@@ -36,7 +36,6 @@ export class Resolver {
|
||||
private followRequestsRepository: FollowRequestsRepository,
|
||||
private utilityService: UtilityService,
|
||||
private instanceActorService: InstanceActorService,
|
||||
private metaService: MetaService,
|
||||
private apRequestService: ApRequestService,
|
||||
private httpRequestService: HttpRequestService,
|
||||
private apRendererService: ApRendererService,
|
||||
@@ -94,8 +93,7 @@ export class Resolver {
|
||||
return await this.resolveLocal(value);
|
||||
}
|
||||
|
||||
const meta = await this.metaService.fetch();
|
||||
if (this.utilityService.isBlockedHost(meta.blockedHosts, host)) {
|
||||
if (this.utilityService.isBlockedHost(this.meta.blockedHosts, host)) {
|
||||
throw new Error('Instance is blocked');
|
||||
}
|
||||
|
||||
@@ -178,6 +176,9 @@ export class ApResolverService {
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.usersRepository)
|
||||
private usersRepository: UsersRepository,
|
||||
|
||||
@@ -195,7 +196,6 @@ export class ApResolverService {
|
||||
|
||||
private utilityService: UtilityService,
|
||||
private instanceActorService: InstanceActorService,
|
||||
private metaService: MetaService,
|
||||
private apRequestService: ApRequestService,
|
||||
private httpRequestService: HttpRequestService,
|
||||
private apRendererService: ApRendererService,
|
||||
@@ -208,6 +208,7 @@ export class ApResolverService {
|
||||
public createResolver(): Resolver {
|
||||
return new Resolver(
|
||||
this.config,
|
||||
this.meta,
|
||||
this.usersRepository,
|
||||
this.notesRepository,
|
||||
this.pollsRepository,
|
||||
@@ -215,7 +216,6 @@ export class ApResolverService {
|
||||
this.followRequestsRepository,
|
||||
this.utilityService,
|
||||
this.instanceActorService,
|
||||
this.metaService,
|
||||
this.apRequestService,
|
||||
this.httpRequestService,
|
||||
this.apRendererService,
|
||||
|
@@ -5,10 +5,9 @@
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { DriveFilesRepository } from '@/models/_.js';
|
||||
import type { DriveFilesRepository, MiMeta } from '@/models/_.js';
|
||||
import type { MiRemoteUser } from '@/models/User.js';
|
||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { truncate } from '@/misc/truncate.js';
|
||||
import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/const.js';
|
||||
import { DriveService } from '@/core/DriveService.js';
|
||||
@@ -24,10 +23,12 @@ export class ApImageService {
|
||||
private logger: Logger;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.driveFilesRepository)
|
||||
private driveFilesRepository: DriveFilesRepository,
|
||||
|
||||
private metaService: MetaService,
|
||||
private apResolverService: ApResolverService,
|
||||
private driveService: DriveService,
|
||||
private apLoggerService: ApLoggerService,
|
||||
@@ -63,12 +64,10 @@ export class ApImageService {
|
||||
|
||||
this.logger.info(`Creating the Image: ${image.url}`);
|
||||
|
||||
const instance = await this.metaService.fetch();
|
||||
|
||||
// Cache if remote file cache is on AND either
|
||||
// 1. remote sensitive file is also on
|
||||
// 2. or the image is not sensitive
|
||||
const shouldBeCached = instance.cacheRemoteFiles && (instance.cacheRemoteSensitiveFiles || !image.sensitive);
|
||||
const shouldBeCached = this.meta.cacheRemoteFiles && (this.meta.cacheRemoteSensitiveFiles || !image.sensitive);
|
||||
|
||||
const file = await this.driveService.uploadFromUrl({
|
||||
url: image.url,
|
||||
|
@@ -6,13 +6,12 @@
|
||||
import { forwardRef, Inject, Injectable } from '@nestjs/common';
|
||||
import { In } from 'typeorm';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { PollsRepository, EmojisRepository } from '@/models/_.js';
|
||||
import type { PollsRepository, EmojisRepository, MiMeta } from '@/models/_.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import type { MiRemoteUser } from '@/models/User.js';
|
||||
import type { MiNote } from '@/models/Note.js';
|
||||
import { toArray, toSingle, unique } from '@/misc/prelude/array.js';
|
||||
import type { MiEmoji } from '@/models/Emoji.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { AppLockService } from '@/core/AppLockService.js';
|
||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||
import { NoteCreateService } from '@/core/NoteCreateService.js';
|
||||
@@ -46,6 +45,9 @@ export class ApNoteService {
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.pollsRepository)
|
||||
private pollsRepository: PollsRepository,
|
||||
|
||||
@@ -65,7 +67,6 @@ export class ApNoteService {
|
||||
private apMentionService: ApMentionService,
|
||||
private apImageService: ApImageService,
|
||||
private apQuestionService: ApQuestionService,
|
||||
private metaService: MetaService,
|
||||
private appLockService: AppLockService,
|
||||
private pollService: PollService,
|
||||
private noteCreateService: NoteCreateService,
|
||||
@@ -182,7 +183,7 @@ export class ApNoteService {
|
||||
/**
|
||||
* 禁止ワードチェック
|
||||
*/
|
||||
const hasProhibitedWords = await this.noteCreateService.checkProhibitedWordsContain({ cw, text, pollChoices: poll?.choices });
|
||||
const hasProhibitedWords = this.noteCreateService.checkProhibitedWordsContain({ cw, text, pollChoices: poll?.choices });
|
||||
if (hasProhibitedWords) {
|
||||
throw new IdentifiableError('689ee33f-f97c-479a-ac49-1b9f8140af99', 'Note contains prohibited words');
|
||||
}
|
||||
@@ -336,8 +337,7 @@ export class ApNoteService {
|
||||
const uri = getApId(value);
|
||||
|
||||
// ブロックしていたら中断
|
||||
const meta = await this.metaService.fetch();
|
||||
if (this.utilityService.isBlockedHost(meta.blockedHosts, this.utilityService.extractDbHost(uri))) {
|
||||
if (this.utilityService.isBlockedHost(this.meta.blockedHosts, this.utilityService.extractDbHost(uri))) {
|
||||
throw new StatusError('blocked host', 451);
|
||||
}
|
||||
|
||||
|
@@ -8,7 +8,7 @@ import promiseLimit from 'promise-limit';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { ModuleRef } from '@nestjs/core';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { FollowingsRepository, InstancesRepository, UserProfilesRepository, UserPublickeysRepository, UsersRepository } from '@/models/_.js';
|
||||
import type { FollowingsRepository, InstancesRepository, MiMeta, UserProfilesRepository, UserPublickeysRepository, UsersRepository } from '@/models/_.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import type { MiLocalUser, MiRemoteUser } from '@/models/User.js';
|
||||
import { MiUser } from '@/models/User.js';
|
||||
@@ -35,7 +35,6 @@ import type { UtilityService } from '@/core/UtilityService.js';
|
||||
import type { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { RoleService } from '@/core/RoleService.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
|
||||
import type { AccountMoveService } from '@/core/AccountMoveService.js';
|
||||
import { checkHttps } from '@/misc/check-https.js';
|
||||
@@ -62,7 +61,6 @@ export class ApPersonService implements OnModuleInit {
|
||||
private driveFileEntityService: DriveFileEntityService;
|
||||
private idService: IdService;
|
||||
private globalEventService: GlobalEventService;
|
||||
private metaService: MetaService;
|
||||
private federatedInstanceService: FederatedInstanceService;
|
||||
private fetchInstanceMetadataService: FetchInstanceMetadataService;
|
||||
private cacheService: CacheService;
|
||||
@@ -84,6 +82,9 @@ export class ApPersonService implements OnModuleInit {
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.db)
|
||||
private db: DataSource,
|
||||
|
||||
@@ -112,7 +113,6 @@ export class ApPersonService implements OnModuleInit {
|
||||
this.driveFileEntityService = this.moduleRef.get('DriveFileEntityService');
|
||||
this.idService = this.moduleRef.get('IdService');
|
||||
this.globalEventService = this.moduleRef.get('GlobalEventService');
|
||||
this.metaService = this.moduleRef.get('MetaService');
|
||||
this.federatedInstanceService = this.moduleRef.get('FederatedInstanceService');
|
||||
this.fetchInstanceMetadataService = this.moduleRef.get('FetchInstanceMetadataService');
|
||||
this.cacheService = this.moduleRef.get('CacheService');
|
||||
@@ -407,10 +407,10 @@ export class ApPersonService implements OnModuleInit {
|
||||
this.cacheService.uriPersonCache.set(user.uri, user);
|
||||
|
||||
// Register host
|
||||
this.federatedInstanceService.fetch(host).then(async i => {
|
||||
this.federatedInstanceService.fetch(host).then(i => {
|
||||
this.instancesRepository.increment({ id: i.id }, 'usersCount', 1);
|
||||
this.fetchInstanceMetadataService.fetchInstanceMetadata(i);
|
||||
if ((await this.metaService.fetch()).enableChartsForFederatedInstances) {
|
||||
if (this.meta.enableChartsForFederatedInstances) {
|
||||
this.instanceChart.newUser(i.host);
|
||||
}
|
||||
});
|
||||
|
@@ -5,10 +5,9 @@
|
||||
|
||||
import { Injectable, Inject } from '@nestjs/common';
|
||||
import { DataSource } from 'typeorm';
|
||||
import type { FollowingsRepository, InstancesRepository } from '@/models/_.js';
|
||||
import type { FollowingsRepository, InstancesRepository, MiMeta } from '@/models/_.js';
|
||||
import { AppLockService } from '@/core/AppLockService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import Chart from '../core.js';
|
||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||
@@ -24,13 +23,15 @@ export default class FederationChart extends Chart<typeof schema> { // eslint-di
|
||||
@Inject(DI.db)
|
||||
private db: DataSource,
|
||||
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.followingsRepository)
|
||||
private followingsRepository: FollowingsRepository,
|
||||
|
||||
@Inject(DI.instancesRepository)
|
||||
private instancesRepository: InstancesRepository,
|
||||
|
||||
private metaService: MetaService,
|
||||
private appLockService: AppLockService,
|
||||
private chartLoggerService: ChartLoggerService,
|
||||
) {
|
||||
@@ -43,8 +44,6 @@ export default class FederationChart extends Chart<typeof schema> { // eslint-di
|
||||
}
|
||||
|
||||
protected async tickMinor(): Promise<Partial<KVs<typeof schema>>> {
|
||||
const meta = await this.metaService.fetch();
|
||||
|
||||
const suspendedInstancesQuery = this.instancesRepository.createQueryBuilder('instance')
|
||||
.select('instance.host')
|
||||
.where('instance.suspensionState != \'none\'');
|
||||
@@ -65,21 +64,21 @@ export default class FederationChart extends Chart<typeof schema> { // eslint-di
|
||||
this.followingsRepository.createQueryBuilder('following')
|
||||
.select('COUNT(DISTINCT following.followeeHost)')
|
||||
.where('following.followeeHost IS NOT NULL')
|
||||
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'following.followeeHost NOT ILIKE ALL(ARRAY[:...blocked])', { blocked: meta.blockedHosts.flatMap(x => [x, `%.${x}`]) })
|
||||
.andWhere(this.meta.blockedHosts.length === 0 ? '1=1' : 'following.followeeHost NOT ILIKE ALL(ARRAY[:...blocked])', { blocked: this.meta.blockedHosts.flatMap(x => [x, `%.${x}`]) })
|
||||
.andWhere(`following.followeeHost NOT IN (${ suspendedInstancesQuery.getQuery() })`)
|
||||
.getRawOne()
|
||||
.then(x => parseInt(x.count, 10)),
|
||||
this.followingsRepository.createQueryBuilder('following')
|
||||
.select('COUNT(DISTINCT following.followerHost)')
|
||||
.where('following.followerHost IS NOT NULL')
|
||||
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'following.followerHost NOT ILIKE ALL(ARRAY[:...blocked])', { blocked: meta.blockedHosts.flatMap(x => [x, `%.${x}`]) })
|
||||
.andWhere(this.meta.blockedHosts.length === 0 ? '1=1' : 'following.followerHost NOT ILIKE ALL(ARRAY[:...blocked])', { blocked: this.meta.blockedHosts.flatMap(x => [x, `%.${x}`]) })
|
||||
.andWhere(`following.followerHost NOT IN (${ suspendedInstancesQuery.getQuery() })`)
|
||||
.getRawOne()
|
||||
.then(x => parseInt(x.count, 10)),
|
||||
this.followingsRepository.createQueryBuilder('following')
|
||||
.select('COUNT(DISTINCT following.followeeHost)')
|
||||
.where('following.followeeHost IS NOT NULL')
|
||||
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'following.followeeHost NOT ILIKE ALL(ARRAY[:...blocked])', { blocked: meta.blockedHosts.flatMap(x => [x, `%.${x}`]) })
|
||||
.andWhere(this.meta.blockedHosts.length === 0 ? '1=1' : 'following.followeeHost NOT ILIKE ALL(ARRAY[:...blocked])', { blocked: this.meta.blockedHosts.flatMap(x => [x, `%.${x}`]) })
|
||||
.andWhere(`following.followeeHost NOT IN (${ suspendedInstancesQuery.getQuery() })`)
|
||||
.andWhere(`following.followeeHost IN (${ pubsubSubQuery.getQuery() })`)
|
||||
.setParameters(pubsubSubQuery.getParameters())
|
||||
@@ -88,7 +87,7 @@ export default class FederationChart extends Chart<typeof schema> { // eslint-di
|
||||
this.instancesRepository.createQueryBuilder('instance')
|
||||
.select('COUNT(instance.id)')
|
||||
.where(`instance.host IN (${ subInstancesQuery.getQuery() })`)
|
||||
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT ILIKE ALL(ARRAY[:...blocked])', { blocked: meta.blockedHosts.flatMap(x => [x, `%.${x}`]) })
|
||||
.andWhere(this.meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT ILIKE ALL(ARRAY[:...blocked])', { blocked: this.meta.blockedHosts.flatMap(x => [x, `%.${x}`]) })
|
||||
.andWhere('instance.suspensionState = \'none\'')
|
||||
.andWhere('instance.isNotResponding = false')
|
||||
.getRawOne()
|
||||
@@ -96,7 +95,7 @@ export default class FederationChart extends Chart<typeof schema> { // eslint-di
|
||||
this.instancesRepository.createQueryBuilder('instance')
|
||||
.select('COUNT(instance.id)')
|
||||
.where(`instance.host IN (${ pubInstancesQuery.getQuery() })`)
|
||||
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT ILIKE ALL(ARRAY[:...blocked])', { blocked: meta.blockedHosts.flatMap(x => [x, `%.${x}`]) })
|
||||
.andWhere(this.meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT ILIKE ALL(ARRAY[:...blocked])', { blocked: this.meta.blockedHosts.flatMap(x => [x, `%.${x}`]) })
|
||||
.andWhere('instance.suspensionState = \'none\'')
|
||||
.andWhere('instance.isNotResponding = false')
|
||||
.getRawOne()
|
||||
|
@@ -3,19 +3,22 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import type { Packed } from '@/misc/json-schema.js';
|
||||
import type { MiInstance } from '@/models/Instance.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { UtilityService } from '@/core/UtilityService.js';
|
||||
import { RoleService } from '@/core/RoleService.js';
|
||||
import { MiUser } from '@/models/User.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { MiMeta } from '@/models/_.js';
|
||||
|
||||
@Injectable()
|
||||
export class InstanceEntityService {
|
||||
constructor(
|
||||
private metaService: MetaService,
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
private roleService: RoleService,
|
||||
|
||||
private utilityService: UtilityService,
|
||||
@@ -27,7 +30,6 @@ export class InstanceEntityService {
|
||||
instance: MiInstance,
|
||||
me?: { id: MiUser['id']; } | null | undefined,
|
||||
): Promise<Packed<'FederationInstance'>> {
|
||||
const meta = await this.metaService.fetch();
|
||||
const iAmModerator = me ? await this.roleService.isModerator(me as MiUser) : false;
|
||||
|
||||
return {
|
||||
@@ -41,7 +43,7 @@ export class InstanceEntityService {
|
||||
isNotResponding: instance.isNotResponding,
|
||||
isSuspended: instance.suspensionState !== 'none',
|
||||
suspensionState: instance.suspensionState,
|
||||
isBlocked: this.utilityService.isBlockedHost(meta.blockedHosts, instance.host),
|
||||
isBlocked: this.utilityService.isBlockedHost(this.meta.blockedHosts, instance.host),
|
||||
softwareName: instance.softwareName,
|
||||
softwareVersion: instance.softwareVersion,
|
||||
openRegistrations: instance.openRegistrations,
|
||||
@@ -49,8 +51,8 @@ export class InstanceEntityService {
|
||||
description: instance.description,
|
||||
maintainerName: instance.maintainerName,
|
||||
maintainerEmail: instance.maintainerEmail,
|
||||
isSilenced: this.utilityService.isSilencedHost(meta.silencedHosts, instance.host),
|
||||
isMediaSilenced: this.utilityService.isMediaSilencedHost(meta.mediaSilencedHosts, instance.host),
|
||||
isSilenced: this.utilityService.isSilencedHost(this.meta.silencedHosts, instance.host),
|
||||
isMediaSilenced: this.utilityService.isMediaSilencedHost(this.meta.mediaSilencedHosts, instance.host),
|
||||
iconUrl: instance.iconUrl,
|
||||
faviconUrl: instance.faviconUrl,
|
||||
themeColor: instance.themeColor,
|
||||
|
@@ -10,7 +10,6 @@ import type { Packed } from '@/misc/json-schema.js';
|
||||
import type { MiMeta } from '@/models/Meta.js';
|
||||
import type { AdsRepository } from '@/models/_.js';
|
||||
import { MAX_NOTE_TEXT_LENGTH } from '@/const.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { InstanceActorService } from '@/core/InstanceActorService.js';
|
||||
@@ -24,11 +23,13 @@ export class MetaEntityService {
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.adsRepository)
|
||||
private adsRepository: AdsRepository,
|
||||
|
||||
private userEntityService: UserEntityService,
|
||||
private metaService: MetaService,
|
||||
private instanceActorService: InstanceActorService,
|
||||
) { }
|
||||
|
||||
@@ -37,7 +38,7 @@ export class MetaEntityService {
|
||||
let instance = meta;
|
||||
|
||||
if (!instance) {
|
||||
instance = await this.metaService.fetch();
|
||||
instance = this.meta;
|
||||
}
|
||||
|
||||
const ads = await this.adsRepository.createQueryBuilder('ads')
|
||||
@@ -140,7 +141,7 @@ export class MetaEntityService {
|
||||
let instance = meta;
|
||||
|
||||
if (!instance) {
|
||||
instance = await this.metaService.fetch();
|
||||
instance = this.meta;
|
||||
}
|
||||
|
||||
const packed = await this.pack(instance);
|
||||
|
@@ -11,7 +11,7 @@ import type { Packed } from '@/misc/json-schema.js';
|
||||
import { awaitAll } from '@/misc/prelude/await-all.js';
|
||||
import type { MiUser } from '@/models/User.js';
|
||||
import type { MiNote } from '@/models/Note.js';
|
||||
import type { UsersRepository, NotesRepository, FollowingsRepository, PollsRepository, PollVotesRepository, NoteReactionsRepository, ChannelsRepository } from '@/models/_.js';
|
||||
import type { UsersRepository, NotesRepository, FollowingsRepository, PollsRepository, PollVotesRepository, NoteReactionsRepository, ChannelsRepository, MiMeta } from '@/models/_.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { DebounceLoader } from '@/misc/loader.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
@@ -43,12 +43,14 @@ export class NoteEntityService implements OnModuleInit {
|
||||
private reactionService: ReactionService;
|
||||
private reactionsBufferingService: ReactionsBufferingService;
|
||||
private idService: IdService;
|
||||
private metaService: MetaService;
|
||||
private noteLoader = new DebounceLoader(this.findNoteOrFail);
|
||||
|
||||
constructor(
|
||||
private moduleRef: ModuleRef,
|
||||
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.usersRepository)
|
||||
private usersRepository: UsersRepository,
|
||||
|
||||
@@ -76,7 +78,6 @@ export class NoteEntityService implements OnModuleInit {
|
||||
//private reactionService: ReactionService,
|
||||
//private reactionsBufferingService: ReactionsBufferingService,
|
||||
//private idService: IdService,
|
||||
//private metaService: MetaService,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -87,7 +88,6 @@ export class NoteEntityService implements OnModuleInit {
|
||||
this.reactionService = this.moduleRef.get('ReactionService');
|
||||
this.reactionsBufferingService = this.moduleRef.get('ReactionsBufferingService');
|
||||
this.idService = this.moduleRef.get('IdService');
|
||||
this.metaService = this.moduleRef.get('MetaService');
|
||||
}
|
||||
|
||||
@bindThis
|
||||
@@ -324,11 +324,9 @@ export class NoteEntityService implements OnModuleInit {
|
||||
const note = typeof src === 'object' ? src : await this.noteLoader.load(src);
|
||||
const host = note.userHost;
|
||||
|
||||
const meta = await this.metaService.fetch();
|
||||
|
||||
const bufferdReactions = opts._hint_?.bufferdReactions != null
|
||||
? (opts._hint_.bufferdReactions.get(note.id) ?? { deltas: {}, pairs: [] })
|
||||
: meta.enableReactionsBuffering
|
||||
: this.meta.enableReactionsBuffering
|
||||
? await this.reactionsBufferingService.get(note.id)
|
||||
: { deltas: {}, pairs: [] };
|
||||
const reactions = mergeReactions(note.reactions, bufferdReactions.deltas ?? {});
|
||||
@@ -441,9 +439,7 @@ export class NoteEntityService implements OnModuleInit {
|
||||
) {
|
||||
if (notes.length === 0) return [];
|
||||
|
||||
const meta = await this.metaService.fetch();
|
||||
|
||||
const bufferdReactions = meta.enableReactionsBuffering ? await this.reactionsBufferingService.getMany(notes.map(x => x.id)) : null;
|
||||
const bufferdReactions = this.meta.enableReactionsBuffering ? await this.reactionsBufferingService.getMany(notes.map(x => x.id)) : null;
|
||||
|
||||
const meId = me ? me.id : null;
|
||||
const myReactionsMap = new Map<MiNote['id'], string | null>();
|
||||
|
Reference in New Issue
Block a user